diff --git a/README.md b/README.md index 007a78e..74e3b50 100644 --- a/README.md +++ b/README.md @@ -76,3 +76,10 @@ Date-only due inputs create all-day reminders; date-time inputs create timed rem Run `remindctl authorize` to trigger the system prompt. If access is denied, enable Terminal (or remindctl) in System Settings → Privacy & Security → Reminders. If running over SSH, grant access on the Mac that runs the command. +If no prompt appears in your terminal app, run: + +```bash +osascript -e 'tell application "Reminders" to get name of reminders' +``` + +Then allow access and rerun `remindctl status`. diff --git a/Sources/RemindCore/Errors.swift b/Sources/RemindCore/Errors.swift index db2cdb4..4c64f96 100644 --- a/Sources/RemindCore/Errors.swift +++ b/Sources/RemindCore/Errors.swift @@ -18,6 +18,8 @@ public enum RemindCoreError: LocalizedError, Sendable, Equatable { "Reminders access denied.", "Run `remindctl authorize` to trigger the prompt, then allow Terminal (or remindctl)", "in System Settings > Privacy & Security > Reminders.", + "If no prompt appears, run `osascript -e 'tell application \"Reminders\" to get name of reminders'`", + "once from the same terminal app.", "If running over SSH, grant access on the Mac that runs the command.", ].joined(separator: " ") case .writeOnlyAccess: diff --git a/Sources/remindctl/PermissionsHelp.swift b/Sources/remindctl/PermissionsHelp.swift index d43c9c4..e488eb1 100644 --- a/Sources/remindctl/PermissionsHelp.swift +++ b/Sources/remindctl/PermissionsHelp.swift @@ -2,6 +2,7 @@ import RemindCore enum PermissionsHelp { static let settingsPath = "System Settings > Privacy & Security > Reminders" + static let promptWorkaround = #"osascript -e 'tell application "Reminders" to get name of reminders'"# static func guidanceLines(for status: RemindersAuthorizationStatus) -> [String] { switch status { @@ -15,6 +16,7 @@ enum PermissionsHelp { case .denied, .restricted: return [ "Grant access in \(settingsPath) for Terminal (or remindctl).", + "If no prompt appears, run `\(promptWorkaround)` once from the same terminal app.", "If running over SSH, grant access on the Mac that runs the command.", ] case .writeOnly: diff --git a/Tests/remindctlTests/PermissionsHelpTests.swift b/Tests/remindctlTests/PermissionsHelpTests.swift new file mode 100644 index 0000000..81642ea --- /dev/null +++ b/Tests/remindctlTests/PermissionsHelpTests.swift @@ -0,0 +1,14 @@ +import Testing + +@testable import RemindCore +@testable import remindctl + +@MainActor +struct PermissionsHelpTests { + @Test("Denied guidance includes terminal prompt workaround") + func deniedGuidanceIncludesPromptWorkaround() { + let guidance = PermissionsHelp.guidanceLines(for: .denied).joined(separator: "\n") + #expect(guidance.contains("osascript")) + #expect(guidance.contains("Reminders")) + } +}