fix(host-service): send follow-up Enter as a separate delayed write so terminals send submits reliably

Merged
KI
3mo ago
+287-21

Summary

Fixes #6243: superset terminals send to a busy/laggy Claude Code session typed the text into the agent's input box but left it as an unsubmitted draft, while the CLI reported submitted: true. Multi-line text (bracketed paste) was the biggest trigger.

Cause: writeFramedInputToSession bundled the submit Enter into the same PTY write as the pasted text (\x1b[200~text\x1b[201~\r). TUI agents aggregate bytes that arrive together into one paste burst, so on a slow session the trailing \r gets folded into the draft instead of acting as a keypress.

Fix: write the framed text first, then the Enter as its own write FOLLOW_UP_ENTER_DELAY_MS (500ms) later — the same class of fix as #6026's INITIAL_COMMAND_ENTER_DELAY_MS for initial commands. In its own read, a \r can only be an Enter keypress. If the session exits during the gap, the send now returns an error instead of pretending. --no-submit and bare-Enter (empty text) behavior unchanged. All callers (CLI, MCP tool, SDK) inherit the fix through the terminal.send mutation.

Tests

  • New node test "submit Enter is a separate write, delayed past the paste burst" in terminal.send-snapshot.node-test.ts — uses canonical-mode cat > file line buffering as the oracle for whether the Enter has been written. Verified it fails against the old bundled write (delay mutated to 0 → fail) and passes with the fix.
  • Full send/snapshot suite green: 13/13 under Electron-as-Node.

E2E verification (dev desktop + real CLI + live Claude Code, driven over CDP)

  • Multi-line idle send → submitted, answered.
  • Multi-line send into a busy mid-turn session → queued, auto-submitted after the turn, answered.
  • Single-line, 8KB payload, and boot-race sends → all submit.

Known limitation (unchanged by this PR, tracked in #6243's remaining asks): if the agent process is dead or suspended, bytes go to whatever owns the pty and submitted: true still only means "bytes written" — programmatic submission verification is a follow-up.


Summary by cubic

Reliably submit text in host-service by sending Enter as a separate delayed write, serializing follow-up sends per session, and deduping in-flight adoptions so concurrent sends share one session. Fixes #6243 where multi-line sends could stay as drafts while the CLI reported submitted.

  • Bug Fixes
    • In writeFramedInputToSession, write framed text first, then send \r after 500ms (FOLLOW_UP_ENTER_DELAY_MS) when submit: true, so TUIs treat it as a keypress.
    • Return an error if the session exits during the delay; --no-submit and empty-text behavior are unchanged.
    • Serialize follow-up sends per session so text + Enter are atomic; a draft cannot ride another send’s Enter.
    • Dedupe in-flight headless adoptions in getOrAdoptSession so racing sends after a restart share one TerminalSession and respect send serialization.

Summary by CodeRabbit

  • Bug Fixes
    • Improved terminal command submission by separating text input from the Enter key.
    • Added a brief delay before submitting commands to ensure terminal input is processed reliably.
    • Non-submitting terminal writes remain immediate.
    • Improved handling of concurrent terminal actions to preserve command order and prevent staged text from being submitted unexpectedly.
    • Added safeguards to ensure terminal actions are sent only while the session remains active.