Repository navigation
Surface Claude's terminal select dialogs in Chat - #1194
nortonandreev wants to merge 4 commits into
Conversation
Trade-offs and open decisionsFor team discussion before this leaves draft. Why the screen, not a hookWith Claude Code 2.1.283 and every hook event logged, nothing fires while a startup dialog is up — not
A falls back to D when the choices can't be parsed, so a UI change on Claude's side degrades to "Open Terminal" rather than to silence. Decisions to make
Known limitations
|
PR Summary by QodoSurface Claude terminal select dialogs in Chat
AI Description
Diagram
High-Level Assessment
Files changed (22)
|
Code Review by Qodo
1.
|
Declined. DaemonMutationLane sequences install, replace, and start of the daemon service. A menu answer is a raw write on the attach client, the same path as other terminal input. |
|
The macOS failure is not from this change. Ubuntu and Windows passed the same commit.
|
Claude fires no hook while a startup dialog such as workspace trust or a new MCP server is up, so the screen is the only place it shows. Its menus take arrow keys, not digits, sent as one write so the TUI never reads a lone Escape.
The PTY follows whichever viewer attached, so the emulated copy is resized with it: Claude wraps a long label at the label's own column, and only the drawn width tells a wrap from a new choice.
A mid-redraw is the only empty menu that keeps its previous choices. A dialog still on the terminal blocks the composer while its card is hidden, and a resize whose cell count does not fit is ignored.
e2adc09 to
80f5ae4
Compare
AI-3233 — no GitHub issue exists
What & why
Claude's startup dialogs (workspace trust, a new project MCP server) show only in the Terminal tab: no hook fires while one is up, and
SessionStartarrives only after it is answered. The daemon now reads a Claude select dialog off its emulated copy of the PTY screen by layout (a rule, the text, and theEnter to confirm · Esc to cancelfooter as the last line on screen), and publishes it on the agent status asterminal_dialog. Chat shows it as a "Waiting for you in Terminal" card with an Open Terminal button, and answers it with arrow keys and Enter in one write. If the choices can't be read as a single-choice list (a checkbox list, say), the card shows the screen text instead. While a dialog is up, the session reads Needs you in the rail, the worktree rollup and the title bar.Where to look
ClaudeTerminalDialogDetector(Harness/Claude/): the anchor is the footer as the last line on screen. Ordinary output always has the prompt box below it, so a transcript that quotes the footer is not a dialog. A same-column row counts as a wrapped label only when its first word could not have fit on the row above.ClaudeScreenWatcherresizes the emulated screen to the PTY's current size. Claude's cursor moves are relative to the width it drew for, and that width decides where a label wrapped.Verification
Ran real Claude Code 2.1.283 in a PTY: sending
ESC[A ESC[A CRin one write picked "Use this MCP server" and wroteenabledMcpjsonServers. Pressing a digit did nothing.The same MCP dialog captured at 40 columns is a test fixture: its heading and two labels wrap, and it still parses as 3 choices with the cursor followed across an Up arrow. With the width check, the resize, or the mid-redraw hold removed, the matching tests fail.
Test suites:
Capacitor.App.Tests.Unit2826/2826, including a mid-turn row with a dialog reading Needs you.Capacitor.Cli.Core.Tests.Unit4063 passed, 9 skipped.Capacitor.Cli.Daemon.Tests.Unit3689 passed, 59 skipped, 1 failed:Installed_codex_schema_matches_the_vendored_pin, because the localcodex(0.145.0) is older than the vendored pin (0.155.0).Daemon and CLI AOT publish: 0 IL warnings.