Commit Graph
8 Commits
Author SHA1 Message Date
rune aaeaeddafb Fix i18n gaps in Mail integration; correct stale beta-bug messaging
Localize mailAccessNote and AppleMailService's account-count string
(was a manual singular/plural literal, now uses inflect syntax). Also
correct the requestAccess() doc comment and the suspectedPlatformBug
fallback message, both of which still asserted "known macOS 27 beta
issue" — that diagnosis was wrong (see 6b4448d): the real cause was a
missing entitlement, already fixed. The instant-failure heuristic stays
as a defensive fallback, just no longer misattributed.
2026-08-26 12:58:16 +02:00
rune 1dc485badb Fall back to System Settings when the Mail consent prompt is the known beta bug
Confirmed via multiple live rounds with Rune this is a macOS 27 beta issue,
not a Confab bug — matches an already-documented pattern in this project
(Calendar/Contacts requestAccess failing identically). Every failure
returns in single-digit milliseconds, ruled out threading, wrong API,
build/signing, and notarization; even a fresh notarized build fails
identically, while Terminal->Mail (first-party) works with no prompt at
all, and the same-style bug already has a drafted Apple Feedback report
for a different permission category.

Kept the real Apple Event attempt as the primary path (the way this
should work once the OS bug is fixed), but now time it: a failure faster
than any human could plausibly answer a real dialog (default 300ms) is
classified as the platform bug rather than a genuine denial, and the UI
falls back to opening System Settings' Automation pane directly with an
explanatory note, instead of the button silently doing nothing.
2026-08-19 14:55:24 +02:00
rune 56a5d1d56f Trigger the Mail consent prompt via a real Apple Event, not the pre-flight API
Rune's log capture proved the theory wrong: AEDeterminePermissionToAutomate-
Target(askUserIfNeeded: true) returned -1743 in ~9ms — far too fast for any
real dialog to have been shown and answered — and the very next passive
status check still reported -1744 (not yet determined), meaning the OS
never actually recorded a decision despite the "denied" return. That's the
pre-flight API misbehaving, not a threading issue (both previous fixes
addressed threading and neither helped).

requestAccess() now attempts a real, harmless Apple Event (listAccounts)
via the same runHandler path mail_list_accounts/testConnection() already
use — sending an actual Apple Event is the standard, proven mechanism for
triggering macOS's first-time Automation consent prompt, and this path is
already confirmed working (it's what correctly reported "not authorized"
in the first live test).
2026-08-19 14:30:16 +02:00
rune 56d49d7854 Dispatch the Mail permission prompt via DispatchQueue.main.async, not implicit MainActor isolation
Previous fix assumed being MainActor-isolated inside an async method was
equivalent to a classic synchronous AppKit call — it wasn't; Rune
confirmed live it still did nothing (no dialog, no state change, even
after a clean tccutil reset). AEDeterminePermissionToAutomateTarget is a
blocking, modal-dialog-presenting legacy API and needs to run from a
genuine DispatchQueue.main.async dispatch to correctly nest its own run
loop, not from inside a suspended Task continuation frame. Added extra
Log.mail checkpoints (call received / about to call AE / result) so the
next attempt has real data to diagnose from either way.
2026-08-19 14:20:30 +02:00
rune da7bce26a2 Fix Request Access button doing nothing: run permission prompt on main thread
requestAccess() was dispatched onto the background queue used for
AppleScript execution, on the assumption that a blocking call needed to
be off-main. That's backwards for AEDeterminePermissionToAutomateTarget's
consent dialog — like this app's existing NSAlert.runModal() calls, it
needs to run on the main thread/run loop to actually display. Off-main,
it silently returned without ever showing a prompt or changing state.

Also added Log.mail diagnostics on both the status-only check and the
prompting call so a future report of "still doesn't work" has an actual
status code to look at instead of starting from scratch.
2026-08-19 14:13:56 +02:00
rune 21d598d88a Add a real permission prompt/status for Mail access, matching Personal Data
Settings previously only surfaced an error message after a failed Test
Connection attempt — there was no way to trigger the actual macOS
Automation permission dialog or see live grant/deny status, unlike
Calendar/Contacts/Reminders/Location.

AEDeterminePermissionToAutomateTarget (askUserIfNeeded: false/true) turns
out to provide exactly that: a non-prompting status check and an explicit
prompt-and-wait call, mirroring EKEventStore.authorizationStatus(for:)/
requestFullAccessToEvents(). Mail's Settings row now uses the same
personalDataRow component as Calendar/Contacts — live status badge plus
a real "Request Access" button — instead of a one-off Test-Connection-only
UI. Test Connection stays as a secondary functional check.
2026-08-19 14:01:29 +02:00
rune cf82720b88 Fix Sendable warning in AppleMailError by dropping the NSDictionary payload
appleScriptError carried the raw NSDictionary from NSAppleScript's error
out-param, which isn't Sendable and got flagged once the type crossed an
async boundary. Extract just the two fields actually used (errorNumber,
errorMessage) into plain Int/String instead.
2026-08-19 13:53:06 +02:00
rune 4064851a3d Add Mail integration: search, read, and save attachments via AppleScript
Lets the AI search Apple Mail, read a message, and save an attachment to
disk (e.g. to hand off to paperless_upload_document) — e.g. "find the
receipt from Elkjøp and add it to Paperless." Talks to Mail.app via
AppleScript/Apple Events rather than parsing its private on-disk store,
so no Full Disk Access or MIME parsing is needed; Mail's own attachment
save handles all decoding. Every mail_* tool call requires approval
(Deny/Allow Once/Allow for Session), mirroring the bash_execute and
Personal Data gate pattern.

Also fixes a pre-existing bug found while touching the adjacent
tool-activation condition: paperlessEnabled was missing from it, so
Paperless tools could fail to activate unless another integration was
also active.
2026-08-19 13:47:38 +02:00