Skip to content

feat(explorer): paste clipboard images into local and remote folders - #27806

Open
marinhooodev wants to merge 20 commits into
stablyai:mainfrom
marinhooodev:feat/explorer-paste-image
Open

marinhooodev wants to merge 20 commits into
stablyai:mainfrom
marinhooodev:feat/explorer-paste-image

Conversation

@marinhooodev

@marinhooodev marinhooodev commented Oct 12, 2026 •

Copy link
Copy Markdown

ELI5

Copy an image, select a folder in Files, and paste. Orca saves it there as a PNG. Today, an image that exists only on the clipboard (a screenshot, an image copied from a browser) cannot be pasted into the Files explorer at all. With this change, Ctrl+V / Cmd+V or Paste Image creates pasted-image.png in that folder without overwriting anything, expands the folder, and selects the new file. Explorer Undo removes it; Redo puts the same image back.

What Changed

  • Gestures: Ctrl+V / Cmd+V, the desktop Edit > Paste menu, and a Paste Image item in the row and background context menus. A folder targets itself, a file targets its parent folder, and the background targets the displayed root.
  • Capture: the main process reads the clipboard pixels once, encodes them as a PNG, and stages them as a private, size-bounded file owned by the requesting window. It uses the same clipboard image reader as chat paste, so CleanShot screenshots that macOS stores as JPEG bytes under the PNG type (fix(clipboard): paste CleanShot JPEG screenshots stored under the macOS PNG type #29685) paste here too. Text, HTML, image URLs without pixels, and copied-file clipboard payloads are ignored; nothing is downloaded.
  • Import: the staged PNG goes through the existing file-import pipeline, so local, paired-runtime, and SSH destinations reuse its routing, authorization, and no-clobber naming (pasted-image copy.png, …). The workspace owner and connection generation are captured before any asynchronous work, so a reconnect or workspace switch cannot redirect the write to another host.
  • Result: the existing Explorer reveal flow expands collapsed folders and selects the new image. The paste is recorded in the existing Explorer undo/redo history: Undo deletes the path that was actually created, and Redo re-imports the retained snapshot without rereading the clipboard. Snapshots are released when their history step is discarded, the history is cleared, or the window goes away.
  • Remote safety: image uploads require the destination folder to still exist instead of recreating it. Hosts advertise files.upload-existing-parent.v1; an older remote host gets a clear "update required" error before any upload.
  • Unchanged: paste in chat, editors, terminals, and rename inputs keeps its current owner, even while an Explorer folder is selected.

Why

Screenshots and browser images often exist only on the clipboard, so today they must be saved somewhere else and then imported. Reusing the existing import pipeline instead of adding a new transfer path keeps host ownership, no-clobber writes, filename rules, and SSH behavior identical to drag-and-drop import. Undo/redo hooks into the history Explorer already has instead of introducing a separate one.

Linked Issue

Fixes #27804

Related: #12929 and #9443 cover copying existing files. This PR handles clipboard pixels only, so it does not close them.

Visual Proof

Same automated gesture and fixture on Windows: select Clipboard demo, then Ctrl+V. Before uses clean main at ae0ff631; after uses this branch. The clipboard holds controlled native image pixels. Screenshots come from real hidden Electron renderers, not mockups.

Before: the folder stays empty.

Before: clipboard pixels do not create a file

After: pasted-image.png is created and selected.

After: the pasted PNG is selected in Files

Remote: a Windows desktop connected to a Linux folder over managed SSH. Keyboard and menu paste create two byte-identical PNGs without overwriting the first.

Managed SSH image paste into Linux

Testing

Manual (Windows 11, local folder workspace, dev build of this branch after merging main at 25f87544): Ctrl+V into a folder; paste into a collapsed folder, which expands and selects the new PNG; Paste Image from a folder row, a file row (saves to its parent), and the tree background (saves to the root); a second paste creates pasted-image copy.png; Ctrl+Z removes the pasted image and Ctrl+Shift+Z restores it. macOS, Linux desktop, and SSH were not tested by hand; they are covered by the automated runs below.

  • I manually tested these changes locally
  • Automated tests added/updated, or explained why not below

After merging current main (6dd7ab55), on Windows (Node 24.14.0, pnpm 12.8.1, Bun 1.4.2, Electron 43.7.8). This merge was validated by the automated runs below, not by hand:

  • pnpm build passed: desktop, WSL guest, CLI, web, mobile web, and the native Windows binaries. pnpm typecheck and the seven changed-code quality checks pass (0 new findings across 62 changed files).
  • pnpm lint: every step passes except audit:code-quality:native, which reports five import/no-cycle warnings in mobile/src/transport and mobile/src/terminal/document. Clean main reports the same five; this branch does not touch mobile/, and the same audit over src, config, and tests passes.
  • Focused unit tests: 188 passed and 1 POSIX-only skip across 18 files, including the three existing import/drop/committed-scope suites. A wider run over the Explorer, runtime file, upload, and clipboard suites: 1,063 passed in 127 files; its 10 failures, in five upstream files, fail the same way on clean main (symlink permissions and POSIX paths on Windows). Linux Docker: the 18 files plus the upstream file-mutation, local-provider, and macOS clipboard suites, 223 passed.
  • 13 Electron scenarios passed: fixture and system clipboard paste without overwriting; mixed clipboard formats (editable paste kept, file-name and shell-file-list previews not converted); an image copied in Edge; collapsed-folder reveal with undo/redo restoring identical PNG bytes; paired runtime with staging cleanup; refusal on a host without files.upload-existing-parent.v1; chat, editor, and terminal keeping their paste; and managed SSH from Windows into a Linux container running an orcad built from this merge.
  • The terminal focus scenario was flaky because it pasted before the shell had attached, and the terminal cancels a paste aimed at a pane that is still attaching. The test now waits for a shell round-trip first, as the other terminal E2E specs do. After that change, the capability and focus scenarios passed three times in a row.

The pre-commit formatter also reformatted repository-project-operations-part-02.spec.ts in the merge commit; oxfmt --check flags that file on main.

Earlier on this branch, before the undo/redo follow-up and the merge (d613ca74):

  • pnpm build passed: desktop, CLI, web, mobile web, and the native Windows CLI launcher.
  • 12 Electron scenarios passed across the system clipboard, mixed clipboard formats, an image copied in Edge, paired runtime, missing capability, focus ownership, and managed SSH.
  • Linux desktop under Xvfb: 5 Electron scenarios passed (controlled and native X11 clipboard images, plus terminal/chat/editor focus ownership). Linux/X11 capture. Wayland and physical desktop focus were not tested.

Known local limitation: the repository-wide pnpm test is not green on this Windows machine for reasons unrelated to this change (SQLite cleanup locks, symlink permissions, POSIX shell assumptions); two clean main runs reproduced the same failure classes. None of the changed test files failed. CI on Linux covers the full suite. pnpm typecheck:e2e reports 686 existing diagnostics, the same count as clean main, none in the image-paste files.

To reproduce the controlled local, history, paired-host, capability, and focus cases:

pnpm run test:e2e tests/e2e/file-explorer-image-paste.spec.ts tests/e2e/file-explorer-image-paste-history.spec.ts tests/e2e/file-explorer-image-paste-paired.spec.ts tests/e2e/file-explorer-image-paste-capability.spec.ts tests/e2e/file-explorer-image-paste-focus.spec.ts --workers=1

System clipboard and Edge specs require their explicit clipboard opt-in (ORCA_E2E_SYSTEM_CLIPBOARD_IMAGE=1, ORCA_E2E_BROWSER_CLIPBOARD_IMAGE=1); their helpers capture and restore the clipboard. The SSH spec requires ORCA_E2E_SSH_DOCKER=1 and ORCA_E2E_ORCAD_CONVERT_TEMPLATE pointing to a Linux template built from this checkout. All Electron runs used isolated profiles and ORCA_BACKGROUND_LAUNCH=1.

AI Disclosure

Implemented and tested with AI coding agents: OpenAI Codex (GPT-6) for the feature and most of the test suite, and Claude Code (Claude Sonnet 5.5 for the reveal and undo/redo follow-up; Claude Opus 5.5 for merging current main and the final validation). The automated checks and screenshots above were run by the agents. The manual testing above was done by the author.

Review

AI agent review of the final diff:

  • Cross-platform: the shortcut uses the runtime platform check (Cmd on macOS, Ctrl elsewhere) and the existing shortcut formatting; paths use the existing path helpers, and menu labels are translated. Windows, Linux unit/host, and Linux desktop (X11 under Xvfb) are covered. macOS (including the CleanShot path, which only unit tests cover), Linux Wayland, and physical native-menu activation still need a collaborator check.
  • Local / SSH / remote: the destination owner, connection, and generation are captured before staging and rechecked around the import and around undo/redo, so the write never falls back to a different host. Undo is refused after an SSH reconnect without losing the history step. The existing-parent rule is enforced on chunk writes and the final commit, and older hosts are refused through capability negotiation. Folder workspaces and git worktrees use the same path.
  • Agents and integrations: no agent-, integration-, or Git-provider-specific code was added.
  • Performance: encoding runs only on an explicit paste action, within the existing image size limits. There is no clipboard polling or new process, and paste listeners are attached only while the Files explorer is visible.
  • UI: existing context-menu primitives, icons, and shortcut hints; no new styles or tokens.
  • Security: trusted-sender IPC; opaque, owner-bound staging handles; existing image size and dimension limits; private staging permissions on POSIX; at most 8 concurrent encodes and 64 retained snapshots (enough for the 50-step Explorer history); cleanup on release plus an expired-file sweep; existing authorization and no-clobber import semantics. URLs and HTML alone are never fetched.

Agent skill upstream boundary

  • Not applicable, or this change copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

Ensure no issues in: Security, Cross-platform support (Linux, Windows, Mac), Remote SSH, Mobile, general backwards compatibility, performance. Covered in Review above: older remote hosts are refused cleanly instead of failing silently, and web/mobile clients are untouched.

Out of scope: web/mobile clipboard access, generic file copy/paste, and undo/redo for arbitrary binary edits. Undo/redo of this image paste is included. Images from native screenshot tools and image editors were not validated separately; they use the same native clipboard image path. The missing-capability test changes the advertised capabilities of a disposable host; it does not run a historical server binary.

Author: @marinhooodev · X: @marinhoo___

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

This is one feature, but about 3,700 of the ~4,600 added lines are tests (unit, Electron, paired-host, and SSH), so the size box is left unchecked. Build, typecheck, and lint pass locally after the merge (apart from the existing mobile/ warnings above), and the focused unit tests pass on Windows and Linux. The full pnpm test relies on CI (see the Windows limitation above).

marinhooodev and others added 17 commits October 12, 2026 02:47
Reveal the imported file through the existing Explorer reveal flow so a collapsed destination folder expands and selects it. Record the paste in the Explorer undo/redo history, retaining a bounded private snapshot so Redo restores the same pixels without rereading the clipboard.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…-image

Resolve useFileExplorerImport.ts against the runtime file client split: the
import flow lives in use-file-explorer-import-operation.ts, which now imports
from runtime-file-import-client and runtime-file-mutation-client.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A paste sent while the pane is still attaching its shell is cancelled as a
stale target, which made the terminal focus scenario flaky. Wait for a shell
round-trip first, as the other terminal E2E specs do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@marinhooodev
marinhooodev marked this pull request as ready for review October 12, 2026 18:02
@coderabbitai

coderabbitai Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 1a0136a3-8464-44dc-9cd9-1ff2a88d80c5
📥 Commits

Reviewing files that changed from the base of the PR and between b0e73d9 and 715c566.

📒 Files selected for processing (63)
  • src/main/ipc/runtime-upload-file-stream.ts
  • src/main/providers/filesystem-provider-contract.ts
  • src/main/providers/local-filesystem-provider.ts
  • src/main/runtime/rpc/methods/files-mutation-methods.ts
  • src/main/runtime/rpc/methods/files-upload-existing-parent.test.ts
  • src/main/runtime/runtime-file-commands-create-file-explorer-dir-no-clobber.ts
  • src/main/runtime/runtime-file-commands-write-file-explorer-file.ts
  • src/main/runtime/runtime-file-upload-existing-parent.test.ts
  • src/main/window/clipboard-image-import-ipc.test.ts
  • src/main/window/clipboard-image-import-ipc.ts
  • src/main/window/clipboard-image-import-source.test.ts
  • src/main/window/clipboard-image-import-source.ts
  • src/main/window/clipboard-image-import-staging.test.ts
  • src/main/window/clipboard-image-import-staging.ts
  • src/main/window/clipboard-ipc-handlers.test.ts
  • src/main/window/clipboard-ipc-handlers.ts
  • src/preload/api/ui-bridge-clipboard-and-window-controls.ts
  • src/preload/api/ui-window-api.ts
  • src/renderer/src/components/right-sidebar/FileExplorer.tsx
  • src/renderer/src/components/right-sidebar/FileExplorerBackgroundMenu.test.tsx
  • src/renderer/src/components/right-sidebar/FileExplorerBackgroundMenu.tsx
  • src/renderer/src/components/right-sidebar/FileExplorerFilesTreePane.tsx
  • src/renderer/src/components/right-sidebar/FileExplorerRow.tsx
  • src/renderer/src/components/right-sidebar/FileExplorerVirtualRows.tsx
  • src/renderer/src/components/right-sidebar/file-explorer-image-paste-history.ts
  • src/renderer/src/components/right-sidebar/file-explorer-row-context-menu.test.tsx
  • src/renderer/src/components/right-sidebar/file-explorer-row-context-menu.tsx
  • src/renderer/src/components/right-sidebar/fileExplorerUndoRedo.test.ts
  • src/renderer/src/components/right-sidebar/fileExplorerUndoRedo.ts
  • src/renderer/src/components/right-sidebar/use-file-explorer-image-paste.history.test.tsx
  • src/renderer/src/components/right-sidebar/use-file-explorer-image-paste.remote.test.tsx
  • src/renderer/src/components/right-sidebar/use-file-explorer-image-paste.test.tsx
  • src/renderer/src/components/right-sidebar/use-file-explorer-image-paste.ts
  • src/renderer/src/components/right-sidebar/use-file-explorer-import-operation.ts
  • src/renderer/src/components/right-sidebar/use-file-explorer-paste-events.test.tsx
  • src/renderer/src/components/right-sidebar/use-file-explorer-paste-events.ts
  • src/renderer/src/components/right-sidebar/use-file-explorer-tree-pane-state.ts
  • src/renderer/src/components/right-sidebar/useFileExplorerImport.ts
  • src/renderer/src/i18n/locales/en.json
  • src/renderer/src/lib/app-menu-paste.test.ts
  • src/renderer/src/lib/app-menu-paste.ts
  • src/renderer/src/runtime/runtime-file-import-client.ts
  • src/renderer/src/runtime/runtime-file-import-existing-destination.test.ts
  • src/renderer/src/runtime/runtime-file-mutation-rpc.ts
  • src/renderer/src/runtime/runtime-file-upload-client.ts
  • src/shared/clipboard-image-import.ts
  • src/shared/file-mutation-capabilities.ts
  • src/shared/protocol-version.ts
  • src/shared/rpc-contract/files-mutation-params.ts
  • src/shared/runtime-upload-staging-contract.ts
  • tests/e2e/file-explorer-image-paste-browser.spec.ts
  • tests/e2e/file-explorer-image-paste-capability.spec.ts
  • tests/e2e/file-explorer-image-paste-focus.spec.ts
  • tests/e2e/file-explorer-image-paste-formats.spec.ts
  • tests/e2e/file-explorer-image-paste-history.spec.ts
  • tests/e2e/file-explorer-image-paste-paired.spec.ts
  • tests/e2e/file-explorer-image-paste-ssh.spec.ts
  • tests/e2e/file-explorer-image-paste.spec.ts
  • tests/e2e/helpers/explorer-image-paste.ts
  • tests/e2e/helpers/hidden-browser-page.ts
  • tests/e2e/helpers/image-paste-capability-probes.ts
  • tests/e2e/helpers/paired-image-paste-probes.ts
  • tests/e2e/helpers/system-image-clipboard.ts

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

📝 Walkthrough

The change adds desktop clipboard image import to the file explorer. It captures eligible clipboard pixels as PNG, stages snapshots under sender ownership, and exposes keyboard and context-menu paste actions. Imports can require an existing destination parent, with runtime capability checks for remote hosts. Successful imports integrate with explorer undo and redo. Unit and end-to-end tests cover clipboard formats, destination and host handling, ownership, cleanup, and paste behavior across local and remote runtimes.

Priority: ➖ Normal

Severity of issue fixed: Low

Merge Risk: ⚪ Minimal · up to 715c5

This change adds clipboard image paste to the Files Explorer for local, paired, and SSH destinations, including conflict-safe naming and undo/redo. No concrete defect was identified. Missing destinations fail instead of being recreated, and staged snapshots are cleaned up. The change appears ready to merge after normal checks.

Pre-merge checks: Passed 4 · Inconclusive 1

Failed Failed checks: 1 inconclusive

Check name Status Explanation Resolution
Docstring Coverage Inconclusive Docstring coverage is 22.41% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 58 functions across 50 files. (13 skipped… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Linked Issues check Passed Issue #27804 is the active direct target. The PR adds desktop Explorer paste through keyboard, app menu, and row/background menus. The implementation maps folders to themselves, files to parent folder…
Out of Scope Changes check Passed The reviewed changes remain connected to #27804. Runtime capability and existing-parent upload changes enforce the required remote safety rule. Clipboard staging, IPC authorization, cleanup, history d…
Title check Passed The title clearly and concisely describes the main change: adding clipboard image paste support to local and remote Explorer folders.
Description check Passed The description follows the required template and clearly documents the user-facing behavior, implementation, rationale, linked issue, visual proof, testing results, known limitations, AI disclosure, …
Full details: Linked Issues check

Explanation

Issue #27804 is the active direct target. The PR adds desktop Explorer paste through keyboard, app menu, and row/background menus. The implementation maps folders to themselves, files to parent folders, and background actions to the displayed root. readClipboardImageForImport rejects copied-file, non-native, empty, and unsupported clipboard content, and encodes bounded native pixels as PNG. useFileExplorerImagePaste uses the existing import path with no-clobber naming, destination checks, reveal/selection flow, and captured ownership. recordFileExplorerImagePaste implements undo and redo from the retained snapshot. Focus, format, local, paired-runtime, capability, and SSH tests cover the required behavior. Related issues #12929 and #9443 are explicitly outside this image-pixel scope.

Full details: Out of Scope Changes check

Explanation

The reviewed changes remain connected to #27804. Runtime capability and existing-parent upload changes enforce the required remote safety rule. Clipboard staging, IPC authorization, cleanup, history disposal, UI wiring, localization, and supporting tests implement the paste feature. The changes do not add generic file copy, web/mobile clipboard support, or unrelated product behavior. No unrelated change is demonstrated by the reviewed summary or focused implementation.

Full details: Description check

Explanation

The description follows the required template and clearly documents the user-facing behavior, implementation, rationale, linked issue, visual proof, testing results, known limitations, AI disclosure, review considerations, and checklist status. It also explains that the full test suite was not green locally and identifies the reported unrelated failures.

Full details: Docstring Coverage

Explanation

Docstring coverage is 22.41% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 58 functions across 50 files. (13 skipped: 1 unsupported, 12 over the file limit.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

❤️ Share

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

@marinhooodev

Copy link
Copy Markdown
Author

@coderabbitai Thanks for the review. About the one inconclusive pre-merge check (Docstring Coverage, 22.41% vs. the 80% threshold): I'm leaving it as is on purpose.

This review raised no other findings (Merge Risk: Minimal), so nothing from it is still open.

For maintainers: the GitHub Actions workflows for 715c566d (PR Checks, Mobile Checks, Headless Node server, PR test LoC) show action_required. They are waiting for approval to run because this PR comes from a fork. I'll fix anything CI turns up.

@coderabbitai

coderabbitai Bot commented Oct 12, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
fd --hidden --exclude .git '^AGENTS\.md$' . --exec sh -c 'printf "\n--- %s ---\n" "$1"; cat "$1"' sh {}

Length of output: 28811


@marinhooodev Thanks for the guidance. I checked AGENTS.md; it confirms “Concise/Brief Non-obvious Comments ONLY” and asks for why-comments, preferably one line.

I accept leaving the docstrings unchanged. Adding docstrings solely to reach 80% would not fit that guidance. The Docstring Coverage result remains below the threshold, but it does not establish a code defect.

The fork-workflow approval is separate from the review result. Based on your reported action_required status, those CI results are still pending.


✏️ Learnings added
Learnt from: marinhooodev
URL: https://github.com/stablyai/orca/pull/27806

Timestamp: 2026-10-12T18:53:20.148Z
Learning: In stablyai/orca, AGENTS.md requires concise, non-obvious comments that explain why rather than how, preferably in one line. Do not recommend blanket docstring additions solely to meet a coverage threshold when they would add obvious or verbose documentation.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

You are interacting with an AI system.

marinhooodev and others added 3 commits October 16, 2026 20:19
…-image

Port the existing-parent upload rule into the runtime file-mutations
module that replaced the per-command runtime classes (stablyai#27582), and
declare files.upload-existing-parent.v1 beside the other file-mutation
capability in runtime-capability-constants.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…reader

Explorer image paste called clipboard.readImage() directly, so a CleanShot
screenshot stored as JPEG bytes under macOS public.png pasted nothing.
Use readClipboardNativeImage, which chat paste adopted in stablyai#29685.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…name

Capability constants now live in runtime-capability-constants, so the
bundler no longer emits a protocol-version chunk for the host probe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Paste clipboard images as PNG files into Explorer folders

1 participant