Skip to content

Surface Claude's terminal select dialogs in Chat - #1194

Draft
nortonandreev wants to merge 4 commits into
mainfrom
norton/ai-3233-chat-mcp-trust-prompt
Draft

nortonandreev wants to merge 4 commits into
mainfrom
norton/ai-3233-chat-mcp-trust-prompt

Conversation

@nortonandreev

@nortonandreev nortonandreev commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

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 SessionStart arrives 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 the Enter to confirm · Esc to cancel footer as the last line on screen), and publishes it on the agent status as terminal_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.
  • ClaudeScreenWatcher resizes 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.
  • A hook-driven card hides the terminal card. A usage-limit question takes over the card and stays answered while the dialog under it redraws.

Verification

  • Ran real Claude Code 2.1.283 in a PTY: sending ESC[A ESC[A CR in one write picked "Use this MCP server" and wrote enabledMcpjsonServers. 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.Unit 2826/2826, including a mid-turn row with a dialog reading Needs you. Capacitor.Cli.Core.Tests.Unit 4063 passed, 9 skipped. Capacitor.Cli.Daemon.Tests.Unit 3689 passed, 59 skipped, 1 failed: Installed_codex_schema_matches_the_vendored_pin, because the local codex (0.145.0) is older than the vendored pin (0.155.0).

  • Daemon and CLI AOT publish: 0 IL warnings.

@linear-code

linear-code Bot commented Sep 28, 2026

Copy link
Copy Markdown

AI-3233

@nortonandreev nortonandreev self-assigned this Sep 28, 2026
@nortonandreev

Copy link
Copy Markdown
Contributor Author

Trade-offs and open decisions

For team discussion before this leaves draft.

Why the screen, not a hook

With Claude Code 2.1.283 and every hook event logged, nothing fires while a startup dialog is up — not Notification, not PermissionRequest. SessionStart arrives only after the dialog is answered. The PTY screen is the only place these prompts exist, so the choice is between:

Option Covers new dialogs Cost
A. Generic screen detection (this PR) Yes, any dialog using Claude's select component Screen parsing can drift when Claude changes its UI
B. Per-dialog detectors (e.g. MCP only) No, one change per new dialog Same fragility, repeated per dialog
C. Pre-answer in config, as TrustWorktreeInClaudeConfig does for folder trust No, one dialog at a time For MCP it would trust a server on the user's behalf, a security decision we should not make silently
D. "Terminal needs you" banner only, no choices Yes Much simpler, but the user still has to switch to Terminal

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

  1. Scope of what gets surfaced. Detection is by layout (the Enter to confirm · Esc to cancel footer and the ❯ cursor row), so dialogs the user opened themselves in Terminal (slash-command pickers, /model, etc.) also show in Chat. Options:
    • keep it, since mirroring the terminal is arguably right
    • surface only dialogs raised before the first prompt (startup dialogs)
    • hide when the Terminal tab is focused
  2. Stale cursor when answering. A choice is sent as arrow keys relative to the option the daemon last saw selected, then Enter. If the user moved the cursor in Terminal between that snapshot and the click, a different option gets confirmed. For a trust dialog that could mean "Use this and all future MCP servers". Options:
    • accept it, since the window is small
    • anchor first, pressing Up N times to reach the top, but only if Claude's select clamps rather than wraps (needs checking)
    • re-read the screen right before sending and refuse if the selection moved
  3. Local only. terminal_dialog goes on the local status IPC only; the server/web view does not see it. Should remote viewers see a "waiting in Terminal" state? Should they be able to answer, given these are trust decisions and today's consent rules for server-driven actions?
  4. Multi-select dialogs. For example, the MCP dialog listing several servers with checkboxes currently gets only the screen-text + Open Terminal fallback. Is that acceptable, or do we want toggle support?
  5. Waiting-on-you signal. A dialog changes only the status dot inside Chat. The sidebar session row and the tray don't show "needs you". Do we want them to, as a permission card does?
  6. Other vendors. This is Claude-only. Codex, Copilot and others have their own TUI dialogs. Should the detector shape (layout rules per vendor → one terminal_dialog DTO) be the pattern they follow?
  7. File placement. ClaudeScreenWatcher and ClaudeTerminalDialogDetector sit in Capacitor.Cli.Daemon/Services/, next to the existing ClaudeUsageLimitDetector. The repo convention puts vendor code under Harness/Claude/. Move all three here or in a follow-up?

Known limitations

  • The emulated screen is a fixed 120×40 (existing). A much wider PTY could garble the parse.
  • Parsing depends on Claude's current select-component layout. A change degrades to the screen-text fallback, not to a wrong answer, unless the layout changes in a way that still parses with shifted rows. The tests pin today's recorded bytes.
  • No one has clicked through the card in the desktop app against a live daemon yet. The verification above is a PTY run against real Claude plus replayed recordings.

@nortonandreev
nortonandreev marked this pull request as ready for review September 28, 2026 11:22
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Surface Claude terminal select dialogs in Chat

✨ Enhancement 🧪 Tests 🕐 40+ Minutes

Grey Divider

AI Description

• Detect Claude startup dialogs from the live terminal screen when no hook reports them.
• Show readable choices in Chat, with a Terminal fallback for dialogs that cannot be safely parsed.
• Preserve usage-limit behavior and send menu answers as one raw terminal write.
Diagram

sequenceDiagram
    actor User
    participant PTY as Claude PTY
    participant Screen as Screen Watcher
    participant Detector as Dialog Detector
    participant Daemon as Agent Orchestrator
    participant IPC as Status IPC
    participant Chat as Chat Menu
    participant Input as Terminal Input
    PTY->>Screen: Output and size
    Screen->>Detector: Emulated screen
    Detector-->>Daemon: Dialog or fallback
    Daemon->>IPC: Running agent status
    IPC->>Chat: Terminal dialog
    User->>Chat: Choose or open Terminal
    Chat->>Input: Raw menu keys
    Input->>PTY: One write
Loading
High-Level Assessment

The shared, PTY-sized screen watcher and optional status field fit the existing usage-limit and agent-status paths. Hook-only or transcript-based detection cannot expose these pre-session dialogs, while leaving every dialog to Terminal would not meet the Chat goal. Retaining a Terminal fallback avoids guessing how to answer unsupported menus.

Files changed (22) +749 / -158

Enhancement (15) +399 / -106
TerminalInputEncoder.csEncode cursor movement and confirmation for menu choices +10/-0

Encode cursor movement and confirmation for menu choices

• Adds an encoder that moves from the displayed selection to the chosen option with arrow keys, then appends Enter. It returns one byte sequence for a single terminal write.

src/Capacitor.App/Services/TerminalInputEncoder.cs

ChatInput.csAllow Chat inputs to send multiple raw keys +3/-2

Allow Chat inputs to send multiple raw keys

• Replaces the single-key menu API with a byte-array API so a complete terminal answer can be sent without bracketed paste.

src/Capacitor.App/ViewModels/ChatInput.cs

ChatSessionInfo.csCarry terminal dialogs into local Chat sessions +4/-2

Carry terminal dialogs into local Chat sessions

• Adds an optional terminal dialog to session information and maps it from local agent status. Remote and older-daemon sessions can continue without one.

src/Capacitor.App/ViewModels/ChatSessionInfo.cs

ChatTabViewModel.csUnify usage-limit and terminal-dialog Chat menus +133/-63

Unify usage-limit and terminal-dialog Chat menus

• Presents detected dialog choices or screen-text fallback, prioritizes usage-limit questions and pending hook cards, and blocks composer sends while a terminal menu is active. Tracks answered menus across redraws, handles failed sends, and exposes an Open Terminal command.

src/Capacitor.App/ViewModels/ChatTabViewModel.cs

TerminalChatInput.csForward complete menu answers to the terminal +1/-1

Forward complete menu answers to the terminal

• Adapts the terminal-backed Chat input to pass a byte array through the raw terminal send path.

src/Capacitor.App/ViewModels/TerminalChatInput.cs

TerminalTabViewModel.csSend raw menu sequences in one guarded write +5/-7

Send raw menu sequences in one guarded write

• Extends the existing attachment and delivery-gated raw send path from one key to a byte array. A complete arrow-and-Enter answer reaches the client in one write.

src/Capacitor.App/ViewModels/TerminalTabViewModel.cs

WorkspaceViewModel.csConnect the Chat fallback to the Terminal tab +3/-1

Connect the Chat fallback to the Terminal tab

• Supplies Chat with a workspace action that activates Terminal when the user selects Open Terminal.

src/Capacitor.App/ViewModels/WorkspaceViewModel.cs

ChatTabView.axamlRender a shared terminal-menu card in Chat +25/-10

Render a shared terminal-menu card in Chat

• Replaces the usage-limit-only card with a menu card that can show a dialog heading, choices, or unparsed screen text. Adds Open Terminal and disables the composer while the card represents an active menu.

src/Capacitor.App/Views/ChatTabView.axaml

StatusIpc.csExpose terminal dialogs in agent status +4/-1

Expose terminal dialogs in agent status

• Adds a nullable terminal-dialog field to the agent status DTO so older daemons and agents without a visible dialog remain compatible.

src/Capacitor.Cli.Core/LocalIpc/StatusIpc.cs

TerminalDialogDto.csDefine a value-comparable terminal-dialog payload +34/-0

Define a value-comparable terminal-dialog payload

• Adds heading, body, options, selected index, and screen text for Chat consumers. Value equality prevents unchanged screen observations from appearing as new dialogs.

src/Capacitor.Cli.Core/LocalIpc/TerminalDialogDto.cs

ClaudeScreenWatcher.csShare a resized Claude screen across menu detectors +30/-0

Share a resized Claude screen across menu detectors

• Emulates each PTY chunk once, then reads both usage-limit questions and select dialogs from the screen. Retains previously readable choices when a chunk ends partway through a same-heading redraw.

src/Capacitor.Cli.Daemon/Harness/Claude/ClaudeScreenWatcher.cs

ClaudeTerminalDialogDetector.csDetect Claude select dialogs by screen layout +104/-0

Detect Claude select dialogs by screen layout

• Requires a rule and confirmation footer at the end of the visible screen, then extracts the heading, body, selection, and width-dependent wrapped choices. Returns screen text without actionable choices when it cannot safely read a single-choice list.

src/Capacitor.Cli.Daemon/Harness/Claude/ClaudeTerminalDialogDetector.cs

AgentOrchestrator.LocalIpc.csPublish live terminal dialogs in status snapshots +2/-1

Publish live terminal dialogs in status snapshots

• Includes the tracked dialog for running agents and reports null for agents that are no longer running.

src/Capacitor.Cli.Daemon/Services/AgentOrchestrator.LocalIpc.cs

AgentOrchestrator.csObserve Claude menus during PTY reads +17/-14

Observe Claude menus during PTY reads

• Tracks the current terminal dialog alongside the usage-limit notice and initializes one watcher at the agent's PTY size. Resizes it as needed and pulses status only when either observed menu changes.

src/Capacitor.Cli.Daemon/Services/AgentOrchestrator.cs

AnsiScreen.csKeep terminal emulation aligned with PTY dimensions +24/-4

Keep terminal emulation aligned with PTY dimensions

• Adds screen resizing and dimension accessors so cursor placement and label wrapping reflect the viewer's current PTY size. Also recognizes additional private CSI prefixes used by Claude.

src/Capacitor.Cli.Daemon/Services/AnsiScreen.cs

Refactor (2) +19 / -10
TerminalMenuChoiceViewModel.csRepresent choices for either terminal menu type +17/-0

Represent choices for either terminal menu type

• Introduces a choice model containing its label, raw answer bytes, and command. It serves both usage-limit questions and parsed select dialogs.

src/Capacitor.App/ViewModels/TerminalMenuChoiceViewModel.cs

ClaudeUsageLimitDetector.csMake usage-limit detection consume the shared screen +2/-10

Make usage-limit detection consume the shared screen

• Moves the detector into the Claude harness namespace and removes its private screen emulator. The shared watcher now supplies screen text to its parser.

src/Capacitor.Cli.Daemon/Harness/Claude/ClaudeUsageLimitDetector.cs

Tests (5) +331 / -42
ChatTabViewModelTests.csCover Chat dialog answers, fallback, and precedence +126/-16

Cover Chat dialog answers, fallback, and precedence

• Updates usage-limit tests for the shared menu and adds tests for one-write arrow answers, composer blocking, unreadable-choice fallback, hook-card precedence, and answered-state retention through redraws.

test/Capacitor.App.Tests.Unit/ChatTabViewModelTests.cs

ChatTabViewSmokeTests.csExercise the renamed shared menu card +2/-2

Exercise the renamed shared menu card

• Updates the Chat view smoke test to locate the terminal-menu card and answer a usage-limit choice through the shared choice model.

test/Capacitor.App.Tests.Unit/ChatTabViewSmokeTests.cs

StatusIpcJsonTests.csPin terminal-dialog status serialization +27/-14

Pin terminal-dialog status serialization

• Updates exact JSON expectations for the nullable status field and verifies that a dialog's options and selected index survive serialization and deserialization.

test/Capacitor.Cli.Core.Tests.Unit/LocalIpc/StatusIpcJsonTests.cs

ClaudeTerminalDialogDetectorTests.csTest dialog parsing against captured terminal renders +166/-0

Test dialog parsing against captured terminal renders

• Covers normal and 40-column MCP dialogs, cursor redraws, resize behavior, clearing, checkbox fallback, and output that merely quotes the footer.

test/Capacitor.Cli.Daemon.Tests.Unit/Harness/Claude/ClaudeTerminalDialogDetectorTests.cs

ClaudeUsageLimitDetectorTests.csRun usage-limit coverage through the shared watcher +10/-10

Run usage-limit coverage through the shared watcher

• Adapts existing menu, partial-chunk, screen-clear, and false-positive tests to the shared Claude screen watcher.

test/Capacitor.Cli.Daemon.Tests.Unit/Harness/Claude/ClaudeUsageLimitDetectorTests.cs

@qodo-code-review

qodo-code-review Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (1) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Terminal resize ends agents ✓ Resolved
Description
AnsiScreen.Resize allocates new char[cols * rows] without bounding the PTY dimensions received
through the local resize path. A valid ushort resize such as 65535×65535 overflows the length
calculation or requests a multi-gigabyte buffer; the resulting exception escapes NoteScreen into
the agent output loop, which finalizes the running agent.
Code

src/Capacitor.Cli.Daemon/Services/AnsiScreen.cs[41]

+        var cells = new char[cols * rows];
Relevance

●●● Strong

Accepted precedent requires validating resize dimensions before storing or using them.

PR-#188

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Local resize frames carry ushort dimensions with no upper bound, and the clamp copies those
dimensions to CurrentCols and CurrentRows. The new screen watcher consumes those values on the
next output chunk, while AnsiScreen.Resize allocates from their unchecked product; output-loop
exceptions are caught outside the loop and enter its finalization path.

src/Capacitor.Cli.Daemon/Services/AgentOrchestrator.LocalIpc.cs[503-506]
src/Capacitor.Cli.Daemon/Services/AgentOrchestrator.LocalIpc.cs[540-578]
src/Capacitor.Cli.Daemon/Services/AgentOrchestrator.cs[3054-3099]
src/Capacitor.Cli.Daemon/Services/AgentOrchestrator.cs[3118-3125]
src/Capacitor.Cli.Daemon/Harness/Claude/ClaudeScreenWatcher.cs[15-16]
src/Capacitor.Cli.Daemon/Services/AnsiScreen.cs[39-49]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

Issue description
`AnsiScreen.Resize` allocates its cell buffer directly from dimensions that originate in a local terminal resize frame. `ushort` values can still produce an overflowing or multi-gigabyte `cols * rows` allocation, and the exception terminates the Claude output loop and finalizes its agent.

Fix Focus Areas
- src/Capacitor.Cli.Daemon/Services/AnsiScreen.cs[39-49]
- src/Capacitor.Cli.Daemon/Services/AgentOrchestrator.LocalIpc.cs[540-578]

Recommended Fix
Enforce sane maximum column, row, and total-cell limits before dimensions reach `AnsiScreen.Resize`; reject or clamp invalid local resize frames consistently with the real PTY limits. Also make `AnsiScreen.Resize` defensive by validating positive dimensions and using checked total-cell arithmetic before allocating, so any future caller cannot bypass the bound.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Checkbox dialogs receive stale answers ✓ Resolved
Description
ClaudeScreenWatcher.Observe replaces any newly parsed dialog with no options with the previous
selectable dialog when their headings match. If a checkbox dialog follows a select dialog with the
same heading, Chat offers the old choices and sends their arrow-and-Enter sequences to the checkbox
dialog instead of showing its screen-only fallback.
Code

src/Capacitor.Cli.Daemon/Harness/Claude/ClaudeScreenWatcher.cs[R25-26]

+        if (dialog is { Options.Count: 0 } && _dialog is { Options.Count: > 0 } && _dialog.Heading == dialog.Heading)
+            dialog = _dialog;
Relevance

●●● Strong

This is a concrete stale-state correctness bug undermining the PR’s documented checkbox fallback
behavior.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The detector intentionally returns no options for checkbox labels, but the watcher substitutes the
previous dialog solely on heading equality. Chat turns every nonempty option list into keys derived
from the published selected index.

src/Capacitor.Cli.Daemon/Harness/Claude/ClaudeTerminalDialogDetector.cs[52-65]
src/Capacitor.Cli.Daemon/Harness/Claude/ClaudeScreenWatcher.cs[19-28]
src/Capacitor.App/ViewModels/ChatTabViewModel.cs[729-746]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A stable, unreadable dialog with the same heading as a previous select dialog inherits the previous choices and can be answered with the wrong keys.

## Fix Focus Areas
- src/Capacitor.Cli.Daemon/Harness/Claude/ClaudeScreenWatcher.cs[19-27]
- src/Capacitor.Cli.Daemon/Harness/Claude/ClaudeTerminalDialogDetector.cs[39-65]

## Recommended Fix
Distinguish an incomplete cursor redraw from a complete but unsupported menu, and retain prior choices only for the incomplete redraw. Add a test that replaces a select dialog with a same-heading checkbox dialog.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Chat text reaches hidden dialogs ✓ Resolved
Description
ApplyTerminalMenu hides a detected dialog while HasPendingCards is true and also sets
HasTerminalMenu to false. While the pending card is displayed, that false value enables the
composer and send path, so a Chat message can be written into the still-active terminal dialog.
Code

src/Capacitor.App/ViewModels/ChatTabViewModel.cs[741]

+        HasTerminalMenu = question || shown;
Relevance

●●● Strong

Recent accepted precedent fixes pending-card suppression and state refresh issues in
ChatTabViewModel.

PR-#1087
PR-#889

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
A pending card makes shown false despite a nonnull dialog; HasTerminalMenu then becomes false.
Both the send-command gate and its post-upload check depend on that value, and terminal chat input
forwards accepted text to the PTY.

src/Capacitor.App/ViewModels/ChatTabViewModel.cs[703-706]
src/Capacitor.App/ViewModels/ChatTabViewModel.cs[740-746]
src/Capacitor.App/ViewModels/ChatTabViewModel.cs[552-559]
src/Capacitor.App/ViewModels/ChatTabViewModel.cs[589-601]
src/Capacitor.App/ViewModels/TerminalChatInput.cs[65-68]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Suppressing a terminal dialog behind a pending card also removes the composer gate, allowing ordinary text to reach that dialog.

## Fix Focus Areas
- src/Capacitor.App/ViewModels/ChatTabViewModel.cs[703-706]
- src/Capacitor.App/ViewModels/ChatTabViewModel.cs[740-746]
- src/Capacitor.App/ViewModels/ChatTabViewModel.cs[552-595]

## Recommended Fix
Separate whether the terminal card is shown from whether terminal input is blocked. Keep the composer and send path gated whenever a detected dialog remains active, including while a pending card takes precedence.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

4. Chat choices skip daemon coordination 📘 Rule violation ⌂ Architecture
Description
SendRawAsync sends menu-answer keys through client.SendInputAsync(keys) instead of the app's
DaemonMutationLane. The new terminal-dialog choice path calls this method, so those daemon writes
bypass the lane's shared ordering of mutations.
Code

src/Capacitor.App/ViewModels/TerminalTabViewModel.cs[223]

+            await client.SendInputAsync(keys);
Relevance

● Weak

Recent precedents reject routing existing direct permission mutations through DaemonMutationLane.

PR-#1055
PR-#770

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The checklist covers desktop protocol writes to the daemon. The new choice handler reaches a changed
direct input write, while the shared lane has a separate mutation entry point that this path does
not use.

Rule 2738493: Route all desktop daemon mutations through the single DaemonMutationLane abstraction
src/Capacitor.App/ViewModels/ChatTabViewModel.cs[758-762]
src/Capacitor.App/ViewModels/TerminalTabViewModel.cs[218-225]
src/Capacitor.App/Services/Mutation/DaemonMutationLane.cs[59-70]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Terminal-dialog answers write directly to the daemon instead of passing through the shared mutation lane.

## Fix Focus Areas
- src/Capacitor.App/ViewModels/TerminalTabViewModel.cs[218-225]
- src/Capacitor.App/ViewModels/ChatTabViewModel.cs[758-762]
- src/Capacitor.App/Services/Mutation/DaemonMutationLane.cs[59-70]

## Recommended Fix
Provide a lane-mediated path for terminal-menu input and use it when sending a choice. Preserve the existing attach-client checks and single-write escape sequences.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


Grey Divider

Context sources
✅ Compliance rules (platform): 64 rules
✅ Cross-repo context — repo relationships
Review mode: 🧠 Deep: This is a broad, behavior-heavy change spanning terminal parsing, PTY resizing, IPC contracts, daemon orchestration, UI state, input delivery, and multiple independent code paths with substantial potential for subtle defects.

Grey Divider

Tip of the day
💡 Did you know, you can keep summaries lean with Findings visible per group, which tucks the rest behind a View link

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread src/Capacitor.Cli.Daemon/Harness/Claude/ClaudeScreenWatcher.cs Outdated
Comment thread src/Capacitor.App/ViewModels/ChatTabViewModel.cs Outdated
Comment thread src/Capacitor.Cli.Daemon/Services/AnsiScreen.cs
@nortonandreev

Copy link
Copy Markdown
Contributor Author

SendRawAsync sends menu-answer keys through client.SendInputAsync(keys) instead of the app's DaemonMutationLane.

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.

@nortonandreev

Copy link
Copy Markdown
Contributor Author

The macOS failure is not from this change. Ubuntu and Windows passed the same commit.

a_failed_session_start_posts_the_next_work_capability_but_never_spools_it expected next_work "v1" and got "". The log shows the session-start post was spooled on HTTP 500 (session-start spooled, not sent … (HTTP 500)), so the assertion read a body that was never the successful post. That test is not in this diff. #1197 freezes the hook clock so a slow run does not take that retry path.

@nortonandreev
nortonandreev marked this pull request as draft September 28, 2026 12:59
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.
@nortonandreev
nortonandreev force-pushed the norton/ai-3233-chat-mcp-trust-prompt branch from e2adc09 to 80f5ae4 Compare October 1, 2026 12:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant