mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 08:17:11 +00:00
83 lines
3.5 KiB
TypeScript
83 lines
3.5 KiB
TypeScript
/**
|
|
* Codex runtime router — testable logic for src/bin/codex-runtime.ts.
|
|
*
|
|
* All inter-module deps are resolved via require() at call-time so tests can
|
|
* inject stubs via require.cache before calling main().
|
|
*
|
|
* Routing:
|
|
* argv[2] === 'auth' → delegate to runCodexAuth(argv.slice(3)), exit with code
|
|
* else → resolve active profile, set CODEX_HOME, load ccs
|
|
* CCS manages the process lifecycle; entry MUST NOT
|
|
* call process.exit() when main returns -1.
|
|
*
|
|
* Return value contract:
|
|
* ≥ 0 → auth branch: caller should process.exit(code)
|
|
* -1 → CCS branch: CCS has taken over the process; caller must NOT exit
|
|
*/
|
|
|
|
process.env.CCS_INTERNAL_ENTRY_TARGET = 'codex';
|
|
|
|
/**
|
|
* Main entry-point for the ccsx / codex-runtime binary.
|
|
*
|
|
* @param argv - process.argv (or test-supplied equivalent)
|
|
* @returns ≥0 exit code for auth branch; -1 for CCS branch (no exit needed)
|
|
*/
|
|
export async function main(argv: string[]): Promise<number> {
|
|
const subcommand = argv[2];
|
|
|
|
// ── auth branch ─────────────────────────────────────────────────────────
|
|
if (subcommand === 'auth') {
|
|
const { runCodexAuth } = require('../codex-auth/codex-auth-router') as {
|
|
runCodexAuth: (args: string[]) => Promise<number>;
|
|
};
|
|
return runCodexAuth(argv.slice(3));
|
|
}
|
|
|
|
// ── non-auth branch: profile resolution ─────────────────────────────────
|
|
|
|
// F1: respect an explicit CODEX_HOME — ccsxp, user export, CI override, etc.
|
|
const explicit = (process.env.CODEX_HOME ?? '').trim();
|
|
if (!explicit) {
|
|
try {
|
|
const { resolveActiveProfile } = require('../codex-auth/resolve-active-profile') as {
|
|
resolveActiveProfile: (
|
|
env: NodeJS.ProcessEnv
|
|
) => { name: string; dir: string; source: string } | null;
|
|
};
|
|
const resolved = resolveActiveProfile(process.env);
|
|
if (resolved) {
|
|
process.env.CODEX_HOME = resolved.dir;
|
|
|
|
try {
|
|
const { ensureSharedConfigSymlink } = require('../codex-auth/codex-config-symlink') as {
|
|
ensureSharedConfigSymlink: (dir: string) => void;
|
|
};
|
|
ensureSharedConfigSymlink(resolved.dir);
|
|
} catch (symlinkErr) {
|
|
const msg = symlinkErr instanceof Error ? symlinkErr.message : String(symlinkErr);
|
|
process.stderr.write(
|
|
`[!] codex-auth: shared config symlink failed (${msg}), continuing\n`
|
|
);
|
|
}
|
|
}
|
|
} catch (resolverErr) {
|
|
const msg = resolverErr instanceof Error ? resolverErr.message : String(resolverErr);
|
|
if (resolverErr instanceof Error && resolverErr.name === 'CodexAuthProfileResolutionError') {
|
|
process.stderr.write(`[X] codex-auth: ${msg}\n`);
|
|
return 1;
|
|
}
|
|
// Resolver module threw unexpectedly — degrade to legacy mode.
|
|
process.stderr.write(`[!] codex-auth: profile resolution skipped (${msg})\n`);
|
|
}
|
|
}
|
|
|
|
// ── delegate to CCS ─────────────────────────────────────────────────────
|
|
// require() is evaluated AFTER env mutations above. CCS manages its own
|
|
// process lifecycle (spawns codex, pipes stdio, calls process.exit).
|
|
// Return -1 so the entry script knows NOT to call process.exit().
|
|
require('../ccs');
|
|
|
|
return -1; // CCS is in control — entry must not call process.exit()
|
|
}
|