Recallyx 0.82
Prompt for Accessibility when a paste can't synthesize ⌘V (#69)
Symptom
Users reported paste silently failing after a re-sign or a fresh DMG
install: selecting a clip and hitting ↵ set the clipboard but nothing
pasted, with no feedback, and the app never re-added itself to the
Accessibility list.
Root cause
Paste works by synthesizing ⌘V via CGEvent.post, which requires
Accessibility permission. Only the ⌃⇧V "transform selection" path
checked/prompted for trust (accessibility.ensureTrustedOrPrompt()).
The three plain-paste paths never checked — so when the grant was absent
or stale (re-signing / a fresh ad-hoc DMG strips it), the clipboard was
still written but the synthesized ⌘V was dropped by the OS. Zero
feedback, no re-prompt.
Fix
Gate every synthesized-⌘V paste on Accessibility via a new
AppDelegate.ensurePasteTrusted():
- Trusted → proceed with the synth as before.
- Untrusted → prompt once/session (the existing modal) plus a
notification on every attempt (so repeated tries still surface), and
always leave the clip on the clipboard so a manual ⌘V is the working
fallback.
Wired into all three synth-⌘V sites:
paste(_:into:)(history-clip paste) — clipboard already set +
markSelfWrite()'d; gate right beforeactivateAndPaste.typeLines(_:into:)(paste-as-lines) — itsPaster.typeText
snapshots and restores the clipboard at the end, so a dropped synth
would leave nothing pasteable. When untrusted it degrades to a plain
clipboard set (+markSelfWrite) and prompts, so the whole clip stays
for a manual ⌘V.- Action-result paste — split
Paster.pasteTextinto
setClipboardText+ gate +activateAndPasteso the result lands on
the clipboard even when untrusted. NomarkSelfWritehere (action
results intentionally re-enter history as a fresh top clip).
Behavior-preserving vs.pasteTextwhen trusted.
Also broadened the Accessibility alert copy to lead with pasting clips
(⌘⇧V) rather than only ⌃⇧V.
Verification
./scripts/bundle.shbuilds clean../scripts/test.sh— all 353 tests pass. The paste paths are
AppKit/AX-bound and attended-verified per repo convention; no brittle
AXIsProcessTrustedtests added.