The detached prefetch spawned four codeburn subprocesses (week, 30days,
month, all) that competed with the main refresh loop's Today fetch for
disk and parser time. On large session corpora that starved the Today
refresh for minutes at a time, and the status label drifted stale until
the prefetch queue finally drained. Users perceived this as the menubar
"stopping" until they clicked a provider tab, which coincided with the
queue clearing.
Drop prefetchAll. Period tabs in the popover now fetch lazily on first
click (3-10 seconds once per app lifetime per period), same as they did
in 0.8.1. Today's label stays fresh because nothing else is hammering
the parser in the background.
prefetchAll was awaited inside the refresh loop after the first cycle.
On large corpora the All Time parse takes 60+ seconds and kept the Today
refresh blocked for that whole window, so the status label got stuck for
minutes at a time while the CLI was returning fresh numbers.
Detach prefetchAll into its own @MainActor task. The popover still gets
the benefit of pre-warmed period caches, the refresh loop ticks every 15
seconds regardless.
Loading overlay no longer flashes on every 15s poll. isLoading now only
toggles when the cache is cold, and all periods prefetch once on launch
so tab switching is instant.
Heatmap tooltip, trend bars, forecast, and all-time stats were computing
on UTC dates while the CLI reports on local dates, so the two disagreed
at day boundaries. Switched every date formatter and calendar in these
paths to .current so the menubar matches codeburn today output.
GitHub asset name includes a v prefix (v0.8.0) while
CFBundleShortVersionString does not (0.8.0). Strip the prefix
before comparing. Also capture stderr on update failure so the
button doesn't hang on "Updating..." forever.
Menubar: reduce cache TTL from 300s to 30s, background refresh from
60s to 15s, always fetch fresh data on tab switch instead of serving
stale cache. TUI: default auto-refresh to 30s (--refresh 0 to disable).
Closes#107
Remove the broken "Connect Claude" / "Reconnect Claude" buttons from
the Plan pane -- they opened a terminal session that did nothing useful
for already-logged-in users. Keep only the "Retry" button.
Add an auto-update checker that queries GitHub releases every 2 days in
the background. When a newer menubar build is available, an "Update"
pill appears in the header. Clicking it runs the existing installer
flow (download, replace, relaunch) with no manual steps.
Add package.json repository/bugs/homepage fields. Swap hardcoded
AgentSeal/codeburn URLs to getagentseal/codeburn across README,
mac README, macOS menubar star banner, and the menubar installer's
release-API endpoint. 301 redirects keep old URLs working, but
canonical links now point at the current org.
Co-authored-by: AgentSeal <hello@agentseal.org>
The trend chart tooltip always displayed `bar.tokens` in its header,
which is zero for provider-filtered history (the CLI only carries
per-provider cost+calls in the daily cache, not tokens). Result: when
you selected Claude/Codex/Cursor/Pi, hovering a bar showed $0.00 even
on days with real spend.
The trend chart's main metric already falls back to cost when tokens
are zero. Pass that same metric value through to the tooltip so both
stay consistent.
Also removed the misleading "No model breakdown available" fallback
line. For provider-filtered views the per-model breakdown legitimately
doesn't exist in the payload, so the tooltip now just shows date +
cost without the error-sounding message.
The refresh loop previously skipped `refreshQuietly(.today)` when the
user was already viewing the Today period. That guard meant while the
user was on (today, claude) or any other non-.all provider, the
(today, all) cache went stale. The menubar title and the agent tab
strip both read from that cache, so they displayed stale costs while
the hero section (which reads the currently-viewed payload) showed
the correct fresh value.
Remove the guard so the (today, all) cache refreshes every cycle
regardless of the currently selected period/provider.
Shipped as mac-v0.7.4.
The Plan pane previously told users to "run claude login in your
terminal, then retry" with no way to start the flow from the app.
Added a primary Connect Claude button on both the no-credentials and
failed states that launches Terminal.app with `claude login`, so the
OAuth flow is one click away.
TerminalLauncher.openClaudeLogin() uses a hardcoded literal, so no
user input reaches AppleScript. Refactored the common path into
runInTerminal(command:preValidated:) which re-validates any non-
literal input against CodeburnCLI.isSafe as defense-in-depth.
On machines without Terminal.app (iTerm/Ghostty/Warp), the button
surfaces an inline instruction to run `claude login` manually instead
of failing silently.
Tabs were filtering on `value > 0` (today's spend), which hid the row
whenever only one provider had activity today. The CLI's providers map
already contains only providers detected on the system, so showing the
map as-is matches user intent: a tab for each installed tool,
regardless of today's spend. Tab strip only hides when nothing is
detected.
This also makes the Plan pill reachable again: it gates on
`selectedProvider == .claude`, which required clicking the Claude tab
to select.
The tab strip was visible for everyone regardless of which tools they
actually run, which produced a row of All + one provider for Claude-only
users and a row of All + zeros for users on exotic stacks. Hide the
whole row until a second provider has real spend, matching the behavior
the GNOME extension ships with.
Also expand ProviderFilter to include every provider the CLI supports
(OpenCode and Pi were missing) so their tabs appear when those tools
produce sessions. The CLI already emits pi and opencode in the payload's
providers map; the Mac app just wasn't offering a tab for them.
visibleFilters now filters on value > 0 instead of key presence, because
the CLI includes zero-cost entries for discovered-but-unused providers
and we don't want those rendering as blank tabs.