mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
* fix(macos): add a Full Disk Access nudge to reduce recurring TCC prompts (#9756) macOS shows the "Orca wants to access other apps' data" (kTCCServiceSystemPolicyAppData) prompt and it can keep reappearing. The reappearing loop is not a fixable app bug: it is TCC identity churn — an unsigned local rebuild mints a new code identity each build, so macOS treats each as a new app — and Orca's other-app reads are already gated behind opt-in settings or explicit user actions. The durable remedy for the population we can help (release users) is Full Disk Access, a superset macOS grant that stops these prompts for a stable identity. Surface it with an ambient, dismissable sidebar card that reuses the existing developer-permissions IPC. macOS-only; probes FDA status at most once per renderer session (the probe itself reads protected data, so it must not repeat on focus/remount); "Open System Settings" opens the Full Disk Access pane; permanent localStorage dismissal. * fix(macos): stop the FDA nudge promising macOS will stop asking The card said Full Disk Access makes "macOS stop asking", but the grant covers this app while terminals are spawned by the detached PTY daemon (daemon-init.ts forks execPath with ELECTRON_RUN_AS_NODE + detached:true, reparented to launchd), which macOS treats as its own TCC identity. A user who followed the card would grant FDA and still be prompted from terminals. Scope the claim to reducing prompts and name the terminal caveat. * fix(macos): drop stale focus refreshes in the FDA nudge refreshFullDiskAccessStatus() applied whichever getStatus() round-trip resolved last. Rapid blur/focus puts several in flight, so an earlier pre-grant 'unknown' landing after a newer 'granted' un-hid the card and also wrote 'unknown' into the module-level session cache, re-nagging a user who already has Full Disk Access for the rest of the session. The adjacent FullDiskAccessSetupPrompt already guards this with a refresh sequence; mirror it here. Also unmount React roots in afterEach: clearing document.body left them mounted, leaking each test's window focus listener into later tests. * test(macos): unmount the StrictMode FDA nudge root between tests The afterEach unmount added in5a0f717only covers roots created through renderNudge(). The StrictMode probe test builds its own root, so it was never unmounted and its component stayed live for the rest of the file. Today that component has no window focus listener, so nothing breaks; add a CTA click to it and the same contamination5a0f717fixed comes back — the two tests after it see extra getStatus() calls and fail. Register the root so the fix covers every mount site. * fix(macos): attribute the FDA prompts to agent activity, not Orca's own reads The card said the prompts happen "when this copy of Orca reads protected app data", but Orca's own reads are small and gated; #9756's trigger is agent find/grep sweeps into ~/Library/Containers, which macOS bills to Orca because Orca is the responsible process for every terminal child. Blaming Orca reads as an accusation and hid why FDA works at all — the grant attaches to Orca rather than to each churning child binary. Name agents as the trigger, keep the "reduce" hedge and the terminal caveat, and drop the "this copy of Orca" dev-build hedge that cost a clause. Assert the causation wording so it can't silently regress. * fix(macos): explain the TCC prompts on the settings row, drop the sidebar card The sidebar nudge added in344d466bwas premised on FDA being reachable "only inside onboarding". It isn't: Settings > macOS Permissions has had a full-disk-access row all along (searchable), the Setup Guide hosts the same prompt from both a settings pane and a re-openable modal, and the sidebar already links to that modal via the "Onboarding checklist" entry. The card added a fifth affordance to the same sidebar that already had the fourth, so it bought prominence rather than access - shown to every macOS user without FDA, most of whom never hit #9756. Keep the part that was actually new. The settings row still described the prompts as something projects and worktrees trigger, which is the same misattribution the card carried: the reads come from the agents Orca runs, and macOS names Orca only because it is the responsible process for every terminal child. It also never mentioned that the grant has to cover Orca Helper, or that the preserved daemon keeps stale TCC state until restart. Non-English catalogs get the English string as a placeholder; the bootstrap translators key their cache on the English value, so a changed string is re-translated on the next run. * feat(macos): nudge Full Disk Access only after macOS repeatedly prompts The FDA hint is only worth showing to users macOS is actually prompting. tccd emits one AUTHREQ_PROMPTING line per consent dialog it displays, carrying the service and both identities, so a narrow log-stream predicate detects the real thing without correlating across lines or guessing whether a dialog appeared. Verified against a captured dialog: the predicate matched 1 line out of 1436 TCC lines in ~28s, because routine preflight checks - the overwhelming majority of TCC traffic - do not emit it. Count dialogs where Orca is the responsible process, persist across launches, and tell the renderer on the third one. The event separates the accessing binary from the responsible app, which is the crux of #9756, so the toast can name the tool that triggered it rather than blaming Orca generically. One toast per user, with a permanent opt-out; it deep-links to the FDA row in Settings > macOS Permissions rather than restating the guidance. macOS-only: the watcher no-ops elsewhere, the web client stubs the API, and the child is killed on before-quit since log stream ignores a closed stdout. * test(macos): pin the platform so the TCC watcher tests exercise the darwin path start() is darwin-gated, so on Linux CI it no-opped and the stream/kill assertions passed vacuously against a watcher that never spawned. Pin process.platform per the existing convention (shared/secure-file.test.ts), and cover the gate itself with an explicit non-darwin case. * fix(macos): start the TCC watcher from app bootstrap, not the window wiring attachMainWindowServices is called directly by its own unit test, so wiring initTccPromptNotice there made `vitest src/main/window/` spawn real `log stream` children that outlived the run - two orphaned watchers were left behind by a single test session. Only the IPC handler registration stays there; the spawn moves to the real app bootstrap in index.ts, which tests never execute. Verified: running the suite that leaked now leaves the watcher count unchanged. * fix(macos): clarify repeated permission notice * fix(macos): keep TCC notice lifecycle safe * fix(macos): retain pending TCC notice delivery * fix(macos): acknowledge TCC notice delivery * fix(macos): release failed TCC notice claims * fix(macos): retry transient TCC notice display * fix(macos): contain TCC notice IPC failures * fix(macos): harden TCC notice renderer lifecycle * fix(macos): contain TCC notice dismissal failures * test(macos): satisfy promise executor lint * fix(macos): detect helper-attributed TCC prompts * fix(macos): align TCC watcher lifecycle and helper identity * perf(macos): defer TCC log reader until first paint * fix(macos): recover deferred TCC watcher startup * fix(macos): recover TCC watcher from deferred quit * fix(macos): localize recurring file access notice * fix(macos): preserve TCC watcher and localized guidance * fix(macos): avoid duplicate TCC watcher recovery * fix(macos): wait for locale before TCC notice * perf(macos): isolate TCC notice subscriptions --------- Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>