fix(primer): resolve bundled codex JS launcher so the periodic primer fires
The Codex usage primer spawned a bare `codex` binary, but under bun/systemd there is no global `codex` on PATH, so every slot failed with ENOENT and the primer never ran. Resolve the vendored @openai/codex JS launcher and run it through the current JS runtime (matching the codex-runner), with global-binary and PATH fallbacks. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import { ChildProcess, spawn } from 'child_process';
|
||||
import fs from 'fs';
|
||||
import { createRequire } from 'module';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
import { DATA_DIR } from './config.js';
|
||||
import type { AppConfig } from './config/schema.js';
|
||||
@@ -87,9 +89,63 @@ function getPreferredCodexPathEntries(): string[] {
|
||||
return [...new Set(entries)];
|
||||
}
|
||||
|
||||
function resolveCodexBinary(): string {
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
interface CodexLauncher {
|
||||
command: string;
|
||||
prefixArgs: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve how to spawn the Codex CLI for warm-up.
|
||||
*
|
||||
* The bot runs under bun/systemd where a global `codex` binary usually is NOT
|
||||
* on PATH, so the old bare-`codex` fallback failed with ENOENT and the primer
|
||||
* never fired. Prefer the bundled `@openai/codex` JS launcher (the same path
|
||||
* the codex-runner spawns) and run it through the current JS runtime, falling
|
||||
* back to a globally installed binary only when the package is unavailable.
|
||||
*/
|
||||
function resolveCodexLauncher(): CodexLauncher {
|
||||
const launcherCandidates: string[] = [];
|
||||
try {
|
||||
launcherCandidates.push(
|
||||
path.join(
|
||||
path.dirname(require.resolve('@openai/codex/package.json')),
|
||||
'bin',
|
||||
'codex.js',
|
||||
),
|
||||
);
|
||||
} catch {
|
||||
/* @openai/codex not resolvable from this module — try explicit paths */
|
||||
}
|
||||
// The codex-runner workspace always vendors @openai/codex.
|
||||
const repoRoot = path.resolve(
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
'..',
|
||||
);
|
||||
launcherCandidates.push(
|
||||
path.join(
|
||||
repoRoot,
|
||||
'runners',
|
||||
'codex-runner',
|
||||
'node_modules',
|
||||
'@openai',
|
||||
'codex',
|
||||
'bin',
|
||||
'codex.js',
|
||||
),
|
||||
);
|
||||
for (const launcher of launcherCandidates) {
|
||||
if (fs.existsSync(launcher)) {
|
||||
return { command: process.execPath, prefixArgs: [launcher] };
|
||||
}
|
||||
}
|
||||
// Fall back to a globally installed codex binary, then bare PATH lookup.
|
||||
const npmGlobalBin = path.join(os.homedir(), '.npm-global', 'bin', 'codex');
|
||||
return fs.existsSync(npmGlobalBin) ? npmGlobalBin : 'codex';
|
||||
if (fs.existsSync(npmGlobalBin)) {
|
||||
return { command: npmGlobalBin, prefixArgs: [] };
|
||||
}
|
||||
return { command: 'codex', prefixArgs: [] };
|
||||
}
|
||||
|
||||
function ensureAccountState(
|
||||
@@ -219,7 +275,8 @@ function runCodexWarmupCommand(
|
||||
);
|
||||
|
||||
try {
|
||||
proc = spawn(resolveCodexBinary(), args, {
|
||||
const launcher = resolveCodexLauncher();
|
||||
proc = spawn(launcher.command, [...launcher.prefixArgs, ...args], {
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
env: spawnEnv,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user