sketchybar: surface meetingbar calendar failures
When sketchybar runs as an AeroSpace child rather than under launchd,
EventKit denies calendar access and the plugin rendered a blank label
indistinguishable from having no meetings.

Assisted-by: Claude Opus 5 via Claude Code
change mkotvlwtntzxolpxumnuusnzptwsrlkl
commit b5bd1a59edff439dd97da054512bc50cbe30a7c7
author Alpha Chen <alpha@kejadlen.dev>
date
parent vsnzpsns
diff --git a/.config/sketchybar/meetingbar.swift b/.config/sketchybar/meetingbar.swift
index 25fae198..7aee288f 100755
--- a/.config/sketchybar/meetingbar.swift
+++ b/.config/sketchybar/meetingbar.swift
@@ -53,15 +53,20 @@ class MeetingBar {
         case .authorized, .fullAccess, .writeOnly:
             self.init(calendarTitle: calendarTitle, eventStore: eventStore)
         case .denied:
-            throw MeetingBarError(message: "Calendar access denied")
+            throw MeetingBarError(
+                message: "Calendar access previously denied for this process. "
+                    + "Grant it in System Settings > Privacy & Security > Calendars.")
         case .restricted:
-            throw MeetingBarError(message: "Calendar access restricted")
+            throw MeetingBarError(message: "Calendar access restricted by policy")
         case .notDetermined:
             let semaphore = DispatchSemaphore(value: 0)
             var accessGranted = false
 
+            var requestError: Error?
+
             eventStore.requestFullAccessToEvents { granted, error in
                 accessGranted = granted
+                requestError = error
                 semaphore.signal()
             }
 
@@ -70,7 +75,9 @@ class MeetingBar {
             if accessGranted {
                 self.init(calendarTitle: calendarTitle, eventStore: eventStore)
             } else {
-                throw MeetingBarError(message: "Calendar access denied")
+                let detail = requestError.map { ": \($0.localizedDescription)" } ?? ""
+                throw MeetingBarError(
+                    message: "Calendar access request was not granted\(detail)")
             }
         @unknown default:
             throw MeetingBarError(message: "Unknown authorization status")
diff --git a/.config/sketchybar/plugins/meetingbar.sh b/.config/sketchybar/plugins/meetingbar.sh
index 697a1efd..c236d5fd 100755
--- a/.config/sketchybar/plugins/meetingbar.sh
+++ b/.config/sketchybar/plugins/meetingbar.sh
@@ -1,8 +1,15 @@
 #!/bin/sh
 
 CALENDAR=
-JSON=$("$CONFIG_DIR/meetingbar.swift" "$CALENDAR")
+
+# On failure the swift script prints nothing, so jq emits no output and the
+# `//` default never fires — leaving a blank label that looks like a working
+# plugin with no meetings. Surface it instead; stderr lands in sketchybar's log.
+if ! JSON=$("$CONFIG_DIR/meetingbar.swift" "$CALENDAR"); then
+    sketchybar --set "$NAME" label="calendar unavailable"
+    exit 1
+fi
 
 DISPLAY=$(echo "$JSON" | jq -r '.primary.display // "No meetings"')
 
-sketchybar --set "$NAME" label="$DISPLAY"
+sketchybar --set "$NAME" label="${DISPLAY:-No meetings}"
diff --git a/.config/sketchybar/plugins/meetingbar_click.sh b/.config/sketchybar/plugins/meetingbar_click.sh
index 52ff76f2..c3a20063 100755
--- a/.config/sketchybar/plugins/meetingbar_click.sh
+++ b/.config/sketchybar/plugins/meetingbar_click.sh
@@ -11,7 +11,15 @@ if [ "$BUTTON" = "right" ]; then
         exit 0
     fi
 
-    JSON=$("$CONFIG_DIR/meetingbar.swift" "$CALENDAR")
+    if ! JSON=$("$CONFIG_DIR/meetingbar.swift" "$CALENDAR"); then
+        sketchybar --remove '/meetingbar\.popup\./' 2>/dev/null
+        sketchybar --add item meetingbar.popup.0 popup.meetingbar \
+                   --set meetingbar.popup.0 \
+                         icon.drawing=off \
+                         label="Calendar unavailable — check sketchybar's log" \
+                   --set meetingbar popup.drawing=on
+        exit 1
+    fi
 
     PINNED_ID=""
     if [ -f "$PIN_FILE" ]; then
@@ -63,7 +71,7 @@ if [ "$BUTTON" = "right" ]; then
     sketchybar --set meetingbar popup.drawing=on
 else
     # Left click: open the displayed event's meeting URL.
-    JSON=$("$CONFIG_DIR/meetingbar.swift" "$CALENDAR")
+    JSON=$("$CONFIG_DIR/meetingbar.swift" "$CALENDAR") || exit 1
     URL=$(echo "$JSON" | jq -r '.primary.url // empty')
 
     if [ -n "$URL" ]; then