Skip to content

macOS Live tab: provider overlays, time-range switcher, range totals#485

Merged
willwashburn merged 6 commits into
mainfrom
macos/settings-tab-bar
Jun 21, 2026
Merged

macOS Live tab: provider overlays, time-range switcher, range totals#485
willwashburn merged 6 commits into
mainfrom
macos/settings-tab-bar

Conversation

@willwashburn

@willwashburn willwashburn commented Jun 21, 2026

Copy link
Copy Markdown
Member

Summary

Builds out the macOS Live tab on top of the merged settings/tab-bar work (#482). Rebased onto current main, so the diff is limited to the macOS app (the --bucket SDK work from #483 is consumed, not duplicated).

  • Overlay both providers with per-provider toggles; Codex rendered in blue/purple.
  • Time-range switcher (5m/1h/12h/1d/7d) driven by summary --bucket.
  • Adaptive time (x) axis with softer gridlines on the live charts.
  • Range totals (tokens + cost) surfaced in the headline.
  • Stop ingesting per poll (was 3–4s); rely on the background watch loop instead.
  • Fix a stuck spinner when switching ranges quickly.

Changes

  • apps/macos/Sources/Burn/LiveBurnView.swift
  • apps/macos/Sources/Burn/LiveBurnViewModel.swift
  • apps/macos/Sources/Burn/BurnLedger.swift
  • apps/macos/Sources/Burn/ContentView.swift
  • apps/macos/Sources/Burn/BrandIcon.swift

🤖 Generated with Claude Code

Review in cubic

willwashburn and others added 6 commits June 21, 2026 00:12
Root of the slow "loading": each live poll ran a one-shot `burn ingest`, which
is ~3–5s on a 591MB ledger (even with nothing new). Read-only `burn summary` is
only ~10ms. Move freshness back to a continuous background `burn ingest --watch`
(FS-event driven, ~1s poll, incremental — verified it catches new turns), and
keep the poll path to summary only. Poll cadence back to 1.5s.

(Keeps the moving-average rate fix from the prior commit.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- LiveBurnViewModel now polls every provider each cycle and keeps a per-provider
  sample series; exposes show/hide toggles (won't hide the last one).
- LiveBurnView overlays one color-coded line per provider (Claude coral, Codex
  blue/purple) on both the rate and cumulative charts, with toggle chips that
  double as the legend. Headline is the combined rate/spend across shown
  providers. Independent of the Usage tab's single-select provider.
- Codex brandColor → blue/purple (#5B6CFF) to match its icon's color scheme,
  replacing the green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the real-time moving-average stream with a bucketed range chart. A
segmented switch picks the window; each range maps to a burn --bucket size and
refresh cadence (5m→30s/3s … 7d→12h/300s). Per provider, query
`burn summary --since <iso> --bucket <b> --json` and plot per-bucket rate
(tokens/bucketSeconds) + a running cumulative line, keeping the overlaid
per-provider lines (Claude coral, Codex blue/purple) and the show/hide toggles.
Switching range clears + re-queries immediately and retimes the loop; stale
in-flight results are dropped. Background `ingest --watch` still provides
freshness.

Depends on burn `--bucket` (PR #483): the release build.sh bundles a
--bucket-capable burn once #483 is on main.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a "legend for time" — an x-axis whose labels adapt to the selected range
(clock time for 5m–1d, calendar date for 7d) on both the rate and cumulative
charts. Soften gridlines (0.08→0.06) for a calmer, more readable chart.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
For the selected timeframe, the headline now leads with the combined total
tokens and total cost across shown providers (e.g. "Last 7d · 2.1B tokens ·
$1,444"), with the current burn rate kept as secondary context. Totals come
from the cumulative line's last point per provider. Add a billions (B) tier to
the token formatter for the large multi-day sums.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
setRange cleared the series and kicked a refresh, but refresh's hard
`guard !refreshing` dropped the new request while one was in flight, and the
in-flight one discarded its result as stale — so nothing repopulated until the
next timer tick (up to 5 min on 7d), leaving the warming spinner stuck.

Coalesce instead: a refresh requested while one runs sets `refreshAgain`, and
the running refresh loops one more pass for the latest range. Publish only when
the queried range still matches.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@willwashburn, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 22 minutes and 4 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b7ff9c0e-c6c9-45b9-8719-67fb7384db14

📥 Commits

Reviewing files that changed from the base of the PR and between a60ff48 and b94c7a0.

📒 Files selected for processing (5)
  • apps/macos/Sources/Burn/BrandIcon.swift
  • apps/macos/Sources/Burn/BurnLedger.swift
  • apps/macos/Sources/Burn/ContentView.swift
  • apps/macos/Sources/Burn/LiveBurnView.swift
  • apps/macos/Sources/Burn/LiveBurnViewModel.swift
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch macos/settings-tab-bar

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@willwashburn willwashburn merged commit 1c8695c into main Jun 21, 2026
4 checks passed
@willwashburn willwashburn deleted the macos/settings-tab-bar branch June 21, 2026 04:14

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b94c7a0271

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +132 to +133
process.standardOutput = Pipe()
process.standardError = Pipe()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Drain or discard the watch process stderr

In a ledger state that causes repeated ingest errors, burn ingest --watch --quiet still writes those errors to stderr (crates/relayburn-cli/src/commands/ingest.rs lines 257-264), but this long-lived child now has both pipes created and never read. Once the stderr pipe fills, the watcher can block and stop freshening the ledger, leaving the Live tab polling stale summaries; redirect the streams to /dev/null or continuously drain them.

Useful? React with 👍 / 👎.

/// cleanly managed); the live chart still polls either way.
func startIngestWatch() {
guard watchProcess == nil else { return }
guard case .bundled(let url) = resolveTool() else { return }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep live ingest working for PATH-only helpers

When the app is run via swift run or built without bundling the helper but a burn exists on PATH, resolveTool() returns .path here and the new watch is skipped. Since this commit also removed the per-poll ingest() call and the Live tab only calls read-only summary --bucket, PATH-only builds no longer freshen the ledger, so the live chart stays stale unless the user separately starts an ingest watcher.

Useful? React with 👍 / 👎.

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.

1 participant