fix(web): paste terminal text once and clear the shortcut on release#19366

merged3
main
t3/fix-13346
opened29d agobyTtheo
View on GitHubTwo-way sync enabledPR last imported 22d ago

A terminal shortcut can send text twice when its clipboard read resolves before Chromium’s native paste event. Keep one gesture’s sent text so the matching native duplicate is consumed, while native-first paste still cancels a late read.

End the gesture on shortcut or modifier release and blur. This also handles macOS omitting V keyup while Command is held, so a later identical menu paste still works. Native fallback after a denied read and paste encoding are preserved.

Fixes #13346. Maintainer takeover of @t3dotgg’s #19366, retaining the original commits and @r4iju’s earlier design contribution.

Verification:

  • Existing surface suite: 77 → 81 passing. Replaced one combined test with five focused parameterized cases covering both arrival orders and cleanup after V release, blur, and Meta release without V release.
  • Clipboard-first test fails with base production code; Meta-release test fails on the original PR and passes after cleanup.
  • Web typecheck, targeted lint, formatting and diff checks passed.
  • Independent Claude Opus 5.5 and Codex GPT-6 Sol whole-PR reviews: one clean round; optional cosmetic suggestions left out.
  • Headless Linux Chromium, actual app terminal and PTY: controlled clipboard-read-first / native-paste event order echoes the text twice on the actual base and once on head. A separately simulated Mac modifier sequence accepts the later identical menu paste. Test fonts are explicitly loaded for both captures.
  • This controls event order with synthetic keyboard/clipboard events; it does not verify native OS clipboard timing. Real macOS, Windows, iOS, Android and Electron desktop were not verified.

Before (actual base, two sends):

Before: one paste appears twice in the terminal

After (one send):

After: one paste appears once in the terminal

Before interaction recording · After interaction recording

Implemented with Codex GPT-6.1 Sol; regression tests with Codex GPT-6 Astra; reviewed with Claude Opus 5.5 and Codex GPT-6 Sol through T3 Code.

Checks

23 successful · 10 skipped
All checks passed
b4e75c1

Added 1 commit

  • fix(web): terminal paste no longer lands twice in Chromium4f9cb7a
Synced from GitHub

Approvability

Verdict: Approved at b4e75c1

Macroscope's review found this PR approvable — This is a narrowly scoped terminal paste bug fix that prevents duplicate delivery while preserving fallback and encoding behavior. The production change is localized and covered by focused tests, with no schema, infrastructure, sensitive-area, product-default, or static-analysis configuration impact.

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

Synced from GitHub

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Team
  • Run ID: d507a749-2683-4730-a42c-64ffa68568da
📥 Commits

Reviewing files that changed from the base of the PR and between 4f9cb7a76b0ac198bcc9d46804730a51c8c5f2c3 and b4e75c1e63ae94083d6afcde77b95bb1987f7b50.

📒 Files selected for processing: 2
  • apps/web/src/terminal/ghostty/surface.test.ts
  • apps/web/src/terminal/ghostty/surface.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 0 remain after this review.

📝 Walkthrough

The terminal surface now tracks text delivered by a clipboard-read paste shortcut and suppresses a matching native paste from the same gesture. Tests cover both event arrival orders and verify that key release or blur clears the gesture.

Changes: Terminal paste deduplication

Layer / File(s)Summary
Track and deduplicate shortcut paste
apps/web/src/terminal/ghostty/surface.ts, apps/web/src/terminal/ghostty/surface.test.ts
The surface records clipboard-read text for the active shortcut, clears the gesture on key release or blur, and drops a matching native paste. Tests cover both event orders and confirm that a later native paste is accepted after gesture cleanup.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: stienswout

Merge Risk: ⚪ Minimal · up to b4e75

The change stops terminal text from being pasted twice when the clipboard read finishes before the native paste event. It ends the paste gesture on key release or blur so a later identical paste still works. No concrete merge-blocking risk was found. Real-browser timing after key release is untested, but it is not shown to cause a problem.

Pre-merge checks: Passed 4
Check nameStatusExplanation
Linked Issues checkPassedIssue #13346 requires deduplication when the asynchronous clipboard read arrives before the native paste. surface.ts records the sent clipboard text and suppresses one matching native paste. The cod…
Out of Scope Changes checkPassedThe changes are limited to paste gesture handling in apps/web/src/terminal/ghostty/surface.ts and related regression tests in surface.test.ts. These changes directly support issue #13346. No unrel…
Title checkPassedThe title clearly and concisely describes the main change: preventing duplicate terminal paste delivery and clearing the shortcut state on release.
Description checkPassedThe description explains the problem, implementation, scope, linked issues, verification results, limitations, and test evidence. It does not use the template headings explicitly or include a direct a…
Full details: Linked Issues check

Explanation

Issue #13346 requires deduplication when the asynchronous clipboard read arrives before the native paste. surface.ts records the sent clipboard text and suppresses one matching native paste. The code preserves native-first fallback and clears the gesture on key release, modifier release, and blur. surface.test.ts covers both arrival orders and later identical pastes after cleanup.

Full details: Out of Scope Changes check

Explanation

The changes are limited to paste gesture handling in apps/web/src/terminal/ghostty/surface.ts and related regression tests in surface.test.ts. These changes directly support issue #13346. No unrelated change is shown.

Full details: Description check

Explanation

The description explains the problem, implementation, scope, linked issues, verification results, limitations, and test evidence. It does not use the template headings explicitly or include a direct approval comment, but it provides the required information in a mostly complete form.

✨ 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

Comment @coderabbitai help to get the list of available commands.

Synced from GitHub

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire5.0 KiB5.0 KiB+7 B (+0.1%)6.8 KiB✅
CodexThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiB✅
CodexLive turn WebSocket wire1.2 KiB1.2 KiB+7 B (+0.6%)2.0 KiB✅
CodexLive turn WebSocket decoded20.9 KiB20.9 KiB0 B (0.0%)29.3 KiB✅
CodexLive turn messages220 (0.0%)8✅
ClaudeTotal thread wire5.0 KiB5.0 KiB−7 B (−0.1%)6.8 KiB✅
ClaudeThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiB✅
ClaudeLive turn WebSocket wire1.2 KiB1.2 KiB−7 B (−0.6%)2.0 KiB✅
ClaudeLive turn WebSocket decoded21.2 KiB21.2 KiB0 B (0.0%)29.3 KiB✅
ClaudeLive turn messages220 (0.0%)8✅

Baseline: 40d43a1 · PR result: 4f9cb7a · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 108.5 KiB
  • Claude decoded thread snapshot: 108.8 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

Taking over this one. I’ll keep your commits and push the maintainer rebuild on this branch.

Added 2 commits

  • Merge remote-tracking branch 'origin/main' into t3/fix-1334622c5d9c
  • fix(web): end terminal paste gestures on modifier releaseb4e75c1