Skip to content

fix(web): let focused terminal programs copy with OSC 52 - #25243

Open
maria-rcks wants to merge 2 commits into
mainfrom
maria/takeover-pr-25051
Open

maria-rcks wants to merge 2 commits into
mainfrom
maria/takeover-pr-25051

Conversation

@maria-rcks

@maria-rcks maria-rcks commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

Terminal programs emit OSC 52 to copy text, but the web terminal ignores it and leaves the old clipboard contents unchanged.

Change

Retain the original's bounded streaming scanner and wire clipboard writes into the thread terminal. Only focused, visible terminals in a focused browser window can copy; history replay resets the scanner without copying, and clipboard reads are never answered. Clipboard failures use the existing error toast. Four files, no dependencies or new test files.

Verification

  • Both regression tests fail on current main (3de45c6254) before implementation. All 47 surface/core tests pass after it.
  • Blacksmith vp run check:changed passes format, lint, both dependency checks, affected typechecks, and all 34 adjacent tests.
  • System Google Chrome, repo Playwright, default vp run dev, real PTY and clipboard: the same command pastes old clipboard on main and osc52 works after the fix. Unfocused live output and reload history preserve a sentinel clipboard.
  • GitHub CI passes on the current head 1eb74fcdf3, rebased on main.
  • Macroscope requests human review of the clipboard side effect. The inline lint suppression it flagged was removed.
  • Unverified: Safari, Electron, native mobile, remote/tunnel connections, and emitting applications such as tmux and Vim. Web and desktop share this path; provider sign-in terminals and native mobile are unchanged. Browser clipboard permissions can reject writes. The existing 512 KiB display buffer can trim large copies before parsing; the scanner bounds buffered OSC bodies at 1 MiB.

main leaves the previous clipboard text in the composer

the same terminal command now copies osc52 works into the composer

real terminal OSC 52 copy followed by composer paste in Chrome

Takeover

Replaces #25051, with thanks to @maria-rcks for the original implementation.

Built with GPT-6.1-Sol in the Codex harness on T3 Code.

@coderabbitai

coderabbitai Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

The terminal surface now detects valid OSC 52 clipboard writes in terminal output. It forwards decoded text to a clipboard callback only when the surface and document have focus and the surface is visible. The terminal drawer copies the text and shows an error toast if copying fails.

Changes: OSC 52 clipboard handling

Layer / File(s) Summary
Decode and scan OSC 52 writes
apps/web/src/terminal/ghostty/osc52.ts
The scanner decodes eligible OSC 52 write bodies across terminal output chunks. It rejects reads, invalid or empty text, and oversized bodies; BEL and ST complete a sequence, while CAN and SUB abort it.
Gate and forward clipboard writes
apps/web/src/terminal/ghostty/surface.ts, apps/web/src/components/ThreadTerminalDrawer.tsx, apps/web/src/terminal/ghostty/surface.test.ts
The surface scans configured writes and forwards decoded text only when focus and visibility checks pass. The drawer copies the text and shows an error toast if copying fails. Tests cover valid, malformed, cancelled, incomplete, and out-of-focus sequences.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant TerminalOutput
  participant GhosttyTerminalSurface
  participant Osc52Scanner
  participant ThreadTerminalDrawer
  participant Clipboard
  TerminalOutput->>GhosttyTerminalSurface: provide terminal output
  GhosttyTerminalSurface->>Osc52Scanner: scan configured output
  Osc52Scanner-->>GhosttyTerminalSurface: return decoded text for valid writes
  GhosttyTerminalSurface->>ThreadTerminalDrawer: invoke callback when focus and visibility checks pass
  ThreadTerminalDrawer->>Clipboard: copy text
Loading

Possibly related issues

  • pingdotgg/t3code#8361: The issue reports that OSC 52 terminal output does not update the clipboard, which this change addresses with OSC 52 copy handling.

Suggested reviewers: t3dotgg

Merge Risk: Minimal · up to 1eb74

This change lets focused, visible web terminals copy text via OSC 52 and shows an error toast if the clipboard write fails. No concrete merge-blocking risk was found.

Pre-merge checks: Passed 3 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Description check Warning The description explains the problem, change, and verification. It omits the required scope and approval information. The visual evidence is not hosted on GitHub. Add a Scope and approval section with a link to a triaged issue or discussion and the explicit maintainer approval comment. If this is a very small, focused fix of an obvious bug, explain why it qualifies without prior approval. Upload the …
Passed Passed checks: 3 passed

Check name Status Explanation
Title check Passed The title clearly describes the OSC 52 clipboard change.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Resolution

Add a Scope and approval section with a link to a triaged issue or discussion and the explicit maintainer approval comment. If this is a very small, focused fix of an obvious bug, explain why it qualifies without prior approval. Upload the screenshots and recording to GitHub and link or embed them in the description.

Finishing Touches

Generate docstrings

  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)

  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Recent review info

Run configuration

Commits

Reviewing files that changed from the base of the PR and between 9469095 and 1eb74fc.

Files selected for processing: 4

  • apps/web/src/components/ThreadTerminalDrawer.tsx
  • apps/web/src/terminal/ghostty/osc52.ts
  • apps/web/src/terminal/ghostty/surface.test.ts
  • apps/web/src/terminal/ghostty/surface.ts

Limit details: You’ve used all 10 included reviews currently available.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Oct 26, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — Terminal programs can now write to the clipboard when their terminal and document are focused; clipboard reads remain disabled. Human review is required to confirm this default behavior, which allows program output to replace existing clipboard contents.

You can add or adjust custom eligibility rules. Learn more.

maria-rcks commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator Author

Note

Written by gpt-6.1-sol on behalf of Maria

Verified in a real dev environment

Verified unchanged head d7863610bad0275bd07c2c55d86a9ad081c84dea on a disposable Linux Boat VM. Reproduced the missing behavior on github/main at f17c9d202b in /home/user/main, installed with vp i, and ran its real dev server. Stopped that server before starting the exact PR head with its own dev home and vp i.

Used repository Playwright and /usr/bin/google-chrome. Created a project pointing at the real /home/user/t3code git repository and a thread through each running web app. Selected Codex gpt-6.1-sol and completed a real provider turn through the local proxy on both versions. No mocks, fixtures, replay provider, or database seeding.

Opened the thread terminal, ran the following through its real PTY, then pasted into the composer:

printf '\033]52;c;b3NjNTIgd29ya3M=\007'
  • Main: clipboard and composer remained old clipboard.
  • PR: clicking the terminal and running the same command copied osc52 works; normal Ctrl+V pasted it into the composer.
  • Nearby behavior: delayed OSC 52 output while the composer held focus preserved background sentinel, with BACKGROUND_EMITTED visible in the terminal. Reloading the page and restoring terminal history preserved history sentinel.
  • Unicode and alternate termination: printf '\033]52;;aMOpbGxvIPCfkYs=\033\\' copied héllo 👋.
  • Real Codex responses, ordinary terminal input, shell output, and composer paste remained usable.

Blacksmith checks on this head: all 47 surface/core tests passed. vp run check:changed passed format, lint, both knip checks, affected typechecks, and 34 adjacent tests. The runner's shallow boundary initially prevented merge-base discovery; after fetching the PR base and exposing the already-present parent in the task runner only, the check correctly inspected the four PR files since 3de45c625434. No repository changes or pushes were needed. Hosted checks are complete: 22 successful, seven skipped, one neutral, with zero failing or pending.

Before, main:

main terminal emits OSC 52 but composer still pastes old clipboard

After, PR:

pr terminal emits the same OSC 52 command and composer pastes osc52 works

real terminal command followed by clipboard paste into the composer

Inspected the full-size screenshots and exported recording. Verified uploaded image bytes and video playback and seeking, including T3's browser player.

Not verified

Native iOS/Android, Electron, macOS/Windows, Safari/Firefox, remote/relay/tunnel connections, tmux/Vim passthrough, large clipboard payloads, clipboard-permission rejection, and browser-window focus loss were not exercised here. This pass verifies Linux Chrome's local web thread-terminal path. Malformed payloads and clipboard read suppression passed the existing automated tests; they were not separately driven through the real PTY in this pass.

@juliusmarminge juliusmarminge added the bugfix Fix PR opened by an issue lead; enters the PR loop label Oct 28, 2026
@juliusmarminge juliusmarminge added the pr:needs-julius Needs Julius: route gate, unverifiable surface, or blocked label Oct 28, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix Fix PR opened by an issue lead; enters the PR loop pr:needs-julius Needs Julius: route gate, unverifiable surface, or blocked size:L 100-499 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants