10 Commits
Author SHA1 Message Date
Tam Nhu Tran b9f6837913 fix(bar): lead carousel with default account, label it as the base command
Address UX review: the bare login (e.g. ~/.codex) is the default way of running a
surface, not a profile. Rename it from 'personal' to 'default' and present it as
the base command ('ccsx') with a 'default' badge, while named profiles show their
name ('ck') plus the owning surface tag ('ccsx'). Order each provider carousel so
the default account leads, then by tightest quota window.
2026-06-23 23:10:15 -04:00
Tam Nhu Tran e8adcb8999 feat(bar): per-provider profile carousel with ccs/ccsx surface tags
Group native subscription rows by provider and render each provider as its own
horizontally paged carousel of profile cards (one profile per page, swipe
between a provider's profiles, page dots indicate count). Add a surface tag
chip (ccs/ccsx) and dim parked profiles. Switch the native-vs-pool split to the
is_subscription flag so pool codex accounts are not misclassified. Raise the
deployment target to macOS 14 for the native scroll paging APIs and bump the
Bar version to 1.9.0.
2026-06-23 22:56:48 -04:00
Tam Nhu Tran 6ed5b2d62b feat(bar): live Codex usage sync with force refresh and spend-chart periods
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.
2026-06-20 18:37:18 -04:00
Tam Nhu Tran 7d3a11a452 fix(bar): resolve pre-dev review findings (security gate, honesty, correctness)
Gate /api/bar/* behind the localhost-when-auth-disabled guard (single DRY
choke point) so native quota/tier/cost can't leak on a non-loopback bind with
auth disabled; add a guard test. Delete the dishonest maxRedirections test that
asserted the opposite of the production redirect hardening. Key per-account
today-cost on the local day (matching analytics) instead of UTC. Stop the
inner 429 retry in the Claude usage fetch so the outer cache + circuit breaker
honor Retry-After. Narrow the usage-transformer map type and fix stale
doc-comments; clarify the one-alert-per-reset-window quota rule; gitignore the
local demo scaffolding.
2026-06-09 18:04:31 -04:00
Tam Nhu Tran 0b1c4e4908 feat(bar-app): tune density and add spend chart style toggle
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.
2026-06-09 17:06:33 -04:00
Tam Nhu Tran b950b41503 fix(bar-app): settings as standalone window, real theme forcing, roomier layout
Move Settings out of the menu-bar popover into a standalone resizable AppKit
window so clicking it no longer steals focus and dismisses the bar (the .sheet
inside MenuBarExtra(.window) was the root cause). Force the actual NSWindow
appearance (aqua/darkAqua/system) on both the popover and the settings window
so Light/Dark visibly flips materials and semantic colors, not just custom
tokens. Replace the fragile popover quit dialog with an inline two-step
arm/confirm. Widen the dropdown and increase spacing/type for readability. Fill
the settings window responsively and make Done close it via the window
controller (dismiss() is a no-op in a hosted NSWindow).
2026-06-09 16:44:10 -04:00
Tam Nhu Tran e33da989eb feat(bar-app): selectable System/Light/Dark theming
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.
2026-06-09 16:11:36 -04:00
Tam Nhu Tran 5aa94b5019 feat(bar-app): retune subscription card palette for the dark theme
Replace the raw system green/yellow/orange/red headroom colors (garish on the
dark surface and colliding with the brand orange) with a muted, intuitive
green-amber-coral-red palette that leans coral for 'low' so a near-empty
window never reads as the accent. Drop the cool indigo card wash for a neutral
elevated surface so the warm bars no longer clash; subscription identity stays
on the section header and badge.
2026-06-09 15:13:56 -04:00
Tam Nhu Tran df967792b9 feat(bar-app): bar-first quota card with sane time formatting
Replace the prose window lines with an aligned per-window bar list (5h /
weekly / Opus / Sonnet), colored by headroom, with the binding window
highlighted and a compact reset chip. Humanize durations beyond a day
(Nd Nh instead of raw hours) and only show the burn-rate pace clause when a
window is projected to exhaust before it resets, so a meaningless 'resets in
44h' / '~110h left' projection no longer appears.
2026-06-09 15:07:08 -04:00
Tam Nhu Tran 0e0b912187 feat(bar-app): subscription-first cockpit with detailed quota card
Lead the dropdown with subscriptions: a dedicated card shows the binding
window as the hero (gauge, remaining %, reset countdown, and a burn-rate
'left at this pace' line), a secondary window, and the Opus/Sonnet split for
Max, with a stale marker for older Codex data. Demote spend/usage to a compact
strip and surface cross-tool headroom. Add pure burn-rate / time-to-exhaustion
and binding-window math in Core. Kill the menu scroll indicator for real
(NSScrollView hider) so content stays aligned. Spend-cap alerts default off
(pay-per-use, opt-in).
2026-06-09 14:40:03 -04:00