Repository navigation
fix(codex): start short-lived Codex app-servers on Windows without cmd.exe - #23830
Conversation
…d.exe Orca's short-lived Codex app-server launches (history index passes, the state-DB recovery claimant, hook trust grants, and the rate-limit and model catalog probes) wrapped npm's codex.cmd in `cmd.exe /d /c` before handing it to spawnProcess. That hid the shim from spawnProcess's resolver, so every one of these launches went through cmd.exe instead of straight to node. Hand the bare CLI path to the spawn chokepoint like the chat session already does. The rate-limit probe and the recovery claimant also move off direct node:child_process imports, shrinking that allowlist by two.
… pairing comments Short-lived Codex app-servers now reach spawnProcess as the bare shim, so the direct child is node for a resolved npm shim and cmd.exe only as the fallback.
…ole ratchet The probe now spawns through spawnProcess, which always hides the console.
|
Status: ready for review. Head What this fixes: on Windows with npm-installed Codex, Orca's short background Codex processes (history indexing, the state-DB pre-create from #22971, the model-list and rate-limit probes, hook trust grants, the recovery claimant) each ran through an extra Review:
Verification:
Not verified on Windows: the hook trust grant, the backfill recovery claimant and the default-home indexer did not occur in the test flow. They use the same changed invocation builders and are covered by unit tests. Not tested with this PR and #23831 in one build. Out of scope, possible follow-ups: commit-message generation ( Not merged; marking ready for a human to decide. |
|
Warning Review limit reachedNext included review available in 52 seconds. View limit detailsLimit details: You’ve used all 10 included reviews currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (17)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
- Bare CLI handed to the spawn chokepoint. The five short-lived Codex callers (
codex-session-index-heal.tsbuildNativeHealInvocation,codex-model-catalog-probe.ts,codex-trust-grant-host.ts,codex-state-db-backfill-recovery.ts,codex-fetcher.tsfetchViaRpc) no longer pre-wrap the CLI withgetSpawnArgsForWindows; they pass the resolved path (the npmcodex.cmdshim) tospawnProcess/runCodexAppServerSession, soresolveSpawnresolves it tonode.exe <script>and dropscmd.exefrom the tree. - Two direct
spawncall sites migrated.codex-state-db-backfill-recovery.tsandcodex-fetcher.tsnow route through the chokepoint, replacing Node'sspawn; both files leave the child-process import allowlist, andcodex-fetcher.tsleaves the Windows console-visibility allowlist (pin lowered 61 → 60). - Ratchet + test rewiring. The fetcher tests now mock
spawnProcessinstead ofgetSpawnArgsForWindows, the recovery test asserts the shim reaches the chokepoint, andcodex-short-lived-app-server-spawn.test.tspins the index-heal, trust-grant, and model-catalog invocations to the shim onwin32. - Comment corrections. The cmd.exe-wrapper premises in the process-tree-kill, probe-termination, and CLI-pairing comments were updated to the launcher-agnostic wording.
Verification this run. All affected suites pass (98 + 61 tests), pnpm tc:node passes, and an ablation reverting codex-trust-grant-host.ts to the pre-wrap makes the new test fail with cmd.exe vs the shim — the new coverage is real, not vacuous. ORCA_DISABLE_CMD_SHIM_RESOLUTION still restores the cmd.exe fallback for these launches. One pre-existing, unamplified observation only: runCodexHookTrustGrantSession in codex-app-server-client.ts carries its own inline spawnProcess({ program, args, ...options }) adapter duplicating spawnCodexAppServerProcess; not introduced by this PR.
DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

ELI5
On Windows, every short background Codex process Orca starts (to index chat history, grant hook trust, read rate limits, list models) was launched through an extra
cmd.execommand prompt. Orca already knows how to skipcmd.exefor npm-installed tools, but these launches wrapped Codex incmd.exebefore that skip could see it. This PR hands them Codex directly, so the skip applies.What Changed
What broke, and who sees it. Found in the Windows validation of #22971 (Windows 11, npm-installed Codex 0.157.1). Orca's short-lived
codex app-serverprocesses launched ascmd.exe /d /s /c "…\npm\codex.cmd" …, even though Orca's process-launch chokepoint (spawnProcess) resolves npm.cmdshims tonode.exe <script>precisely to keepcmd.exeout of the tree. With a large chat history this is hundreds of launches: indexing 16,000 conversations after #22971 took 323cmd.exe→node→codex.exestarts. A burst of short-lived interpreters under one parent is one of the patterns endpoint security products score (seedocs/reference/windows-edr-posture.md)..cmdshims); Codex chats themselves (already spawned the bare shim); the interactive terminal; WSL and SSH Codex (launched throughwsl.exe/ the remote host);codex loginand the rate-limit PTY fallback (out of scope, unchanged).User-facing change. Nothing visible changes: the same probes run and return the same results. On Windows they now show up as
node.exe→codex.exewith nocmd.exeparent, and a probe timeout now names the Codex path instead ofC:\WINDOWS\system32\cmd.exe.Mechanism. The five callers built their argv with
getSpawnArgsForWindows, which turns a.cmdintocmd.exe /d /c <shim> …beforespawnProcessruns.spawnProcessonly resolves a shim it is handed, so it sawcmd.exeand spawned that. Each caller now hands the bare Codex path and its arguments tospawnProcess, the same way the long-lived chat session already does (codex-app-server-connection.ts). An unrecognised shim still falls back tocmd.exeinsidespawnProcess, with its own argument encoding.codex-session-index-heal.ts(buildNativeHealInvocation, used by the account index passes, the fix(codex): index a new account home before bridging history into it #22971 pre-create and the default-home indexer),codex-model-catalog-probe.ts,codex-trust-grant-host.ts: pass the CLI path instead of the pre-wrapped argv intorunCodexAppServerSession, which already spawns throughspawnProcess.codex-state-db-backfill-recovery.tsand the rate-limit RPC probe incodex-fetcher.tscalled Node'sspawndirectly (so they had to pre-wrap). They now spawn throughspawnProcess, and both leave thenode:child_processimport allowlist.Why
The chokepoint already owns this decision and is documented as the one place
.cmdhandling lives (docs/reference/windows-cmd-shim-resolution.md). Removing the pre-wrap makes these callers match the chat launch instead of adding a second shim resolver or a codex-specific special case. Alternatives considered: teachinggetSpawnArgsForWindowsto resolve shims would duplicate the chokepoint's logic in a second place; keepingcmd.exebecause these arguments are fixed flags (no free text) ignores the per-launch interpreter cost on large histories.Linked Issue
Follow-up from the Windows validation of #22971 (no separate issue).
Visual Proof
Nothing in Orca's window changes. These are Windows 11 builds from the same test run. Before (main) and after (this PR), the Codex chat opens and the model picker loads the account's model list the same way:
Before (main):

After (this PR), model picker open:

The difference is in which process starts Codex. A logging shim recorded the parent of every Codex start:
cmd.exeChat sessions were already started directly by Orca on both builds.
Testing
New
codex-short-lived-app-server-spawn.test.ts: on win32 with an npmcodex.cmd, the index-heal, trust-grant and model-catalog invocations hand the shim itself (notcmd.exe) to the session runner.Updated the rate-limit fetcher and backfill-recovery tests to assert the bare shim reaches
spawnProcess; the process-contract and exit-diagnostics tests now swap the stub in atspawnProcessinstead of atgetSpawnArgsForWindows.Ablation: with only the source reverted, the 7 Windows-shape assertions fail; with the change they pass.
pnpm tc:nodepasses; the affected fetcher, recovery, index-heal, trust-grant and import-boundary suites pass (180 tests).Windows 11 ("Windows high spec" box), npm Codex 0.157.1, Electron dev builds, isolated rig home, a guard
codex.cmd(byte-for-byte npm shim) that logs each start's parent process:mainat4da485cac1c: the state-DB pre-create, the index pass, the model-catalog probe and the rate-limit probe were each started bycmd.exe(cmd.exe→node.exe→codex.exe). The chat's own app-server was started byelectron.exe.11302c82f9b: across two runs, all 7 short-lived starts (and both chat starts) were started byelectron.exedirectly (electron.exe→node.exe→codex.exe), 0 viacmd.exe.main). Each short-lived process exited on its own in about 1 s, and no rig process was left after the rig stopped the app.eb265fc9dcb) and a test ratchet fixture (281eb58705a) only.I manually tested these changes locally
Automated tests added/updated, or explained why not below
Review
Agent skill upstream boundary
docs/reference/agent-skill-sharing-upstream-boundary.mdand copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.Notes
Cross-platform: POSIX behaviour is unchanged (
spawnProcesspasses non-.cmdprograms through as before). SSH/WSL: untouched paths. Kill switch:ORCA_DISABLE_CMD_SHIM_RESOLUTIONrestores thecmd.exepath for these launches too.Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)