Skip to content

Latest commit

 

History

History
125 lines (105 loc) · 6.67 KB

File metadata and controls

125 lines (105 loc) · 6.67 KB
summary WidgetKit snapshot pipeline + visibility troubleshooting for CodexBar widgets.
read_when
Modifying WidgetKit extension behavior or snapshot format
Debugging widget update timing
Widget gallery shows no CodexBar widgets

Widgets

Snapshot pipeline

  • WidgetSnapshotStore writes compact JSON snapshots to the app-group container.
  • Widgets read the snapshot and render usage/credits/history states.
  • The app writes snapshots after the main refresh pipeline and token-usage refreshes; narrow single-provider refresh paths may wait for the next snapshot write.
  • Scheduled provider refreshes trigger regular token/cost refreshes; the token/cost TTL determines eligibility when that refresh runs. Timer-driven local-history refreshes have a 15-minute minimum (30 minutes in low-power mode). Manual disables the recurring refresh timer, not all scan activity: startup refreshes and pending Codex catch-up can still scan local history. The floor limits repeated local-history work and extra WidgetKit reload requests without changing provider usage/status freshness or the user-selected provider refresh cadence.
  • Claude local cost/token history remains eligible for widget snapshots when its account does not expose numeric session or weekly quota data.
  • Claude Usage widgets can show each known model-scoped weekly quota after the normal Session, Weekly, and Opus rows. This includes Fable when Claude exposes it. The rows are opt-in via Preferences → Providers → Claude → Show model-specific weekly usage in widgets; the setting is off by default and does not affect fetching or other CodexBar surfaces. Turning it off also removes scoped rows kept from an earlier snapshot, including while no fresh Claude quota data is available.
  • If no snapshot is available, widgets fall back to preview/empty data.

Tests must opt into snapshot persistence with an in-memory save override or a test-owned snapshot URL. Neither opt-in reloads WidgetKit timelines. Production still awaits the file save before requesting a reload; the save/reload helper accepts an explicit test-mode decision and reload callback so tests can verify that ordering with temporary files and a fake callback, without changing process-wide test isolation. The per-store reload callback also lets persistence integration tests count reload attempts without calling WidgetKit.

Extension

  • Sources/CodexBarWidget contains timeline + views.
  • WidgetExtension/CodexBarWidgetExtension.xcodeproj builds those sources as the packaged macOS WidgetKit app extension.
  • Keep data shape in sync with WidgetSnapshot in the main app.

Widget types

  • CodexBar Switcher (CodexBarSwitcherWidget): static provider switcher widget, small/medium/large.
  • CodexBar Usage (CodexBarUsageWidget): configurable provider usage widget, small/medium/large.
  • CodexBar History (CodexBarHistoryWidget): configurable usage-history chart, medium/large.
  • CodexBar Metric (CodexBarCompactWidget): compact credits/today-cost/30-day-cost widget, small only.
  • CodexBar Burn Down (CodexBarBurnDownWidget): configurable session or weekly burn-down chart, medium only.
  • CodexBar Burn Down (Combined) (CodexBarCombinedBurnDownWidget): session and weekly burn-down charts, medium only.

Switcher widgets share one remembered provider selection, so switching one updates all Switcher widgets. To keep Claude and Codex visible side by side, add two CodexBar Usage widgets and configure each widget's Provider separately. Usage widgets read their own configured provider instead of the shared Switcher selection.

Provider picker support

The configurable provider widgets currently expose: Codex, Claude, Cursor, Gemini, Alibaba, Antigravity, z.ai, Copilot, MiniMax, Kilo, OpenCode, and OpenCode Go.

Providers without a ProviderChoice case can still be present in the app snapshot, but they are not selectable from the widget configuration UI yet.

Burn-down widgets currently support Codex and Claude. Their dedicated configuration intents keep existing Usage and History widget configurations unchanged.

Visibility troubleshooting (macOS 14+)

When widgets do not appear in the gallery at all, the issue is almost always registration, signing, or daemon caching (not SwiftUI code).

1) Verify the extension bundle exists where macOS expects it

APP="/Applications/CodexBar.app"
WAPPEX="$APP/Contents/PlugIns/CodexBarWidget.appex"
WIDGET_ID="com.steipete.codexbar.widget" # debug builds use com.steipete.codexbar.debug.widget

ls -la "$WAPPEX" "$WAPPEX/Contents" "$WAPPEX/Contents/MacOS"

2) PlugInKit registration (pkd)

pluginkit -m -p com.apple.widgetkit-extension -v | grep -i codexbar || true
pluginkit -m -p com.apple.widgetkit-extension -i "$WIDGET_ID" -vv

Notes:

  • + = elected to use, - = ignored (PlugInKit elections).
  • If missing or ignored, force-add and re-elect:
pluginkit -a "$WAPPEX"
pluginkit -e use -p com.apple.widgetkit-extension -i "$WIDGET_ID"
  • Check for duplicates (old installs or version precedence):
pluginkit -m -D -p com.apple.widgetkit-extension -i "$WIDGET_ID" -vv

If multiple paths appear, delete older installs and bump CFBundleVersion.

3) Code signing + Gatekeeper assessment

Widgets are loaded by system daemons. Any signing failure can hide the widget.

codesign --verify --deep --strict --verbose=4 /Applications/CodexBar.app
codesign --verify --strict --verbose=4 "$WAPPEX"
codesign --verify --strict --verbose=4 "$WAPPEX/Contents/MacOS/CodexBarWidget"
spctl --assess --type execute --verbose=4 /Applications/CodexBar.app

4) Restart the right daemons (NotificationCenter alone is not enough)

killall -9 pkd || true
sudo killall -9 chronod || true
killall Dock NotificationCenter || true

5) Watch logs while opening the widget gallery

log stream --style compact --predicate '(process == "pkd" OR process == "chronod" OR subsystem CONTAINS "PlugInKit" OR subsystem CONTAINS "WidgetKit")'

6) Packaging sanity checks

  • Widget bundle id should be com.steipete.codexbar.widget for release and com.steipete.codexbar.debug.widget for debug.
  • NSExtensionPointIdentifier must be com.apple.widgetkit-extension.
  • Bundle folder name should match: CodexBarWidget.appex.

Optional: re-seed LaunchServices (rarely helps, but low risk):

/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -seed

Common post-visibility issue: stale data

If the widget appears but always shows preview data:

  • App writes snapshot to fallback path while widget reads app-group container.
  • Validate that both app and widget resolve the same app-group container.

See also: docs/ui.md, docs/packaging.md.