Repository navigation
fix(dashboard-popout): wire terminal copy/paste in the popped-out window - #9765
Conversation
The Edit menu's Paste is a custom item that routes Cmd/Ctrl+V to the focused window as ui:appMenuPaste, and only the main window's React root listens for it — the popout dropped it, so paste silently did nothing. The copy chord similarly resolves in the main window's before-input-event handler, which the popout window never registers; the menu's role:'copy' no-ops on xterm's empty hidden textarea. AgentTerminalPreview now subscribes to onAppMenuPaste (guarded on focus inside the preview) and pastes via terminal.paste(), which xterm flags as user input so the existing preview->PTY routing and main-process input limits apply. A custom key handler honors the terminal.copySelection and terminal.paste keybindings, skipping plain Mod+V since the menu accelerator owns that chord (handling it twice would paste double). The popout bootstrap fetches keybinding overrides so custom bindings apply.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughThe popout now fetches keybindings during settings synchronization. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: b0f47c3f-9be4-4c4f-a7ff-65ad7cd4282d
📒 Files selected for processing (3)
src/renderer/src/components/dashboard-popout/AgentTerminalPreview.test.tsxsrc/renderer/src/components/dashboard-popout/AgentTerminalPreview.tsxsrc/renderer/src/popout.tsx
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/renderer/src/components/dashboard-popout/AgentTerminalPreview.test.tsx (1)
295-314: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winChunking test only covers ASCII; byte-based limits go unverified for multi-byte pastes.
largePasteis built from repeated'x'characters, so.lengthhappens to equal byte count.TERMINAL_PASTE_CHUNK_MAX_BYTES/TERMINAL_PASTE_DIRECT_MAX_BYTESare byte limits per their names, but this test can't catch a chunking implementation that slices by character count instead of UTF-8 byte length — a real gap for pastes containing multi-byte characters (e.g., emoji, non-Latin text).Consider adding a case with multi-byte characters (e.g. repeated multi-byte glyphs) and asserting chunk byte sizes via
Buffer.byteLength/TextEncoderrather than.length.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 729bbaaa-f56b-40c8-8f75-4c35b950d7d9
📒 Files selected for processing (5)
src/main/window/clipboard-dashboard-popout-access.test.tssrc/main/window/clipboard-ipc-handlers.test.tssrc/main/window/clipboard-ipc-handlers.tssrc/renderer/src/components/dashboard-popout/AgentTerminalPreview.test.tsxsrc/renderer/src/components/dashboard-popout/AgentTerminalPreview.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- src/renderer/src/components/dashboard-popout/AgentTerminalPreview.tsx
…erminal-copy-paste
…erminal-copy-paste
…review terminal (#9771) * fix(dashboard-popout): forward macOS IME native-text commits in the preview terminal The preview terminal enables xterm's kitty keyboard protocol (via buildDefaultTerminalOptions), whose encoder can encode and cancel a printable keydown before Chromium commits the real IME/native text — silently dropping macOS input-source commits and synthetic Unicode injection. Main-window panes guard this with the IME native-text forwarder; the pop-out preview never installed it. Install the composition tracker + forwarder (macOS-only, mirroring TerminalPane) and claim native-text key events at the top of the preview's custom key handler so the committed glyph reaches the PTY via terminal.input() and the existing user-input routing. * fix(dashboard-popout): prewarm IME input source * fix(skills): preserve released history across new tags (#9778) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(skills): record latest Linear release history (#9777) --------- Co-authored-by: OrcaWin <alpha-eng@stably.ai> Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…dow (stablyai#9765) * fix(dashboard-popout): wire terminal copy/paste in the popped-out window The Edit menu's Paste is a custom item that routes Cmd/Ctrl+V to the focused window as ui:appMenuPaste, and only the main window's React root listens for it — the popout dropped it, so paste silently did nothing. The copy chord similarly resolves in the main window's before-input-event handler, which the popout window never registers; the menu's role:'copy' no-ops on xterm's empty hidden textarea. AgentTerminalPreview now subscribes to onAppMenuPaste (guarded on focus inside the preview) and pastes via terminal.paste(), which xterm flags as user input so the existing preview->PTY routing and main-process input limits apply. A custom key handler honors the terminal.copySelection and terminal.paste keybindings, skipping plain Mod+V since the menu accelerator owns that chord (handling it twice would paste double). The popout bootstrap fetches keybinding overrides so custom bindings apply. * fix(dashboard-popout): harden terminal clipboard routing * fix(dashboard-popout): authorize terminal clipboard text * test(dashboard-popout): harden terminal paste coverage * fix(terminal): normalize streamed paste newlines * fix(dashboard-popout): forward macOS IME native-text commits in the preview terminal (stablyai#9771) * fix(dashboard-popout): forward macOS IME native-text commits in the preview terminal The preview terminal enables xterm's kitty keyboard protocol (via buildDefaultTerminalOptions), whose encoder can encode and cancel a printable keydown before Chromium commits the real IME/native text — silently dropping macOS input-source commits and synthetic Unicode injection. Main-window panes guard this with the IME native-text forwarder; the pop-out preview never installed it. Install the composition tracker + forwarder (macOS-only, mirroring TerminalPane) and claim native-text key events at the top of the preview's custom key handler so the committed glyph reaches the PTY via terminal.input() and the existing user-input routing. * fix(dashboard-popout): prewarm IME input source * fix(skills): preserve released history across new tags (stablyai#9778) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> * fix(skills): record latest Linear release history (stablyai#9777) --------- Co-authored-by: OrcaWin <alpha-eng@stably.ai> Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> --------- Co-authored-by: OrcaWin <alpha-eng@stably.ai> Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Summary
Fix copy and paste in the popped-out agent dashboard terminal.
The popout is a standalone BrowserWindow outside several main-window-only input and clipboard boundaries:
The fix subscribes the preview to app-menu paste while it owns focus, adds platform-aware terminal copy/paste keybinding handling (including user overrides), and authorizes bounded text clipboard access only for the exact live dashboard popout. Large pastes remain capped at 16 MiB and stream as acknowledged 16 KiB IPC payloads above the 64 KiB direct threshold. The streamed path lazily applies the same terminal line-ending semantics as ordinary xterm paste without allocating a second full-size string. Focus changes cancel stale work and close an opened bracketed-paste frame.
Screenshots
No visual change.
Testing
pnpm lint— touched-file lint passes; repository-wide lint reaches a pre-existing switch-exhaustiveness error under local Node 26 in unchangedskill-freshness-group.tsx(CI uses Node 24)pnpm typecheckpnpm test— 138 tests passed across 12 directly affected terminal, clipboard, popout, runtime, and IPC test files; the current CI run stops during lint before testspnpm build— production desktop, web, relay, CLI, Electron main/preload/renderers, and native macOS targets built successfullyAdditional checks: touched-file oxlint and oxfmt, max-lines ratchet, and reliability gate manifest all pass.
AI Review Report
The review traced the complete keyboard/menu event path, renderer-to-main clipboard trust boundary, PTY write path, async focus cancellation, repeated-key suppression, bracketed-paste cleanup, large-paste memory/IPC behavior, and terminal paste semantics across the direct and chunked paths.
It found and fixed one production blocker: the original implementation routed popout clipboard calls correctly but the main-process clipboard authorization still rejected them. It also found that streamed pastes preserved LF/CRLF while ordinary xterm paste normalizes terminal newlines, making behavior change at the 64 KiB threshold. The streamed iterator now normalizes lazily while preserving UTF-8 chunk limits and CRLF boundaries. Tests also fail loudly if app-menu subscription registration regresses.
Cross-platform behavior was reviewed for macOS, Linux, and Windows. Shortcut matching uses Orca's platform abstraction, plain Cmd/Ctrl+V remains owned by the Edit-menu accelerator to avoid duplicate paste, and no path or shell assumptions were added. PTY writes continue through the provider-owned terminal-preview runtime, preserving SSH, WSL, remote-runtime, and mobile driver boundaries.
Security Audit
Clipboard IPC permits only bounded text reads and writes from the exact live dashboard-popout webContents. Selection, image, file, and remote clipboard APIs remain restricted to the main renderer, and unrelated or stale windows are rejected.
Clipboard text is capped at 16 MiB. Large writes are measured with event-loop yields and sent as bounded acknowledged chunks. Bracketed paste neutralizes embedded escape bytes, and cancellation closes an opened bracket. Product diagnostics do not log clipboard or terminal contents. No command execution, filesystem access, secrets, dependency, or network surface was added.
Notes
Reliability invariant: a focused popout copy/paste action targets the same live PTY exactly once; stale focus cannot redirect an async paste, and an opened bracketed-paste frame is closed.
There is no dedicated live Electron cross-window clipboard gate yet. Live Windows Electron, SSH, WSL, and remote-runtime coverage remains unproved. Mouse selection remains misaligned when the preview is CSS-scaled below 1:1 because xterm does not transform mouse coordinates.
Latest
mainis merged, including the oversized-module splits that removed the prior CI max-lines blockers. The PR remains conflict-free and mergeable.