- one gate (motionEnabled): off under reduced-motion, missing matchMedia,
and vitest; every path checks it first
- mount/filter-change only: count-up and bar grow-in key off the
period|provider|range key, so 30s poll refreshes snap values silently
instead of re-animating
- first-load skeleton shimmer replaces bare scanning text (kept sr-only
for screen readers); slide-in toast host for Settings/export feedback
(validation errors stay inline); CSS hover-lift + press micro-
interactions, all with a reduced-motion escape hatch
- gsap 3.15.0 + @gsap/react 2.1.2 (+74KB raw JS; G4 flame work shares it)
244/244, typecheck + build green.
Replaces the three-rule anomaly card with a Wins/Improvements/Risks
Signals card mirroring the menubar's rule set and thresholds
(FindingsSection.swift): cache >=80% and one-shot >=0.75 and spend-down
>10% and streak >=5d as wins; top-3 optimize findings, low cache <50%,
low one-shot <0.5, retry tax >=25% of spend as improvements; weekday
spike >1.8x, week-over-week >+25%, projected month >1.3x prior month as
risks. Time-comparison rules suppressed under a custom range. Renders
nothing when empty; icons per group, never color-alone. Anomaly test
coverage ported, not deleted.
221/221, build green.
- formatUsd applies the payload currency {code,symbol,rate} once at
display; formatConverted (symbol only) for CLI-preconverted plan
values so nothing converts twice
- provider picker built from providerDetails: label shown, internal id
sent as --provider (fixes filters for providers whose display name
differs, e.g. Grok Build); falls back to map keys on older CLIs
- getYield threads the active provider through preload/main/sections
App suite 170/170, root 1615/1615.
- Provider filter: Models-this-period sources current.topModels (history
days carry empty topModels per provider); StackedBars falls back to a
cost-proportional single segment like the Swift menubar
- Chart windows align to the CLI (week -7, 30days -30, all = 6 months)
and zero-fill a contiguous calendar window; history.daily is sparse and
both sides key local YYYY-MM-DD, so lookups are safe (verified on real
CLI output)
- Custom range threads into Overview panels (chart, models table) and
suppresses MTD/projected and vs-last-week comparisons; Compare states
that custom dates fall back to the period
- usePolled clears errors per attempt and sections show a StaleBanner
instead of silently rendering last-good data after a failed refresh
- Cache-hit denominator matches the CLI; hero savings relabeled 'Saved by
applied fixes' + new 'Saved via local models' line; formatCompact
everywhere; Optimize 'Fixes' count matches the rendered list
App suite 163/163 (was 147), root 1613/1613.
contiguousDailyWindow rebuilt a calendar window from the client clock and looked
up days by date key; on real CLI data every lookup missed and zero-filled, so the
Spend chart went empty and the Overview chart went flat. Use the real last-N
backfilled entries of history.daily directly (Spend last-15, Overview
last-max(30, periodDaily)) and remove the dead helper.
typecheck clean; 147/147 tests pass.
- extract contiguousDailyWindow + formatChartDate to lib/period (shared)
- Spend "Daily spend by model": fixed contiguous 15-day window (zero-filled)
with an .ov-xax date axis, matching the Overview chart
- remove the horizontal gridlines from both charts (they read like data lines)
typecheck clean; 129/129 tests pass.
Drop the FuelRing (and its now-unused plans polling) from the ov-stats3 card;
the stats row is now Month-to-date + Projected month (2 equal columns).
typecheck clean; 128/128 tests pass.
- ProviderLogo: add Copilot/Gemini/Qwen/OpenCode marks; reuse the Cursor logo
for Cursor Agent; single-color logos (Claude, Gemini) via a SINGLE_LOGOS map
- remove the redundant model-series dot from Overview "Most expensive sessions"
(the row already names the model in its sub text)
typecheck clean; 128/128 tests pass.
Re-arrange everything below the two top cards so it reads as a dashboard:
- Insight band grouping the coach pacing line + anomaly callouts.
- Analytics row: Cost-per-outcome | Routing what-if (equal 2-up).
- Height-balanced 2-column body — Left: Models table + Most expensive
sessions; Right: Top activities + Daily spend — so the left column no
longer dead-ends into a big empty gap.
- Consistent gaps, align-items:start, single-column reflow under 900px.
typecheck clean, 88 tests pass.
- Top card: one card, three equal columns split by dividers —
current spend (with Saved-to-date) | daily activity | efficiency
scorecard. Removed the duplicate one-shot/cache ratings column and the
separate efficiency card (EfficiencyScorecard + FuelRing gain a 'bare'
mode).
- Stats: one card, three equal divided columns — Month-to-date |
Projected | Nearest-limit fuel ring.
- Efficiency grade is now a circular brushed-metal medal (one subtle
gradient + inset highlight + depth shadow), tiered A/B-C/D/F, tokenized
for light+dark — premium, not the flat AI-looking pill.
- Tightened spacing/dead space; 1-column reflow under 900px.
typecheck clean, 88 tests pass.
- Hero card now splits into three divider-separated sections: current
spend | daily-activity heatmap | one-shot/cache/saved ratings.
- Move the Nearest-limit fuel ring next to Month-to-date and Projected
(fills the previously-empty third stats column). Efficiency scorecard
takes the row above.
Per feedback, the hero (number + KPIs) and the git-style daily-activity
heatmap now share a single card, split left/right with a divider.
ActivityHeatmap gains a 'bare' mode (renders head+grid without its own
card wrapper). Efficiency scorecard + fuel ring move to a row below.
The KPI strip duplicated the hero (Spend = hero total, Calls/Sessions =
hero subline). Drop the strip; fold the unique KPIs — One-shot, Cache
hit, Saved — into the hero as a secondary row (keeps the a11y label).
- Hero now reflects the SELECTED period (current.cost + current.label +
calls/sessions), not just today — 30D no longer shows today's number.
- New Models table: per-model Input/Output tokens + Cost + Calls,
aggregated from history.daily[].topModels[] (real per-day data),
rebuilt with a robust bar → left-name → right-numbers layout (fixes
the offset/misaligned columns).
- Daily chart: weekly date ticks (MMM d), Avg/Peak/Yesterday chips, and
the hover tooltip now portals to document.body (position:fixed,
edge-clamped) so it is never clipped.
- Removed the meaningless decorative sparklines. Empty fuel-ring card no
longer reserves a tall empty box.
- typecheck clean, 87 vitest pass.
- Daily-spend chart always shows a contiguous >=30 calendar-day trend
(backfilling gaps with zero bars) instead of collapsing to the period
selector (e.g. a single bar on Today).
- Real app shell: viewport-height window with an internally scrolling
.body (was clipped/unscrollable).
- Drop the wireframe's fake traffic-light dots; rely on the real OS
window controls. Window background follows the system theme.
- Update Overview test to assert the 30-day chart window.
history.daily is unbounded CLI backfill (up to 365d, zero-days absent), not
period-scoped. Slice it to the selected period's date window before the chart
(new periodWindowStart/sliceDailyToPeriod), and normalize Waste/wk by the
selected period length (periodLengthDays), not the backfill length.
Also: pace comparator = previous calendar month only (label/math now agree);
session sub-line unit turns->calls; model-join key gains cost to avoid
same-project/day/calls collisions (sessionModelKey); Panel rightLink "See all ›"
on the sessions panel; hide fabricated $0-window gridline labels; correct the
projection comment to the active-days approximation.
Real Overview driven by usePolled(getOverview): 4 stat cards (Today, Month
to date +% vs pace, Projected month est, Waste found /wk), the daily-spend
CapsuleChart, and the most-expensive-sessions list. Every rendered number is
derived from the single MenubarPayload (formulas documented in-code, mirroring
plan-usage projectMonthEnd); topSessions' missing model is recovered from
topProjects sessionDetails. App renders <Overview/> for the overview section,
replacing the T0 smoke view; first-run/error/loading states retained. TDD
spec added (test written first, red→green).