Adds a lightweight self-update path to the CCS Bar menu-bar app so users are
told when a newer build is available and can update with one click.
- App: BarUpdateChecker fetches the published version.txt and compares it to
the running bundle version (numeric semver). A throttled background check
(post-launch, then every 6h) surfaces an "Update available" row in the menu;
"Update Now" spawns `ccs bar install --launch --await-quit` then quits so the
installer can swap the locked bundle and relaunch. A Settings toggle gates
the auto-check (default on). Offline checks degrade silently.
- CLI: `ccs bar install --await-quit` waits for a running CCS Bar to quit
(300ms poll, 15s cap) before swapping, enabling the one-click relaunch.
- Release: bar-release publishes a machine-readable version.txt asset beside
the app zip so the check is cheap (no full download just to compare).
- Shares the ccs-binary resolver between DashboardLauncher and the updater.
- Bumps bar VERSION to 1.8.0; adds isNewer assertions to ccs-bar-check.
Closes#1588
Codex quota in the menu bar came only from frozen local session logs, so it
showed stale data ("older session") that no refresh could update. Fetch it live
from the same source the dashboard uses, under the existing Claude-style safety
controls (10-min TTL, in-flight coalescing, 429 backoff, circuit breaker,
serve-stale), falling back to local logs when offline or rate-limited. A success
with no usable 5h/weekly window keeps the local reading rather than caching a
contentless row. The footer refresh and a new inline button on the Codex card
force a live pull past the open debounce, and a forced /summary re-pulls native
rows while serving the last-known cached rows if the live pull overruns its
budget, so the Claude/Codex cards never blank mid-refresh.
The spend strip gains a Today / 7d / 30d selector (default 7d), a taller chart,
and bottom time-axis labels (local hours for today, weekday for 7d, dates for
30d). The analytics endpoint now exposes a 24-bucket hourly series for today,
converted from the pipeline's UTC hour keys to the user's local clock so the
intra-day chart matches the dashboard.
The app now port-probes for a live CCS server and, if none is found,
starts the recorded detached server itself (launch.json, with a login-shell
fallback) before connecting, so double-clicking the app works without the
CLI. The offline panel gains a Start CCS action and a starting state. The
dropdown is sized to its measured content up to a screen-aware cap instead
of a fixed maxHeight, so it no longer collapses and clips rows.
Refs #1526, #1527
The menu only re-polled on open or after a mutation, so if the server briefly
dropped rows (e.g. a backend restart mid-session) the dropdown could stay stuck
showing stale/missing rows until reopened. Add a 60s background poll that
reconnects if the client was lost and reloads non-force (respecting server-side
caches, so it never hammers providers). As a bonus, alerts now evaluate every
interval instead of only on menu-open, making them genuinely proactive.
Narrow the dropdown (380 to 360) and give it more vertical room (620 to 700).
Tighten the subscription cards (less spacing/padding) since they carry only a
few window rows. Make the spend chart taller (18 to 30) and let the user pick
its style in Settings: chunk bars (default) or a line graph with a subtle area
fill. Persist the choice in UserDefaults.
Add a theme token system (CCSBarCore/BarTheme.swift): a BarAppearance enum
(system/light/dark, default dark to preserve the current look), light+dark
token palettes, a colorScheme-driven resolver, and a SwiftUI EnvironmentKey.
The root forces .preferredColorScheme so Light renders light even under a dark
macOS, and paints an explicit light window surface. Thread the tokens (accent,
headroom bands, subscription, card surface, track) through every view so the
whole dropdown themes consistently, with chip text blending toward black on
light. Add an appearance picker in Preferences, persisted in UserDefaults.
Dark accent/subscription values are locked byte-identical and harness-guarded;
pool-account rows now share the muted band palette for cross-section
consistency.
Add real quota gauges with threshold bands and a reset countdown for
quota-capable accounts. Introduce a pure, deterministic alert rule engine
(CCSBarCore) covering quota-remaining, daily/monthly spend caps, reauth, and
cooldown, with per-rule dedupe keys that re-arm on period rollover or
clears-then-recurs so it never spams. Deliver via UNUserNotificationCenter
with an in-dropdown Alerts fallback when notifications are denied. Add a
preferences surface (per-rule toggles, caps, quota levels, glance mode)
persisted in UserDefaults, and a configurable menu-bar glance
(auto/today/month/lowest-quota/account-count) that still never shows a
lifetime dollar. Default spend caps raised to $500/day and $10000/month.
Mirror the richer analytics payload (quotaStatus, per-account last-active,
bySurface) in the Codable models. Add a per-surface usage section (Claude
Code, Codex, Droid, CLIProxy) with proportional bars beside the existing
spend grid, sparkline, and top models. Rebuild the menu-bar title chain so a
lifetime dollar can never sit in the always-on title (it read as live spend):
quota% then today spend then account count. Rebuild the accounts rows
(default badge, tri-state quota, honest no-data cost, health), pivot to an
honest idle hero when no recent data, hide the scroll indicator, and tighten
spacing.
Send the composite provider:accountId (row.id) for Set as default so the server
can resolve the CLIProxy account; feature the account closest to exhaustion
(lowest remaining quota) in the title instead of the healthiest; rename the
packaged asset to CCS-Bar.app.zip to match what 'ccs bar install' downloads.
Menu-bar app that paints cached rows instantly and fires a debounced
force-refresh on open. Dropdown shows per-account health, quota, tier, cost and
paused state with pause/resume, set default, solo and tier-lock actions, plus an
offline state when CCS is not running.