Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions codex-cli/bin/coder.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { fileURLToPath } from "url";
import { platform as nodePlatform, arch as nodeArch } from "os";
import { execSync } from "child_process";
import { get as httpsGet } from "https";
import { runPostinstall } from "../postinstall.js";

// __dirname equivalent in ESM
const __filename = fileURLToPath(import.meta.url);
Expand Down Expand Up @@ -270,12 +271,26 @@ const tryBootstrapBinary = async () => {
};

// If missing, attempt to bootstrap into place (helps when Bun blocks postinstall)
if (!existsSync(binaryPath) && !existsSync(legacyBinaryPath)) {
const ok = await tryBootstrapBinary();
if (!ok) {
// retry legacy name in case archive provided coder-*
if (existsSync(legacyBinaryPath) && !existsSync(binaryPath)) {
binaryPath = legacyBinaryPath;
let binaryReady = existsSync(binaryPath) || existsSync(legacyBinaryPath);
if (!binaryReady) {
let runtimePostinstallError = null;
try {
await runPostinstall({ invokedByRuntime: true, skipGlobalAlias: true });
} catch (err) {
runtimePostinstallError = err;
}

binaryReady = existsSync(binaryPath) || existsSync(legacyBinaryPath);
if (!binaryReady) {
const ok = await tryBootstrapBinary();
if (!ok) {
if (runtimePostinstallError && !lastBootstrapError) {
lastBootstrapError = runtimePostinstallError;
}
// retry legacy name in case archive provided coder-*
if (existsSync(legacyBinaryPath) && !existsSync(binaryPath)) {
binaryPath = legacyBinaryPath;
}
}
}
}
Expand Down
34 changes: 27 additions & 7 deletions codex-cli/postinstall.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Non-functional change to trigger release workflow

import { existsSync, mkdirSync, createWriteStream, chmodSync, readFileSync, readSync, writeFileSync, unlinkSync, statSync, openSync, closeSync, copyFileSync, fsyncSync, renameSync, realpathSync } from 'fs';
import { join, dirname } from 'path';
import { join, dirname, resolve } from 'path';
import { fileURLToPath } from 'url';
import { get } from 'https';
import { platform, arch, tmpdir } from 'os';
Expand Down Expand Up @@ -288,13 +288,21 @@ function validateDownloadedBinary(p) {
}
}

async function main() {
export async function runPostinstall(options = {}) {
const { skipGlobalAlias = false, invokedByRuntime = false } = options;
if (process.env.CODE_POSTINSTALL_DRY_RUN === '1') {
return { skipped: true };
}

if (invokedByRuntime) {
process.env.CODE_RUNTIME_POSTINSTALL = process.env.CODE_RUNTIME_POSTINSTALL || '1';
}
// Detect potential PATH conflict with an existing `code` command (e.g., VS Code)
// Only relevant for global installs; skip for npx/local installs to keep postinstall fast.
const ua = process.env.npm_config_user_agent || '';
const isNpx = ua.includes('npx');
const isGlobal = process.env.npm_config_global === 'true';
if (isGlobal && !isNpx) {
if (!skipGlobalAlias && isGlobal && !isNpx) {
try {
const whichCmd = process.platform === 'win32' ? 'where code' : 'command -v code || which code || true';
const resolved = execSync(whichCmd, { stdio: ['ignore', 'pipe', 'ignore'], shell: process.platform !== 'win32' }).toString().split(/\r?\n/).filter(Boolean)[0];
Expand Down Expand Up @@ -760,7 +768,19 @@ async function main() {
}
}

main().catch(error => {
console.error('Installation failed:', error);
process.exit(1);
});
function isExecutedDirectly() {
const entry = process.argv[1];
if (!entry) return false;
try {
return resolve(entry) === fileURLToPath(import.meta.url);
} catch {
return false;
}
}

if (isExecutedDirectly()) {
runPostinstall().catch(error => {
console.error('Installation failed:', error);
process.exit(1);
});
}
14 changes: 14 additions & 0 deletions codex-cli/test/postinstall.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';

test('runPostinstall resolves in dry-run mode', async () => {
const { runPostinstall } = await import('../postinstall.js');
process.env.CODE_POSTINSTALL_DRY_RUN = '1';
try {
const result = await runPostinstall({ invokedByRuntime: true, skipGlobalAlias: true });
assert.ok(result && result.skipped === true);
} finally {
delete process.env.CODE_POSTINSTALL_DRY_RUN;
delete process.env.CODE_RUNTIME_POSTINSTALL;
}
});
Loading