docs/providers/NEW_PROVIDER.md items the PR had not reached yet, plus the two
surfaces that are functional rather than cosmetic:
- docs/providers/dsh.md and its row in the provider index, documenting the
storage layout, the JSONL-backend-only scope (the opt-in SQLite persistence
backend is not read), and that DSH is a developer preview whose format
version 0 implies no compatibility.
- CHANGELOG entry under Unreleased.
- README provider count 40 -> 41 and a data-locations row.
- app/package.json: $HOME/.dsh in the snap personal-files allowlist, without
which the Linux snap build cannot read DSH sessions at all.
- UsageDataChangeGuard: the DSH sessions root, without which the menubar never
notices a new session and does not refresh.
- Bumps the dsh parse version, since the parser's attribution changed.
Improve dashboard refresh coordination, scrolling, responsive layout, and data-density behavior, including the Windows-safe resize correction validated on the final head.
The Cline CLI (npm `cline`, 3.x) stores sessions as
<sessions>/<id>/<id>.json + <id>.messages.json. The existing `cline`
provider only discovers tasks/<id>/ui_messages.json, so every CLI session
was silently reported as $0.00 — no warning, not even under --verbose.
Adds `cline-cli` as its own provider rather than a third root on `cline`,
leaving the shared Cline-family parser (Roo Code, KiloCode, IBM Bob)
untouched. It mirrors the CLI's own root resolution
(CLINE_SESSION_DATA_DIR -> CLINE_DATA_DIR -> CLINE_DIR -> ~/.cline),
implements probeRoots() so `doctor` can tell "not installed" from "wrong
override", emits one call per assistant message's `metrics` block, and
falls back to the session rollup when a session carries none. The
fallback reads `usage`, not `aggregateUsage`, which folds in spawned
subagents that are themselves separate session directories.
Two supporting changes, both required for CLI costs to report correctly:
- parser.ts re-priced cline-cli calls from tokens because the provider
was not on the reported-cost allowlist, inflating a real 12-session
local sample from $1.11 to $3.92.
- session-cache.ts gains the matching PROVIDER_ENV_VARS entry (so a
changed override invalidates) and a `reported-cost-v1` parse version
(so sessions cached before the allowlist fix re-parse once instead of
being re-priced forever).
Cost is treated as metered only when actually present and non-negative,
so a metered $0 stays reported while a missing or negative cost falls
back to token pricing — applied identically on the per-message and
rollup paths. Timestamps promote a seconds-resolution value rather than
silently landing in 1970, matching the guard kiro.ts uses.
CLINE_DIR / CLINE_DATA_DIR / CLINE_SESSION_DATA_DIR are added to the test
env-isolation list so a developer's real sessions cannot bleed into
fixtures.
The VS Code variant discovery bug reported alongside this in #874 is
deliberately NOT fixed here — it shipped in #882.
Verified against 18 real local sessions: 142 calls, 4,934,762 input /
224,561 output tokens, and a cost matching the CLI's own metered total to
the cent. `codeburn doctor` reports "Cline CLI OK".
Refs: #874
Full Report and Optimize always opened Terminal.app. Add a closed
PreferredTerminal enum (Terminal.app, iTerm2), a General settings picker,
and graceful fallback: chosen terminal -> Terminal.app -> headless spawn.
Defaults to Terminal.app so existing users see no change.
The terminal is selected from a closed enum, never a user string, so the
`tell application "..."` target stays a compile-time literal. Commands are
still whitespace-joined argv validated token-by-token by CodeburnCLI.isSafe
before any interpolation, preserving the shell-injection invariant.
Only terminals with a real "run in a live window" scripting verb are listed:
Terminal.app has `do script`, iTerm2 has `write text` on a session. Ghostty,
WezTerm, Warp, Alacritty and kitty expose no equivalent, so they keep the
existing headless fallback rather than shipping a window that closes on exit.
The iTerm2 script targets `application "iTerm"`, not `"iTerm2"`. AppleScript
resolves the name of a not-yet-running app through LaunchServices by bundle
file name, and the bundle is iTerm.app. Measured on iTerm2 3.6.11: with the
app quit, `tell application "iTerm2"` fails to compile (-2741) while
`tell application "iTerm"` compiles, cold-launches iTerm2 and runs the
command. The `"iTerm2"` spelling only works while the app already happens to
be running.
Fallback is a chain that checks results rather than a single fire-and-forget
pick, because "installed" does not imply "scriptable": osascript can still
fail on a missing Automation approval or a broken bundle. Each candidate is
run, waited on and its exit status checked, off the main thread so the
popover stays responsive; only once every candidate has failed do we spawn
headless. Every step logs via NSLog, so a user who sees no window has a trail
in Console.app instead of an app that looks dead. The decision logic is
extracted into terminalChain/runFirstWorking so tests exercise
"primary failed -> fell back" without launching anything.
Document the setting in the README next to the other menubar defaults keys.
Closes#877
Cline discovery only looked at the stable VS Code globalStorage root, so
tasks created in VS Code Insiders or VSCodium were never found. The
singular getVSCodeGlobalStoragePath helper returns paths[0], and because
the provider always passed a concrete overrideDir, the 3-variant fallback
inside discoverClineTasks was never reached - unlike the Roo Code and
KiloCode siblings, which pass overrideDir straight through.
Build the default roots from getVSCodeGlobalStoragePaths (stable,
Insiders, VSCodium) plus the ~/.cline/data root and hand them to
discoverClineTasks in one call. The existing dedupe by task id still
collapses a task id seen in more than one root, so totals cannot inflate.
The configuredDirs override used by tests and createClineProvider(dirs)
is unchanged.
0.9.18 was packaged from the pre-fix commit (364eed4) before the final
nine commits landed; npm versions are immutable, so the corrected
release ships as 0.9.19 everywhere. The changelog entry carries over
with a supersede note.
Co-authored-by: reviewer <review@local>
The changelog entry predates the final merges; it now covers the
no-data rendering, the cross-process refresh gate, the straddle guard,
the turn-attribution and insights accuracy fixes, the 10-year retention,
and the small cache/currency fixes. README download badges move from
0.9.16 to 0.9.18.
Co-authored-by: reviewer <review@local>
Re-apply the CLI/dashboard Lifetime split from #391/#416 on current main.
- add lifetime as a first-class period (all stays last 6 months)
- wire period through cli-date, dashboard key 6, and CLI commands
- refresh cli-date and cli-json-daily regression coverage
Part of #389. Supersedes #416.
The AppImage-only Linux build hit users with a no-application-installed
error on double-click, because AppImages do not self-register and need
chmod plus libfuse2 on newer distros. Add deb and rpm electron-builder
targets so Linux users get a native install that lands in the app menu
with no manual steps; the deb ships a .desktop entry for exactly that.
README hero grid now lists Debian/.deb, Fedora/.rpm, and AppImage
alongside the macOS and Windows buttons, and the desktop release notes
explain the deb/rpm path plus the AppImage FUSE requirement.
* docs(readme): four-surface hero grid with per-surface install shortcuts
Replace the single TUI screenshot and the scattered optimize, compare and
old menubar shots with one 2x2 grid under the badges: Desktop, Web,
Terminal, and macOS Menubar, each with its one-line way in (direct
download badges for the desktop builds, npx codeburn web, npx codeburn,
codeburn menubar). New screenshots downscaled to 1600px so the README
stays light.
* docs(readme): star and sponsor ask up top, consistency pass
Adds a one-line ask under the badges: star the repo if CodeBurn showed
you something the bill never did, sponsor to keep 36 integrations
honest. Caption line under the hero grid.
Consistency fixes from a full read: the sponsor section said 30
integrations while everything else says 36; dx is the Dioxus CLI, not a
package runner, so the install line now says pnpm dlx; the by-agent
command row was overstuffed for a table cell; Opus 4.6 in the signals
table aged into Opus 4.8; the License section ran MIT and the affiliation
note into one paragraph; two stray em dashes and a double blank line.
Follow-ups to #710, completing issue #708's second ask plus the two review
notes:
- export: new records.csv with one row per call incl. subagentType and
model; sessions.csv gains both fields APPENDED after all legacy columns
so by-index consumers are unaffected; JSON fields additive; formula-
injection escaping preserved
- models --by-agent: the main-session bucket sentinel becomes '(main)' -
agentType is free-form text, so a real subagent literally named 'main'
no longer merges into the main bucket (test-pinned across all formats)
- README: note that the --min-cost 0.01 default can hide sub-cent agent
buckets; --min-cost 0 shows the complete agent inventory
Orchestrator setups pin different agents to different models (planner on
Opus, implementers on Sonnet, scouts on Haiku). The dashboard shows
"Skills & Agents" and "By Model" as separate panels, so there was no way
to see which agent drove which model's spend, or catch an agent that
silently switched models. `codeburn models --by-agent` closes that gap:
one row per (provider, model, agent), mirroring the existing --by-task
pattern across the table, markdown, CSV, and JSON renderers.
The agent label comes from each Claude subagent transcript session's own
agentType crossed with that session's model calls, aggregated through the
same assistantCalls path --by-task uses (not modelBreakdown), so cache-tier
dedup, savings, and Codex-credit logic all carry over unchanged. This is
the authoritative pairing; main-session subagentTypes spawn markers are
deliberately not joined to models, since a spawn marker names an agent but
not the model that agent actually ran on.
Ordinary main sessions (no agentType) and every non-Claude provider have
no agent, so their spend buckets under the label "main" rather than being
dropped or fabricated into a false agent. --by-agent is mutually exclusive
with --by-task; passing both errors politely.
Exposing subagentType + per-record model on `codeburn export` (so users
can build custom crosses over the export) is a separate follow-up and is
intentionally out of scope here.
* feat(doctor): add per-provider detection diagnostics command
When a provider reports zero (or a number that looks wrong) there was no way
to see why: whether the tool is not installed, an env override points at the
wrong directory, the data dir is empty, or parsing failed. Users had to file
issues like "OpenCode does not work" with nothing to go on.
`codeburn doctor` closes that gap. For every provider (or one via --provider)
it shows the exact directories/dbs probed with any env override and whether the
path exists, how many session files were discovered, how many of a bounded
sample parsed cleanly, the cached file count and parser version, and a one-line
verdict: OK (n sessions), NOTHING FOUND with a concrete likely cause, or
ERRORS (n parse failures). Output is a human table by default or --json.
The collect logic is a pure function separated from rendering so tests exercise
it without a TTY. It runs fully offline and read-only (never writes caches or
config, and skips the one network provider's parse), and isolates each provider
in its own try/catch so a single thrower becomes an error row instead of
crashing the report. Providers expose their scan roots via an optional
probeRoots() so the exact paths are shown even when zero sessions are found,
reusing each provider's own path resolution rather than duplicating it.
* fix(doctor): make the inert promise actually true
Adversarial re-review reproduced two false guarantees. Cursor's parser
writes its results cache to disk before its first yield, so a doctor run
created ~/.cache/codeburn/cursor-results.json on a clean machine; the
collect pass now sets CODEBURN_SUPPRESS_CACHE_WRITES (restored after) and
the cursor writer honors it. Antigravity's parse probes for a live
language server (spawns ps and lsof, RPCs the IDE when found); doctor now
skips its parse sample the way network providers are skipped, keeping
discovery counts meaningful.
Also stop blaming CODEBURN_CACHE_DIR in NOTHING FOUND hints (it is our
cache location, not a discovery path) and correct the sample-cap comment:
the cap truncates yields, eager parsers still do whole-file work.
* feat(dashboard): add inline daily history paging
* refactor(dashboard): make daily activity directly scrollable
* fix(dashboard): keep the empty state for users with no history at all
Scrollable mode kept the dashboard shell up whenever full history exists,
but a truly-new user with zero data anywhere saw a zeroed skeleton instead
of the No usage data message. Extract the decision into showEmptyState so
the boundary is test-pinned: empty period with history renders the shell,
empty everything renders the empty state, and the loading pass never
flashes it.
---------
Co-authored-by: AgentSeal <hello@agentseal.org>
* feat(dashboard): add granular usage timelines
* fix(dashboard): readable timeline legend and month-scale buckets
Session legend labels now use the real projectPath's last two segments
(app/web) instead of the sanitized project dir, which rendered as an
unreadable -Users-name-... dump and truncated in the legend.
Hourly buckets now cap at 8 days; longer ranges bucket daily. A 30-day
window rendered 720 overlapping hourly spikes, unreadable as a chart.
The browser no longer gives the backend session_other/model_other
aggregate a top-N slot, which rendered two identical Other legend
entries whenever the backend fold out-ranked a real series.
---------
Co-authored-by: AgentSeal <hello@agentseal.org>
Settings gains a Usage Refresh picker mirroring the quota cadence
pattern. Auto keeps the adaptive default (30s active, battery and Low
Power backoff); fixed cadences ignore power state but an open popover
always gets the active 30s; Manual never auto-spawns, refreshing only
on popover open, Refresh Now, and first launch (wake included: manual
wakes run stuck-state cleanup without spawning). Stored in UserDefaults
as CodeBurnMenubarRefreshSeconds (-1 auto, 0 manual, else seconds) and
documented in the README with the defaults-write escape hatch.
Refs #647
Models missing from the pricing tables silently contributed $0 to every
total with no indication anywhere (the warning was gated behind
CODEBURN_VERBOSE). Add render-time detection that flags aggregated model
rows with usage but $0 cost whose pricing lookup fails right now, and
surface it in overview, report/today/month JSON (unpricedModels), the
TUI By Model panel, and the MCP get_usage summary.
Render-time detection covers cached sessions (cost is computed at parse
time) and heals as soon as pricing data, an alias, or a price override
arrives. Rows with real cost are never flagged: aggregation keys rows by
display name, which the pricing lookup misses; $0 display-name rows are
reverse-resolved to their raw id before flagging so sessions cached
before their model's pricing landed don't get a misleading alias hint.
Local models and model-savings mappings stay excluded: $0 is correct
for them.
Fixes#638
RON was added to the native macOS/GNOME pickers but not to the shared
SYMBOL_OVERRIDES map, so the CLI, CSV/JSON export, and web dashboard
resolved it through Intl to "RON" while native UI showed "lei" — a
cross-surface split for GNOME/CLI-set currency. Mirror the CNY precedent
(906c533): symbol override + fraction-digits test + README example.
The README "Data location" support matrix listed GitHub Copilot as only the
legacy CLI and VS Code transcript sources. Update the row to reflect all
sources the provider actually reads — the OpenTelemetry `agent-traces.db`
(preferred when present) and the JetBrains IDE Nitrite `.db` — and how the
project is resolved. Links to docs/providers/copilot.md for the full detail.
Bump the version, document the Zed provider (logo, provider doc, data
table row), add the audit and context commands to the README, and
refresh the stale Cursor data-source description to the composer-meter
accounting.
Leads the README with the canonical one-sentence definition (matching codeburn.app, llms.txt, and the JSON-LD) so search and AI answer engines lift a consistent description. The existing hook paragraph stays below.
Browser dashboard (codeburn web), device sharing (share/devices), new providers (Grok Build, ZCode, Hermes Agent, Kiro CLI, zerostack), Codex credit usage, plus CLI and menubar fixes. See CHANGELOG for the full list and contributor credits.
Document codeburn web and device sharing in the README and bump the package version.
* feat(overview): plain-text monthly usage overview command
Add 'codeburn overview', a copy-pasteable text report. Defaults to the
current month, with --from/--to to filter and --no-color for plain
output. Renders Totals, By tool, Top models, Highest-value days, Top
projects, a daily table, By activity, and Tools, with colored section
headings (stripped under --no-color or when piped).
Reuses the existing session aggregation. Cost gains thousands
separators and tokens roll up to a B unit for readability via
display-only wrappers, without changing the shared formatters. Project
names use the path basename instead of the sanitized full path.
* fix(cli): exit cleanly on EPIPE when the stdout pipe closes early
Piping output to a reader that closes early (| head, quitting less, a
missing command) made stdout writes throw EPIPE and crash with an
unhandled error event. Handle EPIPE on process.stdout and exit 0 so
piping the overview and other commands behaves normally.
* docs(readme): document and highlight the overview command
Add a 'Your month at a glance' section featuring codeburn overview with
examples and sample output, a Commands-table entry, and the provider
flag note.
Follow-up to #516, which was merged before these two commits had landed on the branch, so they did not make it into `main`.
Adds the remaining parts of the overhaul:
- Collapse **Commands**, **Features**, **Reading the dashboard**, **How it reads your data**, and **Environment Variables** behind `<details>` toggles so the README is short by default.
- Replace "AI coding tools" with "AI tools" in the README (3 places) and the `package.json` description.
- Lead with a story: hook, hero dashboard, and a quick start that highlights npx, global install, and the menubar app
- Restore the honeycomb logo to the top and recolor all badges to brand orange
- Replace the 28-row supported-tools table with a compact logo wall, adding icons for Warp, Mux, and Vercel AI Gateway
- Group CLI commands into copy-friendly tables
- Merge "Provider notes" and "How it reads your data" into one Provider / Data location / Notes table
- Rewrite the sponsor section
- Change the tagline to "See where your AI spend goes."
- Correct the Node version (22.13+) and the provider count