@avikalpa/codex-litellm
Version:
Patched OpenAI Codex CLI with first-class LiteLLM support
124 lines (102 loc) • 4.07 kB
JavaScript
const crypto = require('crypto');
const fs = require('fs');
const { mkdirSync, rmSync } = fs;
const path = require('path');
const os = require('os');
const https = require('https');
const { execFileSync } = require('child_process');
if (process.env.CODEX_LITELLM_SKIP_DOWNLOAD === '1') {
console.log('Skipping codex-litellm binary download.');
process.exit(0);
}
const TARGET_SUFFIX = new Map([
['linux:x64', 'linux-x64'],
['linux:arm64', 'linux-arm64'],
['android:arm64', 'android-arm64'],
['darwin:x64', 'macos-x64'],
['darwin:arm64', 'macos-arm64'],
['win32:x64', 'windows-x64'],
['win32:arm64', 'windows-arm64'],
['freebsd:x64', 'freebsd-x64'],
['sunos:x64', 'illumos-x64'],
]);
const key = `${process.platform}:${process.arch}`;
const suffix = TARGET_SUFFIX.get(key);
if (!suffix) {
console.error(`codex-litellm: no prebuilt binary for ${process.platform}/${process.arch}.`);
console.error('Please build from source instead: https://github.com/avikalpa/codex-litellm');
process.exit(0);
}
const pkg = require('../package.json');
const version = pkg.version;
const tag = process.env.CODEX_LITELLM_RELEASE_TAG || (pkg.codexLitellm && pkg.codexLitellm.releaseTag) || `v${version}`;
const baseUrl = `https://github.com/avikalpa/codex-litellm/releases/download/${tag}`;
const archiveName = `codex-litellm-${suffix}.tar.gz`;
const archiveUrl = `${baseUrl}/${archiveName}`;
const checksumUrl = `${archiveUrl}.sha256`;
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-litellm-'));
const archivePath = path.join(tmpDir, archiveName);
const checksumPath = `${archivePath}.sha256`;
function download(url, dest) {
return new Promise((resolve, reject) => {
const request = https.get(url, (res) => {
if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
res.resume();
download(res.headers.location, dest).then(resolve).catch(reject);
return;
}
if (res.statusCode !== 200) {
reject(new Error(`Request failed. Status code: ${res.statusCode} for ${url}`));
res.resume();
return;
}
const file = fs.createWriteStream(dest);
res.pipe(file);
file.on('finish', () => file.close(resolve));
file.on('error', (err) => {
file.close(() => fs.unlink(dest, () => {}));
reject(err);
});
});
request.on('error', (err) => {
reject(err);
});
});
}
function verifyChecksum(filePath, checksumFile) {
const expected = fs.readFileSync(checksumFile, 'utf8').split(/\s+/)[0].trim();
const hash = crypto.createHash('sha256');
const data = fs.readFileSync(filePath);
hash.update(data);
const actual = hash.digest('hex');
if (expected !== actual) {
throw new Error(`Checksum mismatch: expected ${expected}, got ${actual}`);
}
}
(async () => {
try {
console.log(`Downloading ${archiveName} (${version})...`);
await download(archiveUrl, archivePath);
console.log('Downloading checksum...');
await download(checksumUrl, checksumPath);
verifyChecksum(archivePath, checksumPath);
const distRoot = path.join(__dirname, '..', 'dist');
const destDir = path.join(distRoot, suffix);
rmSync(destDir, { recursive: true, force: true });
mkdirSync(destDir, { recursive: true });
console.log('Extracting binary...');
execFileSync('tar', ['-xzf', archivePath, '-C', destDir]);
const binaryName = process.platform === 'win32' ? 'codex-litellm.exe' : 'codex-litellm';
const binaryPath = path.join(destDir, binaryName);
if (!fs.existsSync(binaryPath)) {
throw new Error(`Binary missing after extraction: ${binaryPath}`);
}
fs.chmodSync(binaryPath, 0o755);
console.log(`codex-litellm binary installed for ${suffix}.`);
} catch (err) {
console.error(`Failed to install codex-litellm prebuilt binary: ${err.message}`);
console.error('You can build manually by running `npm explore @avikalpa/codex-litellm -- ./build.sh`.');
process.exit(1);
}
})();