Skip to content

Stop a text clipboard from being mistaken for a copied file - #1179

Merged
edwin-zvs merged 1 commit into
mainfrom
ssh-clipboard-text-paste
Aug 2, 2026
Merged

Stop a text clipboard from being mistaken for a copied file#1179
edwin-zvs merged 1 commit into
mainfrom
ssh-clipboard-text-paste

Conversation

@edwin-zvs

Copy link
Copy Markdown
Contributor

Problem

Paste over the ssh clipboard bridge (construct ssh <host>) failed for any ordinary text. Reported from a macOS→macOS pair; reproduced against a live bridge socket:

COPY  -> {'ok': True}
PASTE -> {'ok': False, 'error': 'stat copied file /construct-bridge-test-OK'}

Note the error echoes back the exact text that had just been copied — copy was fine, only paste was broken.

Cause

The pasteboard is read richest-type-first (image → file → text). The file probe decided "this is a file" by asking AppleScript to coerce the clipboard with as «class furl», on the assumption that the coercion fails when no file URL is present.

It doesn't. macOS reinterprets plain text as an HFS filename at the startup disk root:

clipboard contents furl coercion exit
3k tokens /3k tokens 0
hello world /hello world 0
some/relative path /some:relative path 0

The probe then stat'd that bogus path, failed, and propagated the error with ? — aborting the paste before the pbpaste text fallback three lines below could ever run.

Fix

  • Ask the pasteboard which flavors it holds rather than inferring the type from a successful conversion. clipboard info reports «class furl», 24 for a real Finder file copy and only text flavors («class utf8», …) for text. This is the actual fix.
  • Degrade a failed stat to Ok(None) instead of propagating, so a speculative probe can never deny the user a paste it was only guessing about.

Deployment note

The clipboard agent runs inside construct ssh on the machine the user is physically at — not on the remote host. This fix has to ship to the local machine to take effect.

Testing

  • Added clipboard_info_distinguishes_copied_file_from_plain_text, using verbatim clipboard info output captured from macOS for both the text and the real-file case. This function previously had zero coverage.
  • cargo test -p construct-cli clipboard — 17 passed, 0 failed.
  • cargo clippy -p construct-cli --all-targets — no warnings from the changed file.

Spec

Updated specs/0098-ssh-clipboard-bridge.md with the reusable rule this establishes: richest-type-first probes are speculative and must fall through rather than propagate, and type detection must ask which flavors the pasteboard holds rather than infer from a successful coercion.

🤖 Generated with Claude Code

Paste over the ssh clipboard bridge failed for any ordinary text. The
pasteboard is read richest-type-first — image, then file, then text — and
the file probe decided "this is a file" by asking AppleScript to coerce
the clipboard with `as «class furl»`. That coercion does not fail on
plain text: macOS reinterprets the text as an HFS filename at the startup
disk root, so a clipboard holding `3k tokens` coerces to the path
`/3k tokens`, exit status 0. The probe then stat'd that path, failed, and
propagated the error, which aborted the whole paste before the text
fallback could run. Every text paste through the bridge died as
`stat copied file /<whatever was on the clipboard>`.

Ask the pasteboard which flavors it actually holds instead of inferring
the type from a successful conversion: `clipboard info` reports
`«class furl», 24` for a real Finder copy and only text flavors for text.
Also degrade a failed stat to "not a file" rather than propagating it, so
a speculative probe can never deny the user a paste it was only guessing
about.

The agent that runs this code lives in `construct ssh` on the machine the
user is sitting at, so the fix has to be deployed there, not on the
remote host.
@edwin-zvs
edwin-zvs merged commit 98ffda5 into main Aug 2, 2026
1 check passed
@edwin-zvs
edwin-zvs deleted the ssh-clipboard-text-paste branch August 2, 2026 23:51
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.

1 participant