Environment
- Plugin: codex-plugin-cc v1.0.6 (Claude Code marketplace
openai-codex)
- Codex CLI: codex-cli 0.144.4
- Claude Code: 2.1.216
- OS: macOS (cross-platform — the defect is in JS arg handling, not platform-specific)
Summary
codex-companion.mjs task --help (and any unknown --flag on a subcommand) is silently swallowed into the prompt and dispatches a real Codex thread. There is no help output for the task subcommand — --help becomes the literal prompt text "--help", Codex is asked to respond to it, and the resulting throwaway thread becomes the most-recent thread, so the next --resume-last resumes it instead of the intended prior thread.
This is closely related to #512 (prose --model/--write hijacked as real options) — same root cause in parseArgs — but is the inverse manifestation: an unrecognized flag leaking into the prompt rather than a prose word being consumed as a flag. A single fix to unknown-flag handling addresses both.
Reproduction
node scripts/codex-companion.mjs task --help --cwd /tmp --json
Expected: usage text for the task subcommand, exit 0, no thread dispatched.
Actual (v1.0.6): a real thread is created and Codex answers the prompt "--help":
{
"status": 0,
"threadId": "019f84d2-cb9d-7101-b315-16dd344b4bd0",
"rawOutput": "I'm Codex, your coding and research collaborator.\n\nCommon requests:\n- \"Diagnose this test failure.\"\n...\n- `--help` — show this help\n...",
"touchedFiles": [],
"reasoningSummary": []
}
Note the model-level help is Codex answering the prompt — not the companion CLI's usage. The created threadId now shadows --resume-last.
Root cause
Two gaps compound:
-
main() only handles help at the subcommand position (scripts/codex-companion.mjs):
const [subcommand, ...argv] = process.argv.slice(2);
if (!subcommand || subcommand === "help" || subcommand === "--help") { printUsage(); return; }
Once task is the subcommand, a following --help is just an arg passed to handleTask.
-
parseArgs pushes any unrecognized long flag into positionals (scripts/lib/args.mjs):
if (token.startsWith("--")) {
const [rawKey, inlineValue] = token.slice(2).split("=", 2);
const key = aliasMap[rawKey] ?? rawKey;
if (booleanOptions.has(key)) { /* ... */ continue; }
if (valueOptions.has(key)) { /* ... */ continue; }
positionals.push(token); // <-- unknown --flag silently becomes a positional
continue;
}
handleTask → readTaskPrompt then does positionals.join(" "), so the unknown flag becomes the prompt; requireTaskRequest sees a non-empty prompt and dispatches.
Suggested fix
Two targeted changes, low blast radius:
-
Handle --help/-h before dispatch, at any position. In main() (or per-handler), if the subcommand's args contain --help/-h, print that subcommand's usage and exit 0 without dispatching.
-
Reject unknown flags instead of swallowing them. Either an opt-in strict/allowUnknownFlags: false mode in parseArgs, or a guard at the task boundary: any positional beginning with -- is an unknown flag → throw Unknown flag: <token> rather than feeding it to the prompt. This also fixes the dangerous general case where a typo'd flag (--backgroud, --modl) silently becomes prompt text and dispatches. Prefer guarding at the task boundary (or an opt-in strict mode) over making parseArgs globally strict, to avoid disturbing any handler that intentionally relies on passthrough.
Impact
Automated callers that pass explicit, known flags are unaffected. The failure hits interactive/agent exploration (task --help) and any typo'd flag, and — because the throwaway thread shadows --resume-last — silently corrupts a subsequent resume, which is hard to notice after the fact.
Environment
openai-codex)Summary
codex-companion.mjs task --help(and any unknown--flagon a subcommand) is silently swallowed into the prompt and dispatches a real Codex thread. There is no help output for thetasksubcommand —--helpbecomes the literal prompt text"--help", Codex is asked to respond to it, and the resulting throwaway thread becomes the most-recent thread, so the next--resume-lastresumes it instead of the intended prior thread.This is closely related to #512 (prose
--model/--writehijacked as real options) — same root cause inparseArgs— but is the inverse manifestation: an unrecognized flag leaking into the prompt rather than a prose word being consumed as a flag. A single fix to unknown-flag handling addresses both.Reproduction
Expected: usage text for the
tasksubcommand, exit 0, no thread dispatched.Actual (v1.0.6): a real thread is created and Codex answers the prompt "--help":
{ "status": 0, "threadId": "019f84d2-cb9d-7101-b315-16dd344b4bd0", "rawOutput": "I'm Codex, your coding and research collaborator.\n\nCommon requests:\n- \"Diagnose this test failure.\"\n...\n- `--help` — show this help\n...", "touchedFiles": [], "reasoningSummary": [] }Note the model-level help is Codex answering the prompt — not the companion CLI's usage. The created
threadIdnow shadows--resume-last.Root cause
Two gaps compound:
main()only handles help at the subcommand position (scripts/codex-companion.mjs):Once
taskis the subcommand, a following--helpis just an arg passed tohandleTask.parseArgspushes any unrecognized long flag intopositionals(scripts/lib/args.mjs):handleTask→readTaskPromptthen doespositionals.join(" "), so the unknown flag becomes the prompt;requireTaskRequestsees a non-empty prompt and dispatches.Suggested fix
Two targeted changes, low blast radius:
Handle
--help/-hbefore dispatch, at any position. Inmain()(or per-handler), if the subcommand's args contain--help/-h, print that subcommand's usage and exit 0 without dispatching.Reject unknown flags instead of swallowing them. Either an opt-in
strict/allowUnknownFlags: falsemode inparseArgs, or a guard at thetaskboundary: any positional beginning with--is an unknown flag → throwUnknown flag: <token>rather than feeding it to the prompt. This also fixes the dangerous general case where a typo'd flag (--backgroud,--modl) silently becomes prompt text and dispatches. Prefer guarding at thetaskboundary (or an opt-in strict mode) over makingparseArgsglobally strict, to avoid disturbing any handler that intentionally relies on passthrough.Impact
Automated callers that pass explicit, known flags are unaffected. The failure hits interactive/agent exploration (
task --help) and any typo'd flag, and — because the throwaway thread shadows--resume-last— silently corrupts a subsequent resume, which is hard to notice after the fact.