Files
pbakaus_impeccable/plugin/skills/impeccable/scripts/live-codex-worker.mjs
T
Paul Bakaus ead6ddabe5 Preserve experimental Live app-server workstream
Snapshot the current app-server implementation, shared Live optimizations, generated harness output, and in-progress site work before restoring polling as the primary runtime path.

Prepared with Codex assistance under maintainer direction.
2026-07-15 16:07:34 -07:00

293 lines
8.8 KiB
JavaScript

#!/usr/bin/env node
import { spawn } from 'node:child_process';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { createCodexAppServerClient } from './live/codex-app-server-client.mjs';
import {
CODEX_CLI_SETUP_URL,
CODEX_WORKER_OWNER,
codexWorkerProcessStateIsOwned,
codexWorkerStateIsOwned,
resolveCodexExecutable,
resolveCodexWorkerConfig,
} from './live/codex-worker.mjs';
import { CodexLiveWorkerSupervisor } from './live/codex-worker-supervisor.mjs';
import {
getLiveCodexWorkerStatePath,
readLiveServerInfo,
resolveLiveConfigPath,
} from './lib/impeccable-paths.mjs';
const args = process.argv.slice(2);
const cwd = process.cwd();
const scriptPath = fileURLToPath(import.meta.url);
const scriptsDir = path.dirname(scriptPath);
const statePath = getLiveCodexWorkerStatePath(cwd);
if (args.includes('--help') || args.includes('-h')) {
console.log(`Usage: node live-codex-worker.mjs [--background [--no-wait] | --status | --stop]
Codex Live generation supervisor. It owns a separate
app-server process and dedicated worker thread; it never attaches to the
foreground desktop task.
It is enabled by default when a Codex runtime signal is present. Set
IMPECCABLE_LIVE_CODEX_WORKER=0 to use the portable foreground path.
Project config may tune the worker but cannot activate it across harnesses.
Optional environment:
IMPECCABLE_LIVE_CODEX_PROFILE quality (default) or fast
IMPECCABLE_LIVE_CODEX_MODEL Model override; otherwise a quality model is selected dynamically
IMPECCABLE_LIVE_CODEX_EFFORT Reasoning effort override (default: medium)
IMPECCABLE_CODEX_PATH Codex binary path (default: codex)
Outside Codex this command exits without polling, leaving the portable
foreground Live path unchanged.`);
process.exit(0);
}
if (args.includes('--status')) {
const state = readJson(statePath);
console.log(JSON.stringify(state
? { ...state, reachable: pidReachable(state.pid) }
: { ok: false, status: 'not_started' }));
process.exit(0);
}
if (args.includes('--stop')) {
const state = readJson(statePath);
if (state?.pid && !codexWorkerProcessStateIsOwned(state, cwd)) {
console.log(JSON.stringify({
ok: false,
status: 'not_stopped',
error: 'codex_worker_state_unowned',
}));
process.exitCode = 2;
process.exit();
}
if (!state?.pid || !pidReachable(state.pid)) {
console.log(JSON.stringify({ ok: true, status: 'not_running' }));
process.exit(0);
}
process.kill(state.pid, 'SIGTERM');
const stopped = await waitFor(
() => !pidReachable(state.pid),
positiveInteger(process.env.IMPECCABLE_LIVE_CODEX_STOP_TIMEOUT_MS, 5_000),
);
if (!stopped) {
console.log(JSON.stringify({ ok: false, status: 'stop_timeout', pid: state.pid }));
process.exitCode = 2;
process.exit();
}
console.log(JSON.stringify({ ok: true, status: 'stopped', pid: state.pid }));
process.exit(0);
}
const liveConfig = readLiveConfig(cwd);
const config = resolveCodexWorkerConfig({ env: process.env, liveConfig });
if (!config.enabled) {
console.log(JSON.stringify({
ok: false,
error: 'codex_worker_disabled',
fallback: 'foreground',
}));
process.exit(0);
}
if (args.includes('--background')) {
const existing = readJson(statePath);
if (codexWorkerProcessStateIsOwned(existing, cwd)
&& existing?.pid
&& pidReachable(existing.pid)
&& ['starting', 'ready', 'working'].includes(existing.status)) {
console.log(JSON.stringify({ ...existing, ok: true, reused: true }));
process.exit(0);
}
}
const executable = resolveCodexExecutable(config.codexPath, { cwd, env: process.env });
if (!executable.available) {
const unavailable = writeState({
ok: false,
owner: CODEX_WORKER_OWNER,
pid: null,
status: 'unavailable',
mode: 'foreground',
error: executable.error,
command: executable.command,
message: 'Codex CLI not found. Live is using the main agent for generation.',
setup: {
docsUrl: CODEX_CLI_SETUP_URL,
afterInstall: 'codex login',
},
});
console.log(JSON.stringify({ ...unavailable, fallback: 'foreground' }));
process.exit(0);
}
config.codexPath = executable.resolvedPath;
if (args.includes('--background')) {
fs.mkdirSync(path.dirname(statePath), { recursive: true });
const logPath = path.join(path.dirname(statePath), 'codex-worker.log');
const logFd = fs.openSync(logPath, 'a');
const child = spawn(process.execPath, [scriptPath, '--foreground'], {
cwd,
env: process.env,
detached: true,
stdio: ['ignore', logFd, logFd],
});
child.unref();
fs.closeSync(logFd);
const observed = readJson(statePath);
const starting = observed?.pid === child.pid && ['ready', 'working'].includes(observed.status)
? observed
: writeState({
ok: true,
owner: CODEX_WORKER_OWNER,
pid: child.pid,
status: 'starting',
threadId: null,
model: config.model,
effort: config.effort,
profile: config.profile,
delivery: config.delivery,
});
if (args.includes('--no-wait')) {
console.log(JSON.stringify({ ...starting, ok: true, starting: true, logPath }));
process.exit(0);
}
const ready = await waitFor(() => {
const state = readJson(statePath);
if (state?.pid !== child.pid) return null;
if (state.status === 'error') return state;
return ['ready', 'working'].includes(state.status) ? state : null;
}, positiveInteger(process.env.IMPECCABLE_LIVE_CODEX_START_TIMEOUT_MS, 12_000));
if (!ready || ready.status === 'error') {
let terminated = true;
if (pidReachable(child.pid)) {
process.kill(child.pid, 'SIGTERM');
terminated = Boolean(await waitFor(
() => !pidReachable(child.pid),
positiveInteger(process.env.IMPECCABLE_LIVE_CODEX_STOP_TIMEOUT_MS, 2_000),
));
}
console.log(JSON.stringify({
ok: false,
error: ready?.error || 'codex_worker_start_timeout',
fallback: terminated ? 'foreground' : null,
terminated,
childPid: child.pid,
logPath,
}));
process.exitCode = 2;
} else {
console.log(JSON.stringify({ ...ready, ok: true, logPath }));
}
process.exit();
}
await runForeground();
async function runForeground() {
const server = readLiveServerInfo(cwd)?.info;
if (!server?.port || !server?.token) {
writeState({ ok: false, status: 'error', error: 'live_server_not_running' });
process.exitCode = 1;
return;
}
const client = createCodexAppServerClient({
command: config.codexPath,
cwd,
requestTimeoutMs: 30_000,
turnTimeoutMs: 240_000,
clientInfo: {
name: 'impeccable_live',
title: 'Impeccable Live dedicated worker',
version: '0.1.0',
},
});
const supervisor = new CodexLiveWorkerSupervisor({
cwd,
base: `http://localhost:${server.port}`,
token: server.token,
client,
config,
statePath,
scriptsDir,
log: (message) => process.stderr.write(`[impeccable-codex-worker] ${message}\n`),
});
let shuttingDown = false;
const shutdown = async () => {
if (shuttingDown) return;
shuttingDown = true;
await supervisor.shutdown({ archive: true }).catch(() => {});
process.exit(0);
};
process.once('SIGINT', shutdown);
process.once('SIGTERM', shutdown);
try {
await supervisor.initialize();
await supervisor.run();
} catch (error) {
writeState({
ok: false,
status: 'error',
error: error.message,
stack: error.stack,
});
await supervisor.shutdown().catch(() => {});
process.exitCode = 1;
}
}
function readLiveConfig(projectCwd) {
const configPath = resolveLiveConfigPath({ cwd: projectCwd, scriptsDir });
return readJson(configPath) || {};
}
function writeState(value) {
fs.mkdirSync(path.dirname(statePath), { recursive: true });
const state = {
cwd: path.resolve(cwd),
pid: process.pid,
updatedAt: new Date().toISOString(),
...value,
};
const temporary = `${statePath}.${process.pid}.${Date.now()}.tmp`;
fs.writeFileSync(temporary, JSON.stringify(state, null, 2) + '\n', 'utf-8');
fs.renameSync(temporary, statePath);
return state;
}
function readJson(file) {
try { return JSON.parse(fs.readFileSync(file, 'utf-8')); } catch { return null; }
}
function pidReachable(pid) {
if (!Number.isInteger(pid) || pid < 1) return false;
try {
process.kill(pid, 0);
return true;
} catch (error) {
return error?.code === 'EPERM';
}
}
async function waitFor(check, timeoutMs) {
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
const result = check();
if (result) return result;
await new Promise((resolve) => setTimeout(resolve, 25));
}
return null;
}
function positiveInteger(value, fallback) {
const parsed = Number(value);
return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;
}