Three of these break the codex:codex-rescue → codex-companion.mjs task path that tools build review/delegation gates on. Found while debugging a downstream pipeline; all three reproduce on v1.0.4. I have small, isolated fixes with node --test coverage and am happy to open a PR if useful.
1. A missing cwd is misreported as "Codex CLI is not installed"
binaryAvailable() (scripts/lib/process.mjs) treats any spawnSync ENOENT as a missing binary. But spawnSync also raises ENOENT when the cwd does not exist. So when a caller passes a cwd that has been removed (e.g. a cleaned-up git worktree in a parallel/fleet runner), getCodexAvailability(cwd) returns "not found" and every entrypoint throws "Codex CLI is not installed or is missing required runtime support" — even though Codex is installed and authenticated.
Repro: binaryAvailable(process.execPath, ["--version"], { cwd: "/does/not/exist" }) → { available: false, detail: "not found" }.
Fix: a --version/--help probe never depends on the caller's cwd. If a requested cwd doesn't exist, drop it for the probe so availability reflects the binary itself.
2. Prompt fragments are parsed as --model, returning a 400 as the result
The documented forward is codex-companion.mjs task "<raw arguments>" (one quoted string). normalizeArgv() re-splits that single arg with splitRawArgumentString(), and parseArgs() (scripts/lib/args.mjs) then treats any --prefixed token as an option. A prompt that mentions running -m pytest, or a module path like conflict_scan.cli, gets a fragment consumed as --model (alias -m). Codex then 400s — "The 'pytest' model is not supported when using Codex with a ChatGPT account." — and that error envelope is returned as the task/review output.
Repro: task "--write review the conflict_scan.cli module and run -m pytest to verify" → turn started with model: "pytest".
Fix: an opt-in parseArgs option (stopAtFirstPositional), used by handleTask, so option parsing ends once the free-text prompt begins (routing flags precede the prompt). Default behavior unchanged for all other commands.
3. Turn-level errors are dropped from the result status
buildResultStatus() (scripts/lib/codex.mjs) returns success purely on finalTurn.status === "completed", ignoring turnState.error. An app-server error notification can coexist with the inferred/synthetic "completed" turn produced when the main thread drains without a real turn/completed — so an errored run is reported as a clean pass.
Fix: treat any captured turnState.error as failure.
Bonus (docs/contract): silent failures from the rescue subagent
agents/codex-rescue.md / skills/codex-cli-runtime/SKILL.md instruct: "If the Bash call fails or Codex cannot be invoked, return nothing." Callers then can't distinguish a clean "no findings" result from a silent abort. Consider emitting a structured failure envelope so callers can branch deterministically.
Environment: codex-plugin-cc v1.0.4, codex-cli 0.139.0, Node 24, macOS. Happy to send a PR with the fixes + tests.
Three of these break the
codex:codex-rescue→codex-companion.mjs taskpath that tools build review/delegation gates on. Found while debugging a downstream pipeline; all three reproduce on v1.0.4. I have small, isolated fixes withnode --testcoverage and am happy to open a PR if useful.1. A missing
cwdis misreported as "Codex CLI is not installed"binaryAvailable()(scripts/lib/process.mjs) treats anyspawnSyncENOENTas a missing binary. ButspawnSyncalso raisesENOENTwhen thecwddoes not exist. So when a caller passes acwdthat has been removed (e.g. a cleaned-up git worktree in a parallel/fleet runner),getCodexAvailability(cwd)returns "not found" and every entrypoint throws "Codex CLI is not installed or is missing required runtime support" — even though Codex is installed and authenticated.Repro:
binaryAvailable(process.execPath, ["--version"], { cwd: "/does/not/exist" })→{ available: false, detail: "not found" }.Fix: a
--version/--helpprobe never depends on the caller's cwd. If a requestedcwddoesn't exist, drop it for the probe so availability reflects the binary itself.2. Prompt fragments are parsed as
--model, returning a 400 as the resultThe documented forward is
codex-companion.mjs task "<raw arguments>"(one quoted string).normalizeArgv()re-splits that single arg withsplitRawArgumentString(), andparseArgs()(scripts/lib/args.mjs) then treats any--prefixed token as an option. A prompt that mentions running-m pytest, or a module path likeconflict_scan.cli, gets a fragment consumed as--model(alias-m). Codex then 400s — "The 'pytest' model is not supported when using Codex with a ChatGPT account." — and that error envelope is returned as the task/review output.Repro:
task "--write review the conflict_scan.cli module and run -m pytest to verify"→ turn started withmodel: "pytest".Fix: an opt-in
parseArgsoption (stopAtFirstPositional), used byhandleTask, so option parsing ends once the free-text prompt begins (routing flags precede the prompt). Default behavior unchanged for all other commands.3. Turn-level errors are dropped from the result status
buildResultStatus()(scripts/lib/codex.mjs) returns success purely onfinalTurn.status === "completed", ignoringturnState.error. An app-servererrornotification can coexist with the inferred/synthetic "completed" turn produced when the main thread drains without a realturn/completed— so an errored run is reported as a clean pass.Fix: treat any captured
turnState.erroras failure.Bonus (docs/contract): silent failures from the rescue subagent
agents/codex-rescue.md/skills/codex-cli-runtime/SKILL.mdinstruct: "If the Bash call fails or Codex cannot be invoked, return nothing." Callers then can't distinguish a clean "no findings" result from a silent abort. Consider emitting a structured failure envelope so callers can branch deterministically.Environment: codex-plugin-cc v1.0.4, codex-cli 0.139.0, Node 24, macOS. Happy to send a PR with the fixes + tests.