fix(web): block DECRQM/DECRQSS replies and focus/mouse event leaks in xterm.js#277
Merged
Conversation
… xterm.js xterm.js@5.3.0 auto-replies to several additional terminal capability probes through Terminal.onData, and the web bridge forwards every onData byte to the PTY. Building on #271, this closes the remaining leak sources that broke Claude Code's TUI: - CSI $ p / CSI ? $ p (DECRQM) — xterm.js always replies via requestMode. Ink emits CSI ?2026$p (synchronized-output probe) at startup; the reply was rendered as junk inside Claude Code's prompt. - DCS $ q ... ST (DECRQSS) — xterm.js always replies via requestStatusString. - CSI ?1004 h (focus reporting) — once asserted by Claude Code, every DOM focus/blur pumped ^[[I / ^[[O into the PTY. This was the root cause of "asd" rendering on the wrong row below the plan banner and of the plan-approval menu failing to consume arrow keys. - CSI ?1000/1002/1003/1006/1015/1016 h (mouse tracking) — every mouse event pumped coordinate bytes into the PTY, scrambling Ink's frame buffer (visible as the ─ divider bleeding across the typing line). Implementation uses Terminal.parser.registerCsiHandler / registerDcsHandler. The CSI ? h / CSI ? l handler is selective: returns true only for the seven suppressed mouse/focus modes and false for every other parameter, so 25 (cursor), 1007 (alt scroll), 1049 (alt screen), 2004 (bracketed paste), and 2026 (synchronized output) keep reaching xterm.js's built-in setters unchanged. Also added as defense-in-depth: CSI > q (XTVERSION, future-proofs the xterm.js bump), CSI t (window manipulation, gated by windowOptions today), DCS + q (XTGETTCAP). Fixes #273. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Chrome DevTools Issues panel flags the unlabelled <input type='checkbox'>
in the task panel ('A form field element should have an id or name
attribute'). Add 'task-panel-show-system' as both id and name so the
control becomes addressable from form-submission semantics and screen
readers; wire 'htmlFor' on the surrounding label so the click region
stays correct.
Picked from the closed PR #275 (which mis-diagnosed issue #273 as a font
loading race). The probe-leak suppressor in commit efe6671 is the real
fix for #273; this commit only carries the genuinely useful checkbox
hygiene cleanup. terminal-image-paths.ts hunk is a formatter auto-fix
applied by 'bun run lint'.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Member
Author
AI Session BackupCommit: 50a3b96
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #273.
Problem
Claude Code's TUI in the web terminal exhibited three visible symptoms:
asdbut it appeared below the plan-mode banner instead of inside the prompt area.Yes, and bypass permissions…Tell Claude what to change) but cannot navigate or confirm.─divider bleeds across the typing line, producing a strikethrough-like artifact through user input.Root cause
xterm.js@5.3.0 auto-answers several terminal capability probes by emitting reply bytes through `Terminal.onData`. Our web bridge forwards every `onData` byte to the PTY as if the user had typed it. After #271 closed OSC color queries and DA/DSR/CPR replies, four leak channels remained:
The focus-reporting leak is the direct cause of symptoms (1) and (2): every browser focus/blur (and the tiny one that happens whenever the user clicks into the terminal) injects `^[[I` / `^[[O` into Ink's input stream, which misroutes keystrokes through the alt-key parser and shifts the cursor. The mouse-tracking leak corrupts Ink's frame buffer (symptom 3).
Fix
Extend `packages/app/src/web/terminal-query-suppression.ts` to register additional parser hooks immediately after constructing the `Terminal`:
Why these modes and not others
Verification
```
bun x vitest run tests/docker-git/terminal-query-suppression.test.ts
Test Files 1 passed (1)
Tests 15 passed (15)
bun run typecheck # clean (exit 0)
vibecode-linter src/web/terminal-query-suppression.ts ... # 0 errors, 0 warnings, 0 duplicates
eslint --config eslint.effect-ts-check.config.mjs ... # clean (exit 0)
```
New tests cover:
Files changed
🤖 Generated with Claude Code