Skip to content

feat: answer terminal capability queries (OSC 10/11, DSR)#163

Merged
ThomasK33 merged 1 commit into
mainfrom
feat/terminal-query-responder
Jun 22, 2026
Merged

feat: answer terminal capability queries (OSC 10/11, DSR)#163
ThomasK33 merged 1 commit into
mainfrom
feat/terminal-query-responder

Conversation

@ThomasK33

Copy link
Copy Markdown
Member

Problem

agent-tty owns the PTY master and is the terminal that programs in a session talk to, but it never replied to the terminal-capability queries programs emit at startup. So TUIs like Neovim 0.12+ time out probing for the background color and print:

E1568: Terminal did not respond to DSR request for 'background' color. Startup may be slower. :help 'ttyfast'

That warning then lands in the very PNG/WebM captures agent-tty exists to produce. (Reported while using agent-tty with Neovim.)

Fix

Add a small, stateful VT scanner — src/pty/terminalQueryResponder.ts — that answers the handful of startup probes that matter and wire it into the host's live pty.onData loop, writing replies back to the child:

  • OSC 11 (background color) → replies with the render profile's background
  • OSC 10 (foreground color) → replies with the foreground
  • DSR ESC[5n (status) → replies ESC[0n (the sentinel programs use to learn the terminal answers queries at all)

Details:

  • The scanner is a state machine (not a regex) so a query split across PTY read boundaries is still answered, and it has a fast-path that skips the per-character scan for the (overwhelmingly common) chunks with no ESC byte.
  • Advertised colors mirror the default render profile, so a program's light/dark choice matches a default-profile capture. The probe is answered once at startup, before any capture profile is known.
  • Replies are written as child input and are not appended to the event log, so snapshots/screenshots/recordings are unaffected. The reply write runs after queuing output ingestion, so the canonical output path is never gated on it.
  • Lives in the host's live loop, not a renderer backend — the renderers are offline event-log replay consumers and never participate in the live PTY conversation.

Testing

  • Unit (test/unit/pty/terminalQueryResponder.test.ts): OSC 10/11 with BEL & ST terminators, the OSC 11 + DSR startup handshake, split-across-chunk queries, embedded/multiple queries, non-query inputs (SGR, title sets, color sets, DA1, CPR), recovery after aborted sequences and after an 8-bit C1 ST, rgb conversion, constructor validation.
  • Integration (test/integration/terminal-query-responder.test.ts): a child sets raw mode, emits the OSC 11 query, and reports what it received on stdin — proving the full loop (child query → host reply → child stdin).
  • typecheck ✓, lint ✓, full unit suite ✓, full integration suite ✓.
  • Verified against real nvim --clean v0.12.3 via the agent-tty CLI: with the responder the warning is gone; disabling it reproduces the exact E1568 line.

🤖 Generated with Claude Code

agent-tty owns the PTY master but never replied to the terminal-capability
queries programs emit at startup, so TUIs like Neovim 0.12+ timed out and
printed "E1568: Terminal did not respond to DSR request for 'background'
color" into the captured output.

Add a stateful VT scanner (src/pty/terminalQueryResponder.ts) that answers the
common startup probes — OSC 11 (background) and OSC 10 (foreground) color
queries, plus the DSR sentinel ESC[5n — and wire it into the host's live PTY
read loop, writing replies back to the child. The advertised colors mirror the
default render profile so a program's light/dark choice matches a
default-profile capture. Replies are written as child input only and are not
appended to the event log, so snapshots and recordings are unaffected.

Covered by unit tests (split-chunk handling, BEL/ST terminators, non-query
inputs, C1 ST recovery) and an end-to-end integration test that confirms a
child receives the reply on stdin. Verified against real nvim 0.12.3: E1568 is
gone.

Change-Id: Ib647e0c33003711108f73d9bd33491227f380d7b
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Thomas Kosiewski <tk@coder.com>
@ThomasK33 ThomasK33 force-pushed the feat/terminal-query-responder branch from 16aa4e2 to ff3cdaa Compare June 22, 2026 16:48
@ThomasK33 ThomasK33 added this pull request to the merge queue Jun 22, 2026
Merged via the queue into main with commit fcf1d78 Jun 22, 2026
12 checks passed
@ThomasK33 ThomasK33 deleted the feat/terminal-query-responder branch June 22, 2026 16:58
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