Skip to content

Paste restore: save every clipboard type, not just the string coercion (#432) - #458

Open
Nabzx wants to merge 1 commit into
mainfrom
paste-clipboard-restore-432
Open

Nabzx wants to merge 1 commit into
mainfrom
paste-clipboard-restore-432

Conversation

@Nabzx

@Nabzx Nabzx commented Sep 26, 2026

Copy link
Copy Markdown
Owner

Closes #432. Fixes a real data-loss bug in the paste-delivery rung, not a hypothetical one.

The bug

RealClipboardPaster.paste (rung 2 of delivery - used whenever a direct AX write isn't possible or fails verification, the common path for browsers, terminals, many Electron apps) borrows the clipboard for the dictated text, then restores whatever was there before. It only ever saved pasteboard.string(forType: .string). Anything without a plain-string representation - a copied image, a Finder file reference, anything with no .string type - made that come back nil. After the paste, the restore branch never fired, so the pasteboard was left cleared instead of restored: the user's original clipboard content silently and permanently gone.

The existing race guard (skip restore if changeCount moved - added for #62) is a different protection and is untouched by this fix.

The fix

Saves the full pasteboard item set before borrowing it - every type on every NSPasteboardItem, not just the string coercion - and restores by writing fresh NSPasteboardItems built from that saved data. A copied image, a file reference, or anything else with a non-string representation now survives a dictation the same way plain text already did.

Tests

No unit test: RealClipboardPaster talks to the real NSPasteboard.general and has no existing test coverage (the fake used elsewhere covers InjectionEngine's call site, not this adapter). swift build --package-path native/accessibility-helper is clean. Manual checklist in docs/testing/clipboard-restore-432.md - needs a real Mac to actually exercise, same constraint as the other native-helper fixes this session (#137, #433).

🤖 Generated with Claude Code

#432)

RealClipboardPaster only ever saved pasteboard.string(forType: .string)
before borrowing the clipboard for the dictated text. A copied image or
a Finder file reference has no plain-string representation, so that
came back nil - after the paste, the restore branch never fired and
the user's original clipboard content was left cleared, not restored.

Now saves the full item set (every type on every NSPasteboardItem) and
writes it all back on restore. The existing changeCount race guard -
skip the restore if the user copied something else while it was
borrowed - is unchanged.

Compile-verified only (swift build is clean); real NSPasteboard
behaviour needs a Mac, checklist in docs/testing/clipboard-restore-432.md.

Claude-Session: https://claude.ai/code/session_0144sxo5CJiyk99vaR7sgjuj
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.

Paste-based delivery permanently destroys any non-text clipboard content

1 participant