| Server IP : 85.155.190.233 / Your IP : 216.73.216.103 Web Server : nginx/1.24.0 System : Linux antigravity-cli 6.8.0-31-generic #31-Ubuntu SMP PREEMPT_DYNAMIC Sat Apr 20 00:40:06 UTC 2024 x86_64 User : wp-moonbloom ( 1001) PHP Version : 8.3.6 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /lib/node_modules/@google/jules/ |
Upload File : |
#!/usr/bin/env node
"use strict";
const https = require("https");
const path = require("path");
const tar = require("tar");
const zlib = require("zlib");
const fs = require("fs");
const os = require("os");
const { exec } = require("child_process");
// The name of the binary to be installed.
const BINARY_NAMES = process.platform === "win32"
? ["jules.exe", "run.cjs"]
: ["jules", "run.cjs"];
// --- Mappings ---
/**
* Mapping from Node's `process.arch` to Go's `$GOARCH`.
* @type {Object.<string, string>}
*/
const ARCH_MAPPING = {
x64: "amd64",
arm64: "arm64",
};
/**
* Mapping from Node's `process.platform` to Go's `$GOOS`.
* @type {Object.<string, string>}
*/
const PLATFORM_MAPPING = {
darwin: "darwin",
linux: "linux",
win32: "windows",
};
// --- Core Functions ---
/**
* Detects the package manager from the environment variables.
* @returns {'pnpm' | 'npm'}
*/
function getPackageManager() {
const userAgent = process.env.npm_config_user_agent;
if (userAgent && userAgent.startsWith("pnpm")) {
return "pnpm";
}
return "npm";
}
/**
* Determines the correct installation path for binaries.
* @returns {Promise<string>} The path to the 'bin' directory.
*/
async function getInstallationPath() {
const manager = getPackageManager();
try {
const isGlobal = process.env.npm_config_global === "true";
if (manager === "pnpm") {
const cmd = isGlobal ? "pnpm bin -g" : "pnpm bin";
const { stdout } = await executeCommand(cmd);
return path.join(stdout.trim(), "dist"); // To avoid collision of `jules` script generated by pnpm
} else {
const cmd = isGlobal ? "npm root -g" : "npm root";
const { stdout } = await executeCommand(cmd);
const npmRoot = stdout.trim();
if (isGlobal) {
const prefix =
process.env.npm_config_prefix || path.join(npmRoot, "..");
return path.join(prefix, "bin");
} else {
return path.resolve(npmRoot, ".bin");
}
}
} catch (error) {
if (process.env.npm_config_prefix) {
return path.join(process.env.npm_config_prefix, "bin");
}
throw new Error("Couldn't determine binary installation path.");
}
}
/**
* Parses package.json and constructs the binary's download URL.
* @returns {{url: string}}
*/
function parseConfig() {
if (!ARCH_MAPPING[process.arch]) {
throw new Error(`Unsupported architecture: ${process.arch}`);
}
if (!PLATFORM_MAPPING[process.platform]) {
throw new Error(`Unsupported platform: ${process.platform}`);
}
const packageJsonPath = path.join("./", "package.json");
if (!fs.existsSync(packageJsonPath)) {
throw new Error(
"Could not find package.json. Please run from the package root.",
);
}
/** @type {PackageConfig} */
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
if (!packageJson.version) {
throw new Error("'version' property must be specified in package.json");
}
if (!packageJson.binURL) {
throw new Error("'binURL' property must be specified in package.json");
}
let version = packageJson.version;
if (!version.startsWith("v")) {
version = "v" + version;
}
const url = packageJson.binURL;
const finalURL = url
.replace(/{{arch}}/g, ARCH_MAPPING[process.arch])
.replace(/{{platform}}/g, PLATFORM_MAPPING[process.platform])
.replace(/{{version}}/g, version);
console.log(finalURL);
return { url: finalURL };
}
/**
* Executes a shell command and returns a Promise.
* @param {string} command - The shell command to execute.
* @returns {Promise<{stdout: string, stderr: string}>}
*/
function executeCommand(command) {
return new Promise((resolve, reject) => {
exec(command, (error, stdout, stderr) => {
if (error) {
console.error(`โ Error executing command: ${error.message}`);
if (stderr) {
console.error(`stderr from command:\n${stderr}`);
}
return reject(error);
}
resolve({ stdout, stderr });
});
});
}
/**
* Downloads a file from a URL, handling redirects.
* @param {string} url - The URL to download from.
* @param {string} destinationPath - The local path to save the file.
* @returns {Promise<void>}
*/
function downloadFromUrl(url, destinationPath, logFn) {
logFn(`\n๐ Downloading from URL: ${url}`);
return new Promise((resolve, reject) => {
const request = https.get(url, (response) => {
if (
response.statusCode >= 300 &&
response.statusCode < 400 &&
response.headers.location
) {
return downloadFromUrl(
response.headers.location,
destinationPath,
logFn,
)
.then(resolve)
.catch(reject);
}
if (response.statusCode !== 200) {
return reject(
new Error(
`Download failed with status code: ${response.statusCode}`,
),
);
}
const fileStream = fs.createWriteStream(destinationPath);
response.pipe(fileStream);
fileStream.on("finish", () => {
fileStream.close(resolve); // close() is async, resolve in its callback
});
fileStream.on("error", (err) => {
fs.unlink(destinationPath, () => reject(err)); // Delete the partial file on error
});
});
request.on("error", (err) => {
reject(err);
});
});
}
/**
* Extracts a specific binary from a local .tar.gz file.
* @param {string} tarballPath - The local path to the .tar.gz file.
* @param {string} destinationPath - The destination directory for the binary.
* @returns {Promise<void>}
*/
function extractTarball(tarballPath, destinationPath, logFn) {
logFn(`\n๐ Starting extraction from: ${tarballPath}`);
return new Promise((resolve, reject) => {
const stream = fs
.createReadStream(tarballPath)
.pipe(zlib.createGunzip()) // Decompress the gzip stream
.pipe(
// Extract only the specified binary file to the destination directory
tar.extract({ cwd: destinationPath }, BINARY_NAMES),
);
// Handle successful extraction
stream.on("finish", () => {
logFn(
`โ
Successfully extracted ${BINARY_NAMES} to ${destinationPath}`,
);
for (const name of BINARY_NAMES) {
const finalBinPath = path.join(destinationPath, name);
// Set executable permissions (e.g., rwxr-xr-x) on Unix-like systems
if (process.platform !== "win32") {
fs.chmodSync(finalBinPath, 0o755);
logFn(`๐ Set executable permissions for ${finalBinPath}`);
}
}
resolve();
});
// Handle errors during the stream process
stream.on("error", reject);
});
}
// --- Actions ---
/**
* Installs the Go binary.
* @returns {Promise<void>}
*/
async function install(installPath, logFn) {
const { url } = parseConfig();
fs.mkdirSync(installPath, { recursive: true });
const localTarballName = path.basename(url);
let localTarballPath = path.join(installPath, localTarballName);
try {
await downloadFromUrl(url, localTarballPath, logFn);
logFn(`โ
Successfully downloaded to ${localTarballPath}`);
await extractTarball(localTarballPath, installPath, logFn);
logFn(`\n๐ Process complete. Binary is ready at ${installPath}`);
} catch (error) {
logFn("\nโ A critical error occurred during the process.", error);
} finally {
if (fs.existsSync(localTarballPath)) {
fs.unlinkSync(localTarballPath);
logFn(`๐งน Cleaned up temporary file: ${localTarballPath}`);
}
}
}
/**
* Uninstalls the Go binary.
* @returns {Promise<void>}
*/
async function uninstall(installPath, logFn) {
try {
// Loop over the array of binary names
for (const name of BINARY_NAMES) {
const binaryPath = path.join(installPath, name);
if (fs.existsSync(binaryPath)) {
fs.unlinkSync(binaryPath);
logFn(`๐๏ธ Uninstalled ${name} from ${binaryPath}`);
} else {
logFn(
`${name} not found at ${binaryPath}, nothing to uninstall.`,
);
}
}
} catch (error) {
console.error(`Error during uninstall: ${error.message}`);
}
}
(async () => {
const logDir = path.join(os.tmpdir(), "jules_tmp")
fs.mkdirSync(logDir, { recursive: true });
const logFile = path.join(logDir, "jules-install.log");
const logFn = (msg) => {
console.log(msg);
fs.appendFileSync(logFile, `${new Date().toISOString()}: ${msg}\n`);
};
const installPath = await getInstallationPath();
const actions = {};
actions["install"] = async () => {
await install(installPath, logFn);
};
actions["uninstall"] = async () => {
await uninstall(installPath, logFn);
};
const command = process.argv[2];
if (!actions[command]) {
console.error(
"Invalid command. Available commands are 'install' and 'uninstall'.",
);
process.exit(1);
}
try {
await actions[command]();
} catch (error) {
console.error(`โ Error during '${command}': ${error.message}`);
process.exit(1);
}
})();