fix(terminal): restore copying from Claude Code’s fullscreen TUI - #9949
fix(terminal): restore copying from Claude Code’s fullscreen TUI#9949callmemorgan wants to merge 16 commits into
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — The change spans shared terminal infrastructure plus web, desktop, and mobile clipboard, pointer, and input behavior, creating a broad production blast radius beyond a self-contained fix. It also adds a line-level lint suppression in the shared clipboard parser, warranting human review. You can add or adjust custom eligibility rules. Learn more. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8fba6168d8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 69ae8f4a91
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2bf45b6852
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f34fad32e4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit f34fad3. Configure here.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 09986610de
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Addressed the current findings from a separate Sonnet review in ec4f980:
168 focused web/core tests and the web typecheck pass. The six captured provider startup regressions also pass again; these check selection, redraw, copying, and subsequent input, not full model turns. I rechecked the review's HTTP fallback claims against the current helper in Chrome and Playwright WebKit. Both copied exact text and cleared the native macOS clipboard from a button click without a DOM selection. System-message parsing and combined Native iOS verification is now building on the Neo with two build jobs and one simulator. No simulator pass is claimed yet. Written by GPT-6 Astra in T3 Code on Morgan's behalf. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ec4f980f22
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Pushed 4f20dde and 81e2610. Fable 5.1’s simplification consolidates the web/mobile clipboard lifecycle and moves parser/session tests beside the shared implementation. The follow-up fixes isolate failing stream observers, free selection-coordinate allocations on failure, preserve focus acquired during terminal setup, and complete application mouse release on capture loss. Native iOS testing found that AppState focus/blur subscriptions are Android-only. Those subscriptions are now conditional. On the Neo’s iPhone 17e simulator running iOS 26.5, the terminal opened without the previous error overlay. Live PTY output through the isolated T3 server copied exact Unicode text and cleared the native iOS clipboard. Background output and history replay after leaving/reopening the terminal did not change it; fresh copying worked after returning. All 180 focused tests, web/mobile/shared-runtime typechecks, and six provider startup-capture regressions passed. Targeted lint reported no errors. The provider checks cover selection, redraw, copying, and subsequent input, not full model turns. Android was not run in an emulator. The simulator, stream, Metro, and isolated backend are shut down again. Written by GPT-6 Astra in T3 Code on Morgan’s behalf. |
Keep native selection through output redraws and Shift release, including the final pointer position. Track drag ownership separately from the selected range and stop autoscroll on release, cancellation, capture loss and deactivation. Retire completed selections when typing, pasting or other committed input resumes, so a later Ctrl+C can interrupt. Preserve copy gestures, modifiers and terminal protocol replies. Prevent older copy completions from clearing a newer selection. Verified with focused tests using the real Ghostty core and a desktop check on the MacBook Neo. 🤖 Generated with [T3 Code](https://t3.codes) Co-Authored-By: GPT-6 Astra <noreply@openai.com>
Observe bounded OSC 52 writes in the shared desktop/web terminal. Keep stream framing separate from payload retention and copy eligibility, including chunked escapes, wrapped payloads and control-string exits. Never replay historical copies; revoke pending copies on focus or visibility loss while retaining parser framing. Use the Clipboard API without stealing focus or inserting denial errors into a fullscreen application. Clipboard queries remain unsupported. Verified 128 focused tests, web typecheck and the macOS clipboard in the isolated desktop client on the MacBook Neo. 🤖 Generated with [T3 Code](https://t3.codes) Co-Authored-By: GPT-6 Astra <noreply@openai.com>
Preserve a leading U+FEFF when decoding clipboard text, including a payload containing only that character. Serialize OSC clipboard writes across terminal instances and retain only the newest pending copy. Recheck its terminal generation and focus before writing, so a delayed request cannot survive blur, hiding, reset or disposal. Consume clipboard denial without blocking subsequent copies or writing errors to the TUI. Verified regression failures against the previous writer, 138 focused tests, web typecheck and targeted lint (existing React warnings only). 🤖 Generated with [T3 Code](https://t3.codes) Co-Authored-By: GPT-6 Astra <noreply@openai.com>
Retire completed native selections before forwarding wheel mouse reports or alternate-screen arrow keys. Preserve active drags, local scrollback selection and fractional wheel movements that do not send input. Both wheel regressions failed before the fix. Verified 143 focused tests, web typecheck and targeted lint. 🤖 Generated with [T3 Code](https://t3.codes) Co-Authored-By: GPT-6 Astra <noreply@openai.com>
Share the existing OSC parser and bounded clipboard writer through client-runtime. Observe live terminal subscription chunks on mobile and write through Expo Clipboard. This supports both native renderers without parsing their replayed initialBuffer. Only the focused terminal route in the active app may copy. Ignore initial history, reconnect/reset replays and background output; invalidate incomplete and queued copies on navigation, app deactivation and terminal changes. Clipboard reads remain disabled. Verified 171 focused tests, mobile/web/client-runtime typechecks and targeted lint. Six installed provider startup captures passed Ghostty selection/copy/input smoke tests. Simulator verification is pending installation of Xcode on the test host. 🤖 Generated with [T3 Code](https://t3.codes) Co-Authored-By: GPT-6 Astra <noreply@openai.com>
Forward an empty decoded payload so applications can clear the clipboard. Keep malformed payloads and clipboard queries distinct from valid empty text. The shared parser applies the behavior to web, desktop and mobile. Verified the focused clipboard tests, including exact empty and BOM payloads. 🤖 Generated with [T3 Code](https://t3.codes) Co-Authored-By: GPT-6 Astra <noreply@openai.com>
Offer a Copy or Clear action when the browser has no async clipboard API. The click supplies the user gesture required for a clipboard copy event, without moving terminal focus or changing the clipboard before confirmation. Reuse one prompt per terminal and dismiss it when that terminal is disposed. Verified 138 focused web tests and the web typecheck. A real Chrome client on the MacBook Neo copied text and cleared the macOS clipboard over LAN HTTP; its clipboard remained unchanged until each action was clicked. 🤖 Generated with [T3 Code](https://t3.codes) Co-Authored-By: GPT-6 Astra <noreply@openai.com>
Accept q when a selector list also includes the system clipboard c. Secondary-only requests remain local. The three combined-selector tests failed before the change; all 50 clipboard tests now pass. 🤖 Generated with [T3 Code](https://t3.codes) Co-Authored-By: GPT-6 Astra <noreply@openai.com>
Return written, failed, or skipped from the serialized clipboard writer. Offer the existing Copy/Clear prompt after an eligible failure, including browsers that expose the API but require a fresh user gesture. Ignore results from superseded requests and requests that lost terminal focus. Verified 142 web tests, five mobile clipboard tests, web/client-runtime typechecks, and targeted lint. A real Chrome client with async rejection forced copied text and cleared the macOS clipboard through the prompt. 🤖 Generated with [T3 Code](https://t3.codes) Co-Authored-By: GPT-6 Astra <noreply@openai.com>
Observe raw events from the existing terminal attachment before the 512 KiB output window and React batching can discard them. Scope observers to the full environment and attach request, and remove them when the route loses focus. The mobile clipboard session still ignores history and background output. The large single-write regression failed on the previous implementation. All 29 focused mobile/state tests pass, including a real subscription test for complete delivery, retained-buffer limits, isolation and unsubscription. Mobile, web and shared typechecks pass. The web clipboard fallback also passes through the updated attach path in a real Chrome client on the MacBook Neo. Native simulator verification remains pending Xcode installation. 🤖 Generated with [T3 Code](https://t3.codes) Co-Authored-By: GPT-6 Astra <noreply@openai.com>
Feed OSC 52 from the existing raw terminal attachment on web and desktop. Keep display writes/resynchronization separate from clipboard input so a 512 KiB retention reset neither loses a large copy nor replays one. Session resets still invalidate incomplete and queued clipboard requests. Verified 143 focused web tests and the web typecheck. A real Chrome client on the MacBook Neo copied 600 KiB to the macOS clipboard and then cleared it. All six captured provider startup selection/copy/input smoke tests pass again. 🤖 Generated with [T3 Code](https://t3.codes) Co-Authored-By: GPT-6 Astra <noreply@openai.com>
Use the stable attachment atom as the focus-effect dependency. Keep the latest target in a layout-updated ref, so equivalent input objects preserve an ongoing copy while an actual attachment change starts a new session. A React re-render probe failed on the previous code and passes with this change. It covers a split OSC across equivalent input objects and rejection of a partial copy after changing attachments. Mobile typecheck and lint pass. 🤖 Generated with [T3 Code](https://t3.codes) Co-Authored-By: GPT-6 Astra <noreply@openai.com>
Include the provider instance in clipboard observer registration and refresh it when the provider changes. Remove the duplicate toast import introduced by merging main, and verify observer isolation between providers. 🤖 Generated with [T3 Code](https://t3.codes) Co-Authored-By: GPT-6 Astra <noreply@openai.com>
Check selection endpoints against the core after output so scrollback eviction cannot reuse stale row coordinates. Finish native drags when the left button releases, clear cancelled single-cell selections, and release stale application and link ownership on capture loss. Preserve selection for all modifier key names and avoid repainting the whole grid when there is no selection to clear. 🤖 Generated with [T3 Code](https://t3.codes) Co-Authored-By: GPT-6 Astra <noreply@openai.com>
Release both WASM allocations if converting a tracked selection point throws. A fault-injection test checks cleanup through the real runtime. 🤖 Generated with [T3 Code](https://t3.codes) Co-Authored-By: GPT-6 Astra <noreply@openai.com>
Consolidate web and mobile clipboard eligibility and replay handling, and move parser and session tests alongside the shared implementation. Reuse the attach family key and a single web attach input so clipboard observation stays on the same stream. Isolate observer failures without dropping terminal output. Preserve focus acquired during asynchronous setup, keep the first pointer's ownership, and send a matching application mouse release on capture loss. Register AppState focus events only on Android; iOS does not support them. Verified with 180 focused tests, six provider startup captures, scoped typechecks, and native iOS clipboard text, clear, background, and reattachment checks. 🤖 Generated with [T3 Code](https://t3.codes) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Co-Authored-By: GPT-6 Astra <noreply@openai.com>
81e2610 to
8339d2e
Compare
|
Rebased onto upstream main at f8b4c46; the new head is 8339d2e. The rebase was conflict-free, and git range-diff confirms all 16 commit patches are unchanged. All 180 focused terminal/clipboard tests passed again on the rebased head. The previously verified terminal code is unchanged, so the simulator stayed shut down. Written by GPT-6 Astra in T3 Code on Morgan’s behalf. |

I had a number of frustrating situations (old terminal sessions in particular) where copying out of the t3code terminal didn't work with the Claude Code fullscreen tui enabled. Claude Code’s copy-on-select sends OSC 52 clipboard writes, which t3code wasn’t handling. Digging into Claude Code's copy-escape mode (hold shift when selecting text) there were also instances where t3code would hand mouse movement back to the Claude Code instance, even if a drag was still ongoing. This should make the default copy-on-select behavior in Claude Code's fullscreen tui work more reliably, and also improve the reliability of the drag-to-copy-with-shift-pressed fallback option Claude Code exposes.
Text below this line written by an LLM:
What Changed
Fixed copying from fullscreen terminal applications:
Why
Claude Code’s fullscreen redraws could erase a selection mid-drag. Releasing Shift before the trackpad button could hand the remaining drag back to Claude. Its copy-on-select OSC 52 path was unsupported.
Both Shift-drag/Cmd+C and Claude’s own copy were verified in T3 desktop with Claude Code 2.1.261 on the contributor’s physical MacBook Neo trackpad. A separate Chrome test over LAN HTTP verified Copy and Clear against the macOS clipboard, including leaving it unchanged before the click.
The latest fixes pass 180 focused web/shared tests and the web/mobile/client-runtime typechecks. Clipboard output reaches each client before the display buffer is trimmed; tests cover 600 KiB copies and verify that no extra RPC subscription is created. Browser testing covers an available async clipboard API that rejects the write, followed by a successful user-initiated copy. Captured startup output from all six installed providers (Codex, Claude, Cursor, Grok, OpenCode, and Antigravity) passed selection/copy/input checks through the terminal renderer. These were startup-screen checks, not full model turns.
Native iOS verification passed on one iPhone 17e simulator running iOS 26.5 on the MacBook Neo: exact Unicode clipboard text, empty-payload clearing, ignored background output, fresh copying after foregrounding, and no history replay after leaving and reopening the terminal. This caught and fixed Android-only AppState focus/blur subscriptions being registered on iOS. Android has not been tested in an emulator.
UI Changes
Terminal selection gestures are demonstrated below. Plain-HTTP connections now show a Copy/Clear prompt when the browser requires a click.
fullscreen-terminal-copy.webm
Checklist
Implemented with GPT-6 Astra in T3 Code on Morgan’s behalf, with simplification by Fable 5.1.
Note
Medium Risk
Large changes to terminal pointer handling, clipboard timing, and input routing in a core user-facing surface; regressions could affect selection, copy/paste, or mouse reporting in fullscreen apps.
Overview
Adds OSC 52 clipboard support end-to-end so fullscreen TUIs (e.g. Claude Code copy-on-select) can push text to the system clipboard on web, desktop, iOS, and Android.
A shared
@t3tools/client-runtime/terminal-clipboardmodule parses live PTY output for OSC 52, ignores history/replay and ineligible chunks, and serializes native writes so only the newest pending copy runs.terminalEnvironment.observeAttachtaps the same attach stream before buffer retention—no second RPC—feedingwriteClipboard/resetClipboardon Ghostty and a mobileuseTerminalClipboardsession tied to route focus and app state. Web shows a Copy/Clear toast whennavigator.clipboardis blocked and falls back to a gesture-based copy.Ghostty selection and input are reworked: drags bind to their pointer (including Shift fullscreen drags), autoscroll and capture loss are handled cleanly, and committed user input goes through
sendUserInput, which clears a finished selection before sending to the PTY while modifier keys, protocol replies, and native copy keep the highlight. Session output sync no longer clears selection on every chunk; keyboard shortcuts in the drawer use the surface input path instead of direct atom writes.Reviewed by Cursor Bugbot for commit 417e353. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Restore terminal clipboard copying from fullscreen TUI via OSC 52 and gesture-based selection
packages/client-runtime/src/terminalClipboard.ts; only live, focused, visible terminal output triggers a clipboard write, and snapshot/replay history is excludedGhosttyTerminalSurfaceinapps/web/src/terminal/ghostty/surface.tsto track selection as an owned pointer drag with centralized teardown, clearing stale selections on input, output eviction, visibility/focus/window-blur changes, and disposalGhosttyTerminalCore.selectionPositionand wraps native point/grid-ref conversions infinallyblocks inapps/web/src/terminal/ghostty/core.tsto fix memory leaks on thrown conversionsTerminalViewportand mobileuseTerminalClipboard, with toast/action fallback when browser blocks automatic writes and Expo Clipboard support on mobileobserveAttachto the terminal atom factory inpackages/client-runtime/src/state/terminal.tsso consumers can tap live attach stream events before retention without a second RPC subscriptionGhosttyTerminalSurfaceconstructor now reads the active element to initialize focus;onClipboardWriteandobserveClipboardare new surface options that hosts must wire up or clipboard output is silently dropped.pasteFromClipboard,onKeyDown,onPaste,onCompositionEnd,onInput, andonWheelnow route throughsendUserInput, which clears non-dragging selections before delivery — callers relying on directonDatainvocation for these paths are affectedMacroscope summarized 8339d2e.