fix: recognize wrapper-launched Claude Code composers and queue with Enter - #26
Conversation
…Enter Claude Code seats launched through `accounts launch … --tool claude` run as a bare `node` pane, so recognition takes the wrapper path: process-tree proof plus live composer UI proof. The process tree already proved `claude`, but liveUiProofForKind had no Claude Code content matcher — the generic hasNamedAgentComposer requires a name banner plus model:/cwd: context lines that the steady-state Claude Code TUI never renders. Every wrapped Claude Code pane was therefore refused as "not a recognized agent composer (node)", and --force-active could not override, because detection never proved an agent at all. - add hasWrappedClaudeComposer: process-gated content proof from the real TUI signature — the ❯ composer glyph (plain or NBSP-padded) or the `esc to interrupt` busy marker, combined with the permission-mode footer (`⏵⏵ bypass permissions on`, `accept edits on`, `plan mode on`, `? for shortcuts`) or the account/model status lines. A bare composer glyph without chrome stays refused, so copied transcripts are still not targets. - make the queue submit key agent-specific (AGENT_QUEUE_SUBMIT_KEYS): Codewith queues with Tab, Claude Code queues with plain Enter. Claude panes no longer advertise Tab as a submit key — in Claude Code Tab is completion, not submission, so `dispatch key Tab` now correctly refuses. - resolve --queue delivery through the detection's proven queue key and let Enter-queueing agents through the idle-only Enter gates; queued delivery is single-shot for every queue key to avoid double-queueing. - fixtures are sanitized captures from the live hq seats measured on station01 (2026-07-31), including the real accounts-launch process tree. Repro fixed: `dispatch send --to hq:staff -p test --dry-run --json` now returns agentKind claude, composerState idle, canReceivePrompt true instead of refusing with targetKind unknown. Bug task: cb60ace2-fe5d-43e4-849b-d2df60d0e9c6 Agent: Augustus
Agent: Augustus
|
[REVIEW] NO_GO — #26 @ 5d5a820 — lens: correctness+security, reviewer Quintus (1 of 1) Note: PR head 34a6808 = 5d5a820 + a one-line version bump (0.0.24→0.0.25, package.json only, verified by diff); all findings below apply to the PR head. npm still serves 0.0.24. Verdict: NO_GO — the acceptance criteria themselves all pass, but the per-agent queue-key change missed one consumer, and that miss is a newly reachable wrong-key delivery into live Claude seats. P1 (blocking):
|
Review findings on #26 (cycle 1): - P1: recommendRecoveryAction hardcoded Tab for every canQueuePrompt target, so `dispatch recover --apply` would press Tab in an active Claude Code seat — the key the queue-key map exists to avoid. Recovery now uses the detection's proven queue key, and the engine Tab gate additionally requires Tab to BE the proven queue key, so a stale Tab recommendation can no longer reach a Claude composer. - P2: --queue --submit-key Enter on an active Codewith pane rode the queuedDelivery exemption with the wrong key. queuedDelivery now requires the resolved submit key to equal the proven queue key; mismatched explicit keys fall back to the strict idle-only gates, as at base. - P3: removed the unused queueSubmitKeyFor export; consumers read the proven key from detection.recommendedSubmitKey. Regression tests written failing-first: - agent-recovery: "recover plans queued Enter recovery for active Claude Code seats, never Tab" - engine: "refuses --queue --submit-key Tab against active Claude Code seats" and "refuses --queue --submit-key Enter against active Codewith panes" Agent: Augustus
|
[REVIEW] GO — #26 @ 92f4829 — lens: correctness+security, reviewer Quintus (1 of 1) Remediation cycle 1 re-review, scoped to my named defects and their direct regressions per the bounded-review policy. All findings are fixed and verified by re-running the original repros against the new head. P1 fixed and verified.
P2 fixed and verified. P3 fixed. Dead Regression surface of the fix itself checked: legitimate Codewith Tab queueing ("queues active wrapped Codewith panes with Tab", "recover ... plans queued Tab recovery for active Codewith panes") and the no-queue-support refusal all pass in the full run. Failing-first verified for the three new tests: copied onto pre-fix source 5d5a820, all three fail (3 fail / 66 pass); at 92f4829 all pass. Gates: full suite 494 pass / 2 fail — the same two pre-existing environmental confirm-regression.integration failures already reproduced identically at clean base 27a5f75 (80-col pane wraps the long cwd). Scope check: the remediation diff (34a6808..92f4829) touches only agent-recovery.ts, engine.ts, exec-policy.ts (dead-export removal) and the two test files — nothing outside the named defects. Clear to merge. |
|
[REVIEW] GO — #26 @ 92f4829 — lens: correctness+security, reviewer Quintus (1 of 1) Re-review of remediation cycle 1. Scope limited to my three named defects and their direct regressions, per the bounded-review policy. All three are fixed and verified by re-running my original repros, not by reading the diff. P1 (blocking, FIXED) — Tab into an active Claude Code seat. At 5d5a820 this returned P2 (FIXED) — P3 (FIXED) — dead Regression tests present and passing (all failing-first claims accepted on the basis that they encode the exact refuted behaviour):
Direct regressions — none found.
Gates. Full suite 496 pass / 0 fail, exit 0 ( Provenance / caveat, stated because it affects what this verdict certifies. My review worktree was deleted mid-run (PR already merged; worktree cleanup). The first full-suite attempt is therefore garbage — 30 fail / 28 errors, all No concrete, currently-reachable P0/P1 remains in the remediated code or its direct regressions. GO. |
Bug
dispatch send/dispatch triagerefused prompt delivery to every Claude Code seat on the fleet:Measured on station01 (2026-07-31 ~09:08Z) against the hq tmux session — 7 windows, each a live Claude Code TUI launched via
accounts launch … --tool claude.--force-activecannot override because detection never proves an agent at all. This blocks the CEO coordinator delivering directives into seat terminals.Bug task:
cb60ace2-fe5d-43e4-849b-d2df60d0e9c6(dispatch project).Root cause
Wrapper-launched panes (
node) need process-tree proof AND live composer UI proof. The process tree already provesclaude(theclaude --dangerously-skip-permissionschild). ButliveUiProofForKindhad wrapped-composer matchers only for Codewith and Codex; for claude it fell back tohasNamedAgentComposer, which requires a name-banner line plusmodel:/cwd:context lines — a synthetic shape the steady-state Claude Code TUI never renders (the existing wrapped-claude test passed only because its fixture invented that banner).Fix
hasWrappedClaudeComposer(src/lib/exec-policy.ts), wired intoliveUiProofForKindalongside the Codewith/Codex matchers: process-gated content proof from the real TUI signature — the❯composer glyph (plain or NBSP-padded) or theesc to interruptbusy marker, combined with the permission-mode footer (⏵⏵ bypass permissions on,accept edits on,plan mode on,? for shortcuts) or the account/model status lines. A bare❯with no chrome stays refused (existing spoof-guard test still green), and the accounts launcher alone (noclaudechild) is not evidence.AGENT_QUEUE_SUBMIT_KEYS): Codewith queues with Tab (unchanged); Claude Code queues with plain Enter. Claude panes no longer advertise Tab as a submit key — in Claude Code Tab is completion, not submission, sodispatch key Tabto a claude pane now correctly refuses.--queueresolves the detection's proven queue key; Enter-queueing agents pass the idle-only Enter gates when queueing is explicitly requested and proven; queued delivery is single-shot for every queue key (avoids double-queueing).Regression tests (written failing-first)
recognizes wrapped idle Claude Code seats launched through the accounts wrapper— the headline regression: sanitized capture of a real hq seat + the real measured process tree must yieldagentKind claude, composerState idle, canReceivePrompt true, submitKeys ["Enter"].recognizes busy wrapped Claude Code seats and offers Enter queueingrecognizes the Claude Code composer glyph followed by a non-breaking space(the live TUI pads❯with U+00A0)refuses Claude Code seat content without Claude process evidence(spoof tree + launcher-only tree)queues active wrapped Claude Code seats with Enter when queue is explicitly requestedEvidence
Full suite: 491 pass / 2 fail — the 2 failures are
confirm-regression.integration.test.tsreal-tmux tests that fail identically at clean base27a5f75(pre-existing, environment-dependent; out of scope).bun run typecheckandbun run buildgreen.Live dry-run with the built fix on station01:
Fixtures are sanitized (synthetic workspace id, synthetic dollar/percent figures); profile slugs match the shapes already present in the repo's Codewith fixtures.
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.