fix: bracket multi-line terminal pastes so pasted code isn't treated as Enter#1013
Open
SmolSmolStar wants to merge 1 commit into
Open
fix: bracket multi-line terminal pastes so pasted code isn't treated as Enter#1013SmolSmolStar wants to merge 1 commit into
SmolSmolStar wants to merge 1 commit into
Conversation
…as Enter Pasting multi-line text into a terminal sent the raw string (newlines included) straight to the PTY. With no bracketed-paste wrapping, each newline is read as an Enter keypress, so multi-line code submits line-by-line / early instead of landing as one block. This hit both the worktree terminals and the Commander terminal. - client/terminal.js: route paste through a new pasteTextToTerminal() helper that uses xterm's terminal.paste(). paste() normalizes newlines and, when the running program has bracketed-paste mode enabled (it sent ESC[?2004h), wraps the text in ESC[200~ .. ESC[201~ so it's treated as literal pasted input. It flows through terminal.onData (already forwarding to sendTerminalInput), and updateInputBuffer ignores ESC-prefixed data so autosuggestions aren't polluted. Falls back to a raw send if the xterm instance is unavailable. Image paste is unchanged. - client/commander-panel.js: the Commander paste handler bypasses xterm.onData (to keep paste out of slash-command capture), so it brackets inline via a small bracketPastedText() helper using terminal.modes.bracketedPasteMode. - Programs that don't enable bracketed-paste mode still receive the text unwrapped, so nothing regresses for them. Tests: extend tests/e2e/commander-paste.spec.js with a multi-line case asserting the POST body is bracketed when mode is on (the existing single-line/mode-off case still asserts a raw body). The bracketing mechanism (xterm.paste + terminal.modes) was verified in a headless browser. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Summary
Pasting multi-line code into a terminal (e.g. a SQL block or a snippet from chat) misbehaves: the paste is sent to the PTY as a raw string, so every newline is read as an Enter keypress. The result is code that submits line-by-line or early instead of landing as one clean block. This affects both the worktree terminals and the Commander terminal.
Root cause
The paste handlers send the clipboard text straight through (
sendTerminalInput/sendInput) with no bracketed-paste wrapping. Bracketed paste (ESC[200~…ESC[201~) is the mechanism that tells a program "this is pasted text — treat the newlines as literal input, don't act on them." Without it, multi-line pastes are indistinguishable from a burst of typed Enters.Change
client/terminal.js(worktree terminals): the three raw-send sites now route through a newpasteTextToTerminal()helper that calls xterm's ownterminal.paste(). That normalizes newlines and, only when the running program has bracketed-paste mode enabled (it sentESC[?2004h), wraps the text inESC[200~ … ESC[201~. It flows throughterminal.onData(which already forwards tosendTerminalInputand marks the session active), andupdateInputBufferignoresESC-prefixed data so autosuggestions aren't polluted. Falls back to a raw send if the xterm instance is unavailable. Image paste is untouched.client/commander-panel.js(Commander terminal): its paste handler intentionally bypassesxterm.onData(to keep pastes out of slash-command capture), so it brackets inline via a smallbracketPastedText()helper that readsterminal.modes.bracketedPasteMode.Test plan
tests/e2e/commander-paste.spec.jswith a multi-line case: with bracketed-paste mode enabled, thePOST /api/commander/inputbody must beESC[200~line one\rline two ESC[201~. The existing single-line / mode-off case still asserts a raw body (guards against regressions).terminal.paste()bracketing +terminal.modes.bracketedPasteModereflectingESC[?2004h) was verified in a headless browser against xterm 5.3.0.VAR=valueenv-prefix syntax that cmd.exe rejects, and therun-e2e-safe.jsrunner spawnsnpxwhich doesn't resolve under Git Bash). The tests are discovered byplaywright --listand will run in CI on Linux.🤖 Generated with Claude Code