Repository navigation
fix(tui): forward pastes with bracketed-paste framing when the child enabled mode 2004 - #457
Merged
Merged
Conversation
…enabled mode 2004 Dragging an image into a Claude Code session running inside construct landed the image *path* as literal text instead of an `[image #N]` reference like the native Claude Code CLI produces. Root cause: the client received the drag correctly as a bracketed-paste event from the outer terminal, but forwarded it to the child PTY as raw bytes, dropping the `ESC[200~`/`ESC[201~` framing. Claude Code's drag-image detection (and its multiline-paste guard) only fire on a real bracketed paste, so the path was treated as typed keystrokes. The client already models each child's terminal via vt100, which tracks DEC mode 2004 (`screen.bracketed_paste()`) — it just never consulted it when forwarding a paste. Now `dispatch_paste_text` wraps the payload in the bracketed-paste markers a real terminal would send, but only when the target child currently has mode 2004 enabled (claude/codex/shell do; synth/smith sessions fall back to raw, preserving prior behavior). The closing marker is stripped from the payload first so an embedded `ESC[201~` can't end the paste early. Verified end-to-end against the real claude binary in a PTY: a bracketed-pasted image path renders as `[Image #1]`; the same path sent raw stays literal text. Adds spec 0034.
Merged
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.
Problem
Dragging an image into a Claude Code session running inside construct put the image path into the input as literal text, instead of the
[image #N]reference the native Claude Code CLI produces. (Reported behavior: native CLI →[image #1]; construct claude session → raw path.)Root cause
The construct client does receive the drag correctly as a bracketed-paste event from the outer terminal (
CtEvent::Paste). But when it forwards that to the child PTY,dispatch_paste_textsenttext.into_bytes()— raw, with noESC[200~/ESC[201~framing. Claude Code's drag-image detection (and its multiline-paste guard) only fire on a real bracketed paste, so the path arrived as ordinary typed keystrokes and stayed literal.The client already models each child terminal with vt100, which tracks DEC private mode 2004 (
Screen::bracketed_paste()). It just never consulted that flag when forwarding a paste — effectively a terminal-passthrough bug that bites images hardest.Fix
ItemHistory::bracketed_paste_enabled()— reads the live (cached) parser's mode 2004 state. TheESC[?2004htoggle is a CSI sequence, so it already flows throughfeed_byteinto the parser for the interactive harnesses (claude/codex/shell).dispatch_paste_textnow routes throughencode_paste_for_pty, which wraps the payload inESC[200~…ESC[201~only when the target child currently has mode 2004 enabled. Synth/smith sessions with no live parser fall back to raw forwarding (prior behavior).ESC[201~can't terminate the paste early (paste-injection guard, as real terminals do).This is general terminal fidelity, not an image special-case: multiline and shell pastes into a mode-2004 child are now framed too (no premature submit/execute).
Verification
Validated the full chain against the real
claudebinary in a PTY (not just unit tests):ESC[?2004hon startup (byte 19) → construct tracks it.[Image #1]./tmp/...pngtext.(2) and (3) reproduce the exact reported discrepancy and confirm the fix closes it.
Tests:
pty_render::tests::tracks_child_bracketed_paste_mode—ESC[?2004h/ltoggles the tracked state.app::tests::paste_wraps_in_bracketed_markers_only_when_child_enables_mode_2004— wraps only when mode 2004 is on; strips embedded end-marker.agentd-clisuite green (275 + reconnect).Adds spec
0034-forwarded-pastes-honor-child-bracketed-paste-mode.Binaries
Code lives entirely in
crates/cli→ relevant binary isconstruct:/Users/moon/agentd/.claude/worktrees/bracketed-paste-passthrough/target/debug/construct🤖 Generated with Claude Code