v0.10.2 — Permission UX & TCC stability
Pre-release
Pre-release
Permission UX & TCC stability
A user-reported pain point: every Sparkle upgrade felt like macOS was clearing the app's Accessibility grant — translate hotkeys went silent until you manually re-granted, with no in-app surface telling you what happened.
v0.10.2 fixes the user experience and hardens the signature so the underlying TCC issue is much less likely to recur in the first place.
Added — Auto-recovery onboarding
- Permission-loss detection on launch —
AppDelegatereads the persistedlastKnownAccessibilityGrantedflag before refreshing the live grant, so the true→false transition that signals a TCC reset is detectable. When detected, the onboarding window pops automatically in recovery mode with copy that acknowledges you already did this once. OnboardingMode.permissionRecoveryswaps the title + intro: "Welcome back. macOS cleared the app's Accessibility grant after the recent update — translate hotkeys are silent until you re-grant. Click Request below, or Open Settings if the prompt does not appear."- Hotkeys still register in recovery mode so any grants that survived (e.g. Input Monitoring) keep working — the onboarding pops on top so the issue cannot be missed.
Hardened — Codesign stability
--identifier "app.lookerlab.translator"is now passed explicitly to the main-appcodesigncall instead of being inferred fromCFBundleIdentifier. The value baked into the signature is byte-stable across releases. Verified post-build: v0.10.0, v0.10.1, and v0.10.2 all sign with byte-identical designated requirements, so TCC should persist the grant across upgrade.
Internal — PermissionManager testability
- Constructor accepts injected
accessibilityProbe/inputMonitoringProbe/requestAccessibilityAction/requestInputMonitoringActionclosures so unit tests exercise grant-sync wiring without touching the real TCC database. refresh()writes the live grant back toSettingsStore.lastKnownAccessibilityGranted(guarded bydidSetso the 1-second polling loop does not spam UserDefaults).refreshLater()settle delay bumped 1s → 2s — gives the TCC database room after the user clicks "Allow".
Tests
- +11 new tests — 6 in
PermissionManagerTests(grant-sync, init non-mutation, request action, nil-settings), 5 inLaunchRecoveryDecisionTreeTests(fresh / steady / revoked / never-granted / lost-then-regranted). - 388 tests pass (was 377).
Risk-free upgrade
UserDefaults adds one new key (translator.lastKnownAccessibilityGranted) defaulting to false on existing installs — so the recovery flow does not fire spuriously on the v0.10.1 → v0.10.2 upgrade itself. The first refresh writes the current live state forward; from v0.10.3 onwards the recovery signal is armed end-to-end.
Install
- Sparkle — existing installs receive this automatically via the appcast at
https://hoangperry.github.io/hp-translator/appcast.xml. - Fresh install — download
Contextual-Mac-Translator-v0.10.2-macos-arm64.zipbelow, unzip, drag the.appto/Applications. Signed (Developer IDJP4XV8A9JF) + notarized + stapled.
Apple Silicon only. macOS 14 or later.