Filter terminal reply traffic around tmux attach and detach#588
Merged
asheshgoplani merged 1 commit intoasheshgoplani:mainfrom Apr 17, 2026
Merged
Conversation
The attached-session path can leak terminal reply bytes back into Agent Deck's
Bubble Tea UI during rapid attach/detach cycles. In practice this showed up as
literal fragments such as `(0.44.0)/d3d3/f5f5/d3d3/f5f5(0.44.0)...` appearing
in the TUI after repeating:
- attach to a tmux-backed session
- detach with `Ctrl+Q`
- reattach and press `Enter` a few times
Relevant environment from the repro:
- Agent Deck running inside tmux
- Bubble Tea UI on the host side
- terminal-emulator replies arriving on stdin during redraw / teardown
- the visible reply fragments included terminal version and color-report text
The underlying problem is that terminal protocol replies are not user input, but
we were still letting them cross the attach/detach boundary. The fix here keeps
that handling bounded to those lifecycle edges and treats the problem from first
principles:
- add a small stateful terminal-reply filter that understands protocol classes
instead of matching terminal-specific payload strings
- discard escape-string replies generically (OSC, DCS, APC, PM, SOS)
- discard non-keyboard CSI replies during the short quarantine window
- preserve normal keyboard input, including CSI/SS3 key sequences such as
arrows, Home/End, Backtab, and CSI-u key events
- reuse the same filter in both the tmux attach path and the keyboard
compatibility reader so split replies are handled consistently across reads
This intentionally avoids keying behavior to a specific terminal emulator,
terminal version, or tmux version. The parser is based on control-sequence
structure, not on reply payload contents.
Constraint: normal keyboard input must survive immediately after attach/detach,
including CSI/SS3-based keys
Rejected alternatives:
- match terminal-specific payload strings
- too brittle against emulator or multiplexer version changes
- drop all CSI traffic during the quarantine window
- would break legitimate keyboard input
- keep extending PTY drain timeouts alone
- the failing bytes were arriving on stdin as protocol replies, not just on
PTY output
Tested:
- `nix shell nixpkgs#go nixpkgs#gcc -c go test ./internal/tmux ./internal/ui ./internal/termreply -run 'TestCleanupAttach_|TestCSIuReader(DropsTerminalRepliesDuringQuarantine|DropsSplitTerminalRepliesDuringQuarantine|PreservesNormalInputDuringQuarantine)|TestFilter'`
Not tested:
- a fresh packaged build exercised manually through repeated `Ctrl+Q` / `Enter`
cycles after this exact commit
This was referenced Apr 16, 2026
7 tasks
asheshgoplani
added a commit
that referenced
this pull request
Apr 17, 2026
Patch release shipping PR #588 (protocol-aware terminal reply filter) which closes #597, #585, and #586 — all symptoms of DA1/DA2 device attribute responses leaking into the input buffer during tmux attach/ detach on WSL, WezTerm, Ghostty, and similar terminals. The fix is protocol-aware (understands OSC/DCS/APC/PM/SOS/CSI byte structure) rather than time-based, so normal keyboard input is preserved during the quarantine window — no lost keystrokes. Committed by Ashesh Goplani
Clarity-89
added a commit
to Clarity-89/agent-deck
that referenced
this pull request
Apr 17, 2026
Upstream's flushDetachInput in internal/tmux/pty.go (introduced by PR asheshgoplani#588 / commit 119c55d) calls unix.IoctlSetInt with unix.TCFLSH, which only exists on Linux. The build broke on darwin as of v1.7.4. Split the function into pty_flush_linux.go (TCFLSH + TCIFLUSH) and pty_flush_darwin.go (TIOCFLUSH + FREAD) — semantically equivalent flush-input ioctls on each platform. FREAD isn't re-exported by golang.org/x/sys/unix on darwin, so it's defined locally as 0x1 (stable value from <sys/fcntl.h>).
Clarity-89
added a commit
to Clarity-89/agent-deck
that referenced
this pull request
Apr 17, 2026
Upstream's flushDetachInput in internal/tmux/pty.go (introduced by PR asheshgoplani#588 / commit 119c55d) calls unix.IoctlSetInt with unix.TCFLSH, which only exists on Linux. The build broke on darwin as of v1.7.4. Split the function into pty_flush_linux.go (TCFLSH + TCIFLUSH) and pty_flush_darwin.go (TIOCFLUSH + FREAD) — semantically equivalent flush-input ioctls on each platform. FREAD isn't re-exported by golang.org/x/sys/unix on darwin, so it's defined locally as 0x1 (stable value from <sys/fcntl.h>).
4 tasks
This was referenced Apr 17, 2026
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.
The attached-session path can leak terminal reply bytes back into Agent Deck's
Bubble Tea UI during rapid attach/detach cycles. In practice this showed up as
literal fragments such as
(0.44.0)/d3d3/f5f5/d3d3/f5f5(0.44.0)...appearingin the TUI after repeating:
Ctrl+QEntera few timesRelevant environment from the repro:
The underlying problem is that terminal protocol replies are not user input, but
we were still letting them cross the attach/detach boundary. The fix here keeps
that handling bounded to those lifecycle edges and treats the problem from first
principles:
instead of matching terminal-specific payload strings
arrows, Home/End, Backtab, and CSI-u key events
compatibility reader so split replies are handled consistently across reads
This intentionally avoids keying behavior to a specific terminal emulator,
terminal version, or tmux version. The parser is based on control-sequence
structure, not on reply payload contents.
Constraint: normal keyboard input must survive immediately after attach/detach,
including CSI/SS3-based keys
Rejected alternatives:
PTY output
Tested:
nix shell nixpkgs#go nixpkgs#gcc -c go test ./internal/tmux ./internal/ui ./internal/termreply -run 'TestCleanupAttach_|TestCSIuReader(DropsTerminalRepliesDuringQuarantine|DropsSplitTerminalRepliesDuringQuarantine|PreservesNormalInputDuringQuarantine)|TestFilter'Not tested:
Ctrl+Q/Entercycles after this exact commit