Repository navigation
fix(tui): patch StdinParser to prevent garbled text from fragmented mouse sequences - #19520
Closed
agutmanstein-scale wants to merge 1 commit into
Closed
agutmanstein-scale wants to merge 1 commit into
agutmanstein-scale wants to merge 1 commit into
Conversation
…ouse sequences When SGR mouse escape sequences arrive fragmented across multiple stdin chunks (due to event loop pressure from LLM streaming + TUI rendering), opentui's StdinParser timeout fires mid-sequence and leaks individual bytes as KEY events, inserting garbled characters into the input box. Three timeout paths in the parser could trigger this: 1. esc_recovery timeout: emitted '[' as a KEY event via emitKeyOrResponse. Fixed to use emitOpaqueResponse (dropped) and set justFlushedEscBracket flag so subsequent '<' routes to mouse handling. 2. CSI timeout: dropped '\x1b[' correctly but lost recovery context. Fixed to set justFlushedEscBracket so '<' arriving in ground state routes to esc_less_mouse. 3. esc_less_mouse timeout: had no deferred mechanism — flushed accumulated bytes and returned to ground, causing remaining bytes to leak as KEY events. Fixed to clear forceFlush and wait for more bytes, matching the csi_sgr_mouse_deferred pattern. Also increases DEFAULT_TIMEOUT_MS from 10 to 25ms (matches kitty/alacritty defaults) for defense-in-depth. Includes test-stdin-parser.mjs (parser unit test) and frag-pty.py (PTY reproducer with 12ms byte-by-byte delay). Verified end-to-end: frag-pty.py no longer produces garbled text. Fixes anomalyco#3199 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This was referenced Mar 30, 2026
agutmanstein-scale
added a commit
to agutmanstein-scale/opencode
that referenced
this pull request
Apr 1, 2026
…ragmented input Two bugs cause SGR mouse escape sequences to appear as garbled text: 1. **Post-exit garbling** (new fix): cleanupBeforeDestroy() calls setRawMode(false) before mouse tracking is disabled, creating a window where mouse events echo as raw bytes. Fixed by adding disableMouse() + stdin drain before setRawMode(false), matching the correct ordering already used in suspend(). 2. **In-session garbling** (ported from anomalyco#19520): StdinParser timeout fires mid-mouse-sequence during heavy event loop pressure, leaking individual bytes as KEY events. Fixed by patching three timeout paths with recovery flags and deferred processing. Also bumps DEFAULT_TIMEOUT_MS from 20 to 25ms for defense-in-depth. Patch targets @opentui/core@0.1.95 (current dev dependency). Upstream fix: anomalyco/opentui#905 Closes anomalyco#20458 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
3 of 6 tasks
18vijayb
pushed a commit
to 18vijayb/opencode
that referenced
this pull request
Apr 2, 2026
…ragmented input Two bugs cause SGR mouse escape sequences to appear as garbled text: 1. **Post-exit garbling** (new fix): cleanupBeforeDestroy() calls setRawMode(false) before mouse tracking is disabled, creating a window where mouse events echo as raw bytes. Fixed by adding disableMouse() + stdin drain before setRawMode(false), matching the correct ordering already used in suspend(). 2. **In-session garbling** (ported from anomalyco#19520): StdinParser timeout fires mid-mouse-sequence during heavy event loop pressure, leaking individual bytes as KEY events. Fixed by patching three timeout paths with recovery flags and deferred processing. Also bumps DEFAULT_TIMEOUT_MS from 20 to 25ms for defense-in-depth. Patch targets @opentui/core@0.1.95 (current dev dependency). Upstream fix: anomalyco/opentui#905 Closes anomalyco#20458 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
agutmanstein-scale
added a commit
to agutmanstein-scale/opencode
that referenced
this pull request
Apr 2, 2026
…ragmented input Two bugs cause SGR mouse escape sequences to appear as garbled text: 1. **Post-exit garbling** (new fix): cleanupBeforeDestroy() calls setRawMode(false) before mouse tracking is disabled, creating a window where mouse events echo as raw bytes. Fixed by adding disableMouse() + stdin drain before setRawMode(false), matching the correct ordering already used in suspend(). 2. **In-session garbling** (ported from anomalyco#19520): StdinParser timeout fires mid-mouse-sequence during heavy event loop pressure, leaking individual bytes as KEY events. Fixed by patching three timeout paths with recovery flags and deferred processing. Also bumps DEFAULT_TIMEOUT_MS from 20 to 25ms for defense-in-depth. Patch targets @opentui/core@0.1.95 (current dev dependency). Upstream fix: anomalyco/opentui#905 Closes anomalyco#20458 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Collaborator
|
Automated PR Cleanup Thank you for contributing to opencode. Due to the high volume of PRs from users and AI agents, we periodically close older PRs using automated criteria so maintainers can focus review time on the most active and community-supported contributions. This PR was closed because it matched the following cleanup criteria:
PRs created within the last month are not affected by this cleanup. If you believe this PR was closed incorrectly, or if you are still actively working on it, please leave a comment explaining why it should be reopened. A maintainer can review and reopen it if appropriate. Thanks again for taking the time to contribute. |
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.
Issue for this PR
Closes #3199
Type of change
What does this PR do?
When the event loop is busy (LLM streaming + 60fps rendering), the StdinParser's timeout fires mid-mouse-sequence, leaking individual bytes as KEY events that appear as garbled text in the input box.
Three timeout paths could trigger this. This PR patches all three via
patchedDependenciesfor@opentui/core@0.1.90:esc_recoverytimeout: was emitting[as a KEY event. Changed toemitOpaqueResponse+ set ajustFlushedEscBracketrecovery flag so<still routes to mouse handling.csitimeout: dropped\x1b[but lost context. Now also sets the recovery flag.esc_less_mousetimeout: had no deferred mechanism — flushed mid-sequence and leaked remaining bytes. Now waits for more bytes instead of flushing, matching the existingcsi_sgr_mouse_deferredpattern.Also bumps
DEFAULT_TIMEOUT_MSfrom 10 to 25ms (matches kitty/alacritty defaults).How did you verify your code works?
packages/opencode/test/cli/tui/test-stdin-parser.mjs— unit test confirming the 3-chunk fragmentation case is fixedpackages/opencode/test/cli/tui/frag-pty.py— PTY wrapper that fragments every mouse event byte-by-byte with 12ms delays. Ran in a VS Code web terminal (code-server), scrolled and clicked with the fix — zero garbled text. Without the fix — consistent garbling.Screenshots / recordings
Not a UI change — stdin parser fix verified via included test files.
https://github.com/user-attachments/assets/5ab9955f-a55d-40c9-bd6e-30db554aa827
https://github.com/user-attachments/assets/3dd588b9-30f0-43f4-90ad-e59f6abc6b2d
Checklist