Skip to content

Add lifetime full-history menubar trend across macOS, GNOME, and CLI#391

Open
0monish wants to merge 1 commit into
getagentseal:mainfrom
0monish:feat/lifetime-full-history-menubar
Open

Add lifetime full-history menubar trend across macOS, GNOME, and CLI#391
0monish wants to merge 1 commit into
getagentseal:mainfrom
0monish:feat/lifetime-full-history-menubar

Conversation

@0monish
Copy link
Copy Markdown

@0monish 0monish commented May 24, 2026

Issue Reference

Proposed issue reference: #389

Summary

  • Solved items count: 8 total.
    • 2 Lifetime correctness fixes (Lifetime period wiring + uncapped/full-history semantics)
    • 6 desktop menubar follow-up fixes (Trend cadence mismatch, Lifetime Stats semantics, Top Projects session-count contrast, backward-compatible stats payload decoding, GNOME period-aware chart/trend rendering, and period-appropriate visualization)
  • Coverage count: 4 product surfaces + 2 docs surfaces.
    • Product surfaces: CLI, dashboard, macOS desktop menubar, GNOME desktop extension
    • Docs surfaces: root README + GNOME README
  • Validation count: 5 core validations completed.
    • CLI/dashboard tests + build
    • macOS menubar build + live UI verification
    • GNOME desktop extension runtime wiring verification
    • Menubar JSON contract regression coverage
    • Cross-surface lifetime cadence regression coverage

What Changed

  • Added a separate selected-period stats summary to the menubar payload so Stats can use true selected-period totals without forcing Trend to render unbounded daily bars.
  • Lifetime now retains full selected-period daily history in the menubar payload instead of trimming it to the generic 365-day chart cache, so older years remain available for aggregation.
  • Added real intraday history to the menubar payload for Today, using 6 x 4-hour buckets.
  • Updated Trend to use period-appropriate bar cadences:
    • Today: 6 x 4-hour buckets
    • 7 Days: daily bars
    • 30 Days: daily bars
    • Month: month-to-date daily bars
    • 6 Months: weekly bars across Recent 26 weeks
    • Lifetime: adaptive full-history bars
      • <= 24 months: monthly
      • <= 60 months: quarterly
      • > 60 months: yearly
  • Kept Lifetime Stats all-time with Tracked spend (all time).
  • Removed the orange comparison badge from Lifetime, since there is no sensible fixed prior-window comparison once the chart spans full history.
  • Updated the macOS menubar status-period setting to include Lifetime, so the always-visible status item can track the same uncapped period independently from the popover.
  • Improved Top Projects session-count visibility in the macOS popover.
  • Made the Swift menubar decoder tolerate older payloads that do not yet contain the new stats block.

Trend Window Approach

For this compact popover UI, I found that forcing every period into daily bars did not feel like the best tradeoff. The bars become visually dense, hover targets get worse, and the chart communicates the trend less clearly.

In this PR, I used the following approach:

  • Today uses intraday buckets instead of a single daily bar.
  • Short multi-day periods render their real selected window using daily bars.
  • 6 Months uses weekly aggregation so the full half-year can fit cleanly.
  • Lifetime uses full-history aggregation rather than a fixed recent window:
    • monthly through 24 months of history
    • quarterly through 60 months of history
    • yearly beyond 60 months

My goal here was to keep each selected period semantically correct while still keeping the chart legible. If there is a better presentation for any of these windows, I am very open to adjusting it.

Testing

  • I have tested this locally against real data (not just unit tests)
  • npm test passes
  • npm run build succeeds

Additional validation performed:

  • Full Vitest suite passed:
    • npm test
  • Focused menubar regression suites passed:
    • npm test -- --run tests/menubar-json.test.ts tests/gnome-trend-series.test.ts tests/cli-status-menubar.test.ts
  • Added explicit multi-year regression coverage for older Lifetime history, including a mock 2024/2025/2026 dataset.
  • Added GNOME cadence regression coverage for Today, 6 Months, and Lifetime monthly/quarterly/yearly aggregation.
  • Added provider-scoped Lifetime regression coverage for --provider claude.
  • swift build passed after the Trend aggregation refactor.
  • swift test now runs under an explicit swift-testing package dependency in mac/Package.swift.
  • Added macOS lifetime cadence regression coverage for monthly, quarterly, and yearly Lifetime trend selection.
  • Added macOS menubar status-period regression coverage for persisted Lifetime selection and suffix rendering.
  • Cross-surface UI checks passed:
    • CLI/dashboard period options include Lifetime.
    • macOS menubar period control and status-period setting both include Lifetime and render adaptive monthly/quarterly/yearly bars based on full history.
    • GNOME indicator + prefs include Lifetime as a selectable default period.
  • Live macOS menubar verification passed:
    • Today now shows 6 x 4-hour bars with Avg/4h, Peak slot, and Current 4h
    • 7 Days now shows Last 7 days
    • 6 Months now shows Recent 26 weeks with weekly bars
    • Actual local data (61 tracked days) now shows Lifetime as All time by month
    • Synthetic 2024-2026 data shows Lifetime as All time by quarter
    • Synthetic 2020-2026 data shows Lifetime as All time by year
    • Lifetime Stats now shows Tracked spend (all time)
  • Live GNOME lifetime cadence verification passed with synthetic exported snapshots:
    • Synthetic 2023-2026 snapshot shows Lifetime as All time by quarter
    • Synthetic 2020-2026 snapshot shows Lifetime as All time by year

Screenshots

Surface State Period Before After
macOS View Lifetime before-lifetime after-lifetime
macOS Trend Today before-today-trend after-today-trend
macOS Stats Today before-today-stats after-today-stats
macOS Trend 7 Days before-7days-trend after-7days-trend
macOS Stats 7 Days before-7days-stats after-7days-stats
macOS Stats Month before-month-stats after-month-stats
macOS Trend 6 Months before-6months-trend after-6months-trend
macOS Stats 6 Months before-6months-stats after-6months-stats
macOS Stats 30 Days before-30days-stats after-30days-stats
macOS Trend Lifetime (monthly) N/A lifetime-trend-monthly
macOS Trend Lifetime (quarterly) N/A lifetime-trend-quarterly
macOS Trend Lifetime (yearly) N/A lifetime-trend-yearly
macOS Stats Lifetime (detail) N/A lifetime-stat
GNOME View Lifetime before-lifetime-gnome after-lifetime-gnome
GNOME Trend Today before-today-trend-gnome after-today-trend-gnome
GNOME Trend 7 Days before-7days-trend-gnome after-7days-trend-gnome
GNOME Trend Month before-months-trend-gnome after-month-trend-gnome
GNOME Trend 30 Days before-30days-trend-gnaome after-30days-trend-gnome
GNOME Trend 6 Months before-6months-trend-gnome after-6months-trend-gnome
GNOME Trend Lifetime (monthly) N/A lifetime-trend-monthly-gnome
GNOME Trend Lifetime (quarterly, synthetic 2023-2026) N/A lifetime-trend-quarterly-gnome
GNOME Trend Lifetime (yearly, synthetic 2020-2026) N/A lifetime-trend-yearly-gnome

Keep Lifetime uncapped in the menubar payload, add adaptive monthly/quarterly/yearly trend aggregation, and extend the macOS menubar status-period setting to support Lifetime.
@iamtoruk
Copy link
Copy Markdown
Member

Thanks for the thorough work here, especially the adaptive trend cadences and the cross-surface coverage.

However, we're going in a different direction for the period strip. We're adding a custom calendar popover (inline calendar icon after "6 Months") that lets users pick arbitrary dates — single days or non-contiguous multi-day selections. With that in place, adding a "Lifetime" tab explicitly creates too much congestion in the strip:

Today  7 Days  30 Days  Month  6 Months  📅

The strip is already tight, and "Lifetime" as a permanent tab doesn't earn its space when the calendar picker can already cover any date range the user wants.

What we'd accept instead: put Lifetime as an option under Settings — if the user enables it, it replaces "6 Months" with "Lifetime" in the strip. That way users who want unbounded history get it, without adding visual clutter for everyone else.

The trend cadence work (intraday buckets for Today, weekly bars for 6 Months, adaptive monthly/quarterly/yearly for long ranges) is solid and could land separately once we sort out the Lifetime UX question.

@iamtoruk
Copy link
Copy Markdown
Member

Also — this PR touches 24 files across 4 surfaces (CLI, macOS menubar, GNOME, docs) with 1800+ additions. That's hard to review as a single unit.

Would you be open to splitting this into separate PRs? For example:

  1. CLI + dashboard: Lifetime period wiring, cli-date.ts, main.ts, dashboard.tsx
  2. macOS menubar: Swift changes, trend cadence, stats payload
  3. GNOME extension: indicator, prefs, trend-series

Each surface can land and be tested independently. Smaller PRs are easier to review and less likely to have merge conflicts pile up.

@iamtoruk
Copy link
Copy Markdown
Member

One more thing — the adaptive trend bars for Lifetime (monthly/quarterly/yearly) aren't something we'd want in the menubar. The popover is a small screen and cramming months or years of bars into it just creates visual clutter without being useful. Lifetime in the menubar should just show the aggregate stats (total spend, calls, top models) without a trend chart. The trend section can simply be hidden when Lifetime is active.

That removes a big chunk of the complexity in this PR.

@0monish
Copy link
Copy Markdown
Author

0monish commented May 24, 2026

Also — this PR touches 24 files across 4 surfaces (CLI, macOS menubar, GNOME, docs) with 1800+ additions. That's hard to review as a single unit.

Would you be open to splitting this into separate PRs? For example:

  1. CLI + dashboard: Lifetime period wiring, cli-date.ts, main.ts, dashboard.tsx
  2. macOS menubar: Swift changes, trend cadence, stats payload
  3. GNOME extension: indicator, prefs, trend-series

Each surface can land and be tested independently. Smaller PRs are easier to review and less likely to have merge conflicts pile up.

Yes Sure

@0monish
Copy link
Copy Markdown
Author

0monish commented May 24, 2026

Thanks for the thorough work here, especially the adaptive trend cadences and the cross-surface coverage.

However, we're going in a different direction for the period strip. We're adding a custom calendar popover (inline calendar icon after "6 Months") that lets users pick arbitrary dates — single days or non-contiguous multi-day selections. With that in place, adding a "Lifetime" tab explicitly creates too much congestion in the strip:

Today  7 Days  30 Days  Month  6 Months  📅

The strip is already tight, and "Lifetime" as a permanent tab doesn't earn its space when the calendar picker can already cover any date range the user wants.

What we'd accept instead: put Lifetime as an option under Settings — if the user enables it, it replaces "6 Months" with "Lifetime" in the strip. That way users who want unbounded history get it, without adding visual clutter for everyone else.

The trend cadence work (intraday buckets for Today, weekly bars for 6 Months, adaptive monthly/quarterly/yearly for long ranges) is solid and could land separately once we sort out the Lifetime UX question.

First of all welcome and I love this tool thank you. And I was also thinking for that calendar view earlier then I ended up with this, no issues I will put it in the settings.

@0monish
Copy link
Copy Markdown
Author

0monish commented May 24, 2026

One more thing — the adaptive trend bars for Lifetime (monthly/quarterly/yearly) aren't something we'd want in the menubar. The popover is a small screen and cramming months or years of bars into it just creates visual clutter without being useful. Lifetime in the menubar should just show the aggregate stats (total spend, calls, top models) without a trend chart. The trend section can simply be hidden when Lifetime is active.

That removes a big chunk of the complexity in this PR.

NOTED 🫡

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants