fix: forward Ctrl+V to PTY for non-text clipboard paste#18
Conversation
There was a problem hiding this comment.
Pull request overview
This PR aims to improve client terminal input handling by forwarding Ctrl+V to the PTY when the clipboard paste contains no text/plain (enabling non-text clipboard flows for TUIs), while also updating docs/ADRs and speeding up tests by replacing fixed sleeps with polling.
Changes:
- Add a capture-phase
pastehandler in the browser client to send\x16to the PTY when the clipboard has notext/plain. - Add ADR 014 (image/non-text paste) and ADR 013 (cursor style/DECSCUSR) plus client spec updates.
- Replace fixed
Bun.sleep(...)waits in tests withwaitForPrompt/waitForContent/waitForDatapolling helpers; force/bin/shto reduce startup time.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/client/index.ts | Adds paste interception + introduces cursor-style config wiring and DECSCUSR hook call. |
| src/server/websocket.test.ts | Replaces fixed sleeps with prompt/content polling and forces /bin/sh for faster tests. |
| src/pty/index.test.ts | Replaces fixed sleeps with polling helper and forces /bin/sh. |
| docs/specs/client.md | Updates client spec for new config keys and documents new features as done. |
| docs/adrs/014.client.image-paste.md | New ADR documenting the non-text paste issue and workaround/upstream fix. |
| docs/adrs/013.client.cursor-style.md | New ADR documenting DECSCUSR cursor-shape workaround and upstream path. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
jesse23
left a comment
There was a problem hiding this comment.
Thank you for the review. Addressed all 5 comments:
Fixed in ceb204f:
-
cursor.tsmissing /applyDecscusrimport broken (comments onsrc/client/index.ts:3anddocs/adrs/013.client.cursor-style.md:20):src/client/cursor.tswas accidentally deleted bygit clean -fdduring branch history rebuild. Restored frome576532on main. Build passes cleanly. -
waitForData(received, '$')fragile on root (comment onsrc/pty/index.test.ts): Replaced with a sentinel — test now writesecho __ready__first and waits for__ready__in output. Deterministic regardless of$vs#prompt.
Not a regression from this PR:
cursorStyle/cursorStyleBlinkmissing from/api/config(comments onsrc/client/index.ts:52anddocs/specs/client.md:59): Both keys are already returned byGET /api/config— they were added ine576532on main (src/server/routes.ts). This PR does not touch the config endpoint. The spec accurately reflects the current server implementation.
ghostty-web swallows Ctrl+V keydown without sending \x16 to the PTY. When clipboard contains no text/plain, also silently drops the paste event. TUI apps (e.g. opencode) read images via native OS clipboard API on Ctrl+V. Intercept via capture-phase paste listener: when no text/plain in clipboard, block ghostty-web's handler and send \x16 to PTY directly — matching xterm.js behaviour that makes ttyd work. See ADR 014. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Bun.sleep(800/2500) in PTY and WebSocket tests caused 7s+ of unnecessary wait time. Replace with waitForData/waitForPrompt/waitForContent helpers that poll on actual shell output. Also use /bin/sh instead of $SHELL to avoid zsh/oh-my-zsh 2s startup cost per test. Suite: 21s -> 2.8s. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…el for prompt detection git clean -fd during branch rebuild removed src/client/cursor.ts which was committed on main (e576532). Restore it. Also replace waitForData(received, '$') prompt detection with a sentinel echo to be robust on root shells where the prompt is '#' not '$'. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…hostty-web" in ADRs
ceb204f to
d71be20
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary
\x16to the PTY (unlike xterm.js). When clipboard has notext/plain, its paste handler also silently drops the event. TUI apps like opencode detect Ctrl+V from the PTY to trigger their native OS clipboard read (osascript/powershell/wl-paste). Fix: capture-phase paste listener sends\x16to PTY when clipboard has no text — matching the xterm.js behaviour that makes ttyd work.InputHandler.handleKeyDown).Bun.sleep(800/2500)fixed waits withwaitForPrompt/waitForContentpolling helpers; uses/bin/shinstead of user's shell to avoid zsh startup cost.Commits
fix: forward Ctrl+V to PTY for non-text clipboard paste—src/client/index.ts+ ADR 014 + specdocs: add upstream contribution section to DECSCUSR ADR— how to fix ghostty-web for cursor styletest: replace fixed sleeps with prompt/content polling— test suite speedupGhostty-web upstream
The root cause in ghostty-web is
InputHandler.handleKeyDownreturning early on Ctrl+V without emitting\x16toonDataCallback. ADR 014 documents the exact one-function fix and contribution checklist forcoder/ghostty-web.