Repository navigation
Conversation
`dispatch --inject` delivered the preamble as terminal input terminated by Enter without checking pane readiness. A worker parked on Codex's directory-trust prompt consumed that Enter to answer the prompt, which silently granted the trust decision as a side effect of task delivery and swallowed the TASK body. Dispatch still returned `injected: true`, the worker received no work, and the task stayed `dispatched` forever with no error surfaced anywhere. Gate `--inject` on the same readiness signal the renderer's send path already refuses on, and fail loudly with an actionable message. Readiness lookup failures are treated as "not blocked" so an unreachable terminal keeps surfacing its own precise error from the send path. Also fix the Antigravity ready-prompt probe, which is what made the documented `terminal wait --for tui-idle` guard unreliable: it recorded the FIRST model/prompt line after the banner, so once a startup modal was drawn over the initial paint, the ready evidence stayed behind the modal text and the stale blocked signal never cleared. Record the last match instead, matching the `lastIndexOf` semantics of the Codex and Cursor probes beside it. Refs stablyai#10666
📝 WalkthroughWalkthroughAdds interactive-prompt detection before injected task delivery, preventing preambles from being consumed by permission prompts while allowing injection when no blockage is reported or readiness lookup fails. Updates Gemini header matching to use the latest evidence and adds Antigravity trust-prompt tests covering repaint and no-repaint TUI-idle outcomes. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
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.
🧹 Nitpick comments (1)
src/main/runtime/rpc/methods/orchestration.ts (1)
498-503: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winCondense the guard rationale.
The six-line comment repeats details already present in the thrown error. Keep the non-obvious Enter/prompt hazard in one concise line.
Proposed simplification
- // Why (`#10666`): the preamble is delivered as terminal input terminated by Enter. A pane - // parked on an interactive prompt (directory trust, permission, upgrade notice) consumes - // that Enter to answer the prompt — granting a trust decision as a side effect of task - // delivery — and swallows the TASK body, so the task stays dispatched forever with no - // error anywhere. Refuse loudly instead. The renderer's send path already gates on this - // same readiness signal; the dispatch path must not be weaker than the UI. + // Prevent Enter-terminated preambles from answering live interactive prompts (`#10666`).Source: Coding guidelines
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 1ae18acd-d735-45be-b36d-c59375bd01c2
📒 Files selected for processing (4)
src/main/runtime/orca-runtime.test.tssrc/main/runtime/orca-runtime.tssrc/main/runtime/rpc/methods/orchestration.test.tssrc/main/runtime/rpc/methods/orchestration.ts
Summary
Addresses #10666.
orca orchestration dispatch --injectdelivers the preamble as terminal input terminated by Enter, with no check on whether the target pane is able to receive it. If the worker is sitting on Codex's directory-trust prompt, that Enter answers the prompt: the trust decision is granted as a side effect of task delivery, the TASK body is swallowed, and dispatch still returnsinjected: true. The coordinator then waits forever on a worker that received no work, and the task staysdispatchedwith no error surfaced anywhere — which is the mechanism behind the reporter's 11 orphanedcodexprocesses accumulated over six days.Two changes:
1.
dispatch --injectrefuses to inject into a pane parked on an interactive prompt. The gate reuses the readiness signal the renderer's own send path already refuses on (src/renderer/src/lib/active-agent-terminal-send-readiness.tsreturns'permission'and blocks the send). The CLI/orchestration path was simply weaker than the UI for the same hazard. The refusal happens beforecreateDispatchContext, matching the placement of the existing "no recognized agent detected" pre-check, so no dispatch row is created and the task staysready.Added
OrcaRuntimeService.isTerminalBlockedOnInteractivePrompt(), which is deliberately positive-evidence-only: readiness lookups throw for gone/exited/stale handles, and those cases returnfalserather than "blocked", so an unreachable terminal keeps surfacing its own precise error from the send path instead of a misleading one. That also keeps every existing dispatch test's behavior unchanged.2. The Antigravity ready-prompt probe now reads the latest paint, not the first. This is what made the documented
terminal wait --for tui-idleguard unreliable, which is why the issue's suggested workaround does not protect.findAntigravityReadyPromptIndex()recorded the first model line and first bare>line after the banner. Antigravity paints banner/model/prompt once, a startup modal (directory trust) is drawn after that paint, and it then repaints model/prompt lines without repeating the banner. So the ready evidence stayed positionally behind the modal text forever,findDismissedStartupModalIndex()never saw newer evidence, and the answered prompt kept reportingblockedReason: 'codex-trust-workspace'indefinitely. Recording the last match matches thelastIndexOfsemantics that the Codex and Cursor probes directly beside it already use, and it is the same bug class already fixed for Cursor in #8210.Deliberately not included (see Notes): the issue's third suggestion (surface stuck dispatches) is a design/UX change rather than a bug fix, and renaming the Codex-shaped
codex-trust-workspacereason is a breaking change to a CLI-visible enum. Both are flagged for maintainers instead of decided here.Screenshots
No visual change. Both changes are main-process logic; the error surfaces as a CLI/RPC error string.
Testing
Verified on Windows 11 with portable Node v24.18.0 (matching
engines.node) and pnpm 9.15.9. Both touched suites importnode:sqlitetransitively, so they cannot even load on older Node — worth knowing if anyone else hitsError: No such built-in module: node:sqlite.5 tests added.
vitest run --config config/vitest.config.ts src/main/runtime/orca-runtime.test.ts src/main/runtime/rpc/methods/orchestration.test.ts:upstream/main(f3d8edb)995 → 1000is exactly the 5 added tests, no failures on either side and no pre-existing failures in these files.Added tests:
rejects inject when the target pane is parked on an interactive prompt— asserts the throw, thatsendTerminalAgentPromptis never called, that the task staysready, and that no dispatch context is created.still injects when the target pane reports no interactive prompt— guards against over-blocking normal dispatch.does not block dispatch when pane readiness cannot be determined— pins the fail-open-on-unknown decision so it can't be changed silently.resolves tui-idle for an Antigravity lane past its dismissed trust prompt (#10666).still reports blocked for an Antigravity lane sitting on a live trust prompt (#10666)— the important one: it pins that reading the latest ready evidence does not weaken detection of a live trust prompt into a false "ready". A false ready here would re-enable the exact injection this PR is preventing.Negative controls (each fix reverted independently, tests re-run):
Removed only the dispatch guard → the test fails by reproducing the reported symptom exactly:
That is the bug verbatim:
injected: truereturned for a pane parked on a prompt.Restored only the first-match ordering in the Antigravity probe → the dismissed-trust test fails:
and the 13 other Antigravity tests — including the live-trust-prompt test — still passed, so the failure is attributable to the ordering change alone.
Other gates (all on Node 24):
pnpm lint— partially.oxlintexit 0 (Found 27 warnings and 0 errors, all pre-existing, none in touched files).lint:switch-exhaustiveness,check-styled-scrollbars,check:reliability-gates,check:max-lines-ratchet,verify:bundled-skill-guides,verify:localization-catalogall exit 0.verify:skill-bundle-manifestandverify:localization-coverageexit 1, and fail identically on pristineupstream/main(stale generatedresources/skills/*.json;Ghosttykeyword coverage). Unrelated to this change; I did not regenerate artifacts I have no business regenerating.pnpm typecheck— clean, all three projects exit 0.pnpm test(full suite) — not run end-to-end;pnpm testfirst runsensure-native-runtime.mjs, and thenode-ptynative rebuild needs an MSVC toolchain I don't have on this non-admin box. Ranvitestdirectly on the affected suites with the baseline comparison above.pnpm build— not run (native + Electron packaging, same toolchain gap).oxfmt --checkon all four touched files →All matched files use the correct format.What I could not verify, stated plainly: I have no
codex-cliand no Antigravity CLI on this machine, so there is no live end-to-end repro. Fix 1 is verified at the unit level against the readiness contract, which is where the defect lives. Fix 2 is verified against the mechanism (paint ordering) using this repo's own Antigravity fixture shapes, includingantigravityPromptBeforeModelReadyScreen, which showsagyre-emitting model/path/prompt lines without repeating the banner. If Antigravity's post-trust frame differs from those fixtures in a way that changes the probe's inputs — e.g. no bare>line, or a box-drawn input row — then the probe needs a real capture to fix properly. @lalagogo2012, if you can paste the raw tail of anagypane right after answering the trust prompt, I'll confirm or correct that half.AI Review Report
Written and reviewed with an AI coding agent (Kiro CLI). This PR is AI-authored; the review below is the agent's own.
Risks checked:
tui-idlehalf, the review rejected the issue's stated diagnosis ("the detector is keyed to Codex-specific strings"). That is not the mechanism:TERMINAL_WAIT_BLOCKED_SENTINEL_REis generic (do you trust/trust this/trusted workspace) and matches Antigravity's prompt correctly. Only the label is Codex-shaped. The actual defect is first-match vs. last-match ordering in the Antigravity ready probe, which is why the signal never cleared.isKnownReadyPromptPreview()more likely to report ready, and a false "ready" would re-enable injection into a live trust prompt. Mitigations:>only matches a line whose entire trimmed content is>, and Codex/Antigravity trust prompts use›(U+203A) for their selection cursor, not>; plus a dedicated test asserts a live trust prompt still reports blocked. Verified by negative control that this test passes with both orderings.--injectdispatch, only after the existing agent check already passed.findAntigravityReadyPromptIndexkeeps the same single-pass, no-split()scan; the change only drops two=== nullshort-circuits, so worst-case work is unchanged (it already walked to end of tail) and the existing "nosplit()on the ready tail" performance test still passes.\ris already handled by the existing whitespace helper. Tests were executed on Windows; the reported behavior was on macOS arm64. No Electron platform API touched.Flagged during review and acted on: the first draft of the "rejects inject" test let
sendTerminalAgentPromptcall through, so its negative control failed with an unrelatedruntime_unavailableinstead of demonstrating the bug. The mock was changed to resolve successfully, which is what makes the negative control print the realinjected: truesymptom quoted above.Security Audit
pnpm-lock.yamluntouched.--dangerously-bypass-approvals-and-sandboxno longer suppresses the trust prompt (upstream [possible degradation] Directories are now not trusted by default even with the--dangerously-bypass-approvals-and-sandboxoption. openai/codex#14345). That is Codex-side; this PR makes Orca behave safely regardless of whether that flag works.Notes
dispatchedpast a heartbeat threshold) is intentionally not in this PR. It needs a product decision on threshold and surface, and it belongs in the coordinator rather than the dispatch handler. Happy to do it as a follow-up if you tell me where you'd want it surfaced.codex-trust-workspacereported for an Antigravity pane is a naming wart, exactly as the reporter observed. I left it alone deliberately:RuntimeTerminalWaitBlockedReasonis CLI-visible (terminal wait --json), so renaming it or adding an agent-neutral alias is a breaking change for existing coordinator scripts. Your call — I'd be glad to add a neutral reason with the old value kept for compatibility if you want it.terminal create --titlenot applying the title; automation run records withfinishedAt: null). They look like genuine separate bugs; keeping this PR to one topic. They deserve their own issues.X handle: I don't have one.
ELI5
Injecting orchestration tasks into a blocked agent pane (e.g. a trust prompt) could accidentally answer the prompt and lose the task. Dispatch now refuses inject into blocked panes so trust decisions and tasks stay separate.