Commit graph

2517 commits

Author SHA1 Message Date
Resham Joshi
247957ff91
perf(cursor): stop JSON and menubar answers waiting on cursor.com (#1724)
* perf(cursor): stop JSON and menubar answers waiting on cursor.com

report/today/month --format json, overview and status --format menubar-json
awaited the hourly Cursor usage download (15 s cap, 45 s on the first
backfill) before parsing. The download now runs beside the command and its
import applies after the command (serve: between two requests, then its
memos are dropped), so the next run shows it. Dashboards still wait.

* test(cursor-sync): keep the in-process sync enabled when the shell disables it

* test(cursor-sync): wait for the serve memo instead of a fixed answer count

The serve test expected the second answer to be memoized, but serve only
memoizes once its root watchers are armed, which on a slow CI runner lands
after that answer. Keep asking until two answers share a generation. The
spawn now imports the fake fetch by file URL so Windows accepts the path,
and the in-process test points USERPROFILE at the temp home too.
2026-10-10 07:24:37 +02:00
Resham Joshi
6f4c3f772b
perf(models): memoize short display names by model id (#1727)
Warm reports re-derived the display name of every cached call, a linear
scan of the short-name table each time (about 0.5 s on a lifetime run).
The name depends only on the aliases and the pricing namespaces, so it is
memoized per model id and cleared when either changes.
2026-10-10 07:06:23 +02:00
Resham Joshi
e7c67a6695
perf(devin): read only the metadata fields the parser uses (#1726)
The sessions.db query returned each message's whole metadata blob and
parsed it in JS (617 MB on a real store) to use five fields. The query now
builds an object of just those fields; a missing or non-object metadata
still comes back NULL.
2026-10-10 07:06:19 +02:00
Resham Joshi
02dff282a8
perf(codex): resolve fork parents once on the main thread (#1725)
The fork-parent memo lived in module state, so every parse worker indexed
the Codex home and read the same parent rollouts again (58 reads of 10
parents, 8 GB for 1.28 GB on a real corpus). Workers now ask the main
thread over a message port, which keeps one memo for the whole parse.
2026-10-10 07:06:15 +02:00
Resham Joshi
ddacfcbf15
fix(plans): word flat subscriptions past their price as API value (#1723)
A preset subscription plan (SuperGrok, Cursor Pro, Google AI) past its price
showed "$X over" in red and "On pace to exceed", but a flat subscription is
not billed overage. Those cards now read "13.6x your plan's price in API
value" with a neutral bar and projection; custom plans keep the cap wording.
2026-10-10 07:06:10 +02:00
Resham Joshi
389c14ce5e
fix(ui): mark estimated headline totals with ~ on every hero (#1722)
#1657 put the ~ mark on estimated rows, but the headline total stayed bare on
the desktop hero, the mac hero, the Windows hero and tray text, and GNOME.
Each now applies the same 1% rule to the provider split's estimated portion
(the desktop helper moves from the VS Code summary into lib/format). Combined
device totals carry no estimated split and stay unmarked.
2026-10-10 07:05:58 +02:00
Resham Joshi
c2cfbd18d8
fix(compare): never request a model pair the current period does not list (#1721)
Switching period or provider kept the previous model pair in state, so the
report query fired once with the new period and the old models before the
facets effect reset them, and the CLI exited 1 with "model not found". Both
Cohorts and Classic now request a report only for models listed in the
current period's facets.
2026-10-10 07:05:54 +02:00
Resham Joshi
95651189e2
fix(optimize): price deferred MCP tools as name lines, once per call (#1720)
The low-coverage and project-scope findings only see servers whose tools were
deferred, yet charged 400 tokens per tool and counted every call as both a
cache write and a cache read. A deferred tool is one name line (~9 tokens),
and each call now pays it as a read, or as a write only when it read no cache.
2026-10-10 07:05:50 +02:00
Resham Joshi
aa85ed2312
fix(optimize): stop flagging delivered and editing sessions as low-worth (#1719)
The delivered check read bashBreakdown keys, which are base names (git), so
git commit / gh pr create never matched; it now reads the full command from
each call's tool sequence (Kimi Code now records one) and allows git global
options. Devin and cursor-agent edit tools count as edits, and the retry
share divides by edit steps instead of user prompts.
2026-10-10 07:05:47 +02:00
Resham Joshi
89bc4598f8
fix(cursor-agent): leave Cursor IDE chat transcripts to the cursor provider (#1717)
* fix(cursor-agent): leave Cursor IDE chat transcripts to the cursor provider

Cursor IDE agent chats write agent transcripts too, so on days without a
Cursor import they were counted by both cursor (state.vscdb) and
cursor-agent. Discovery now skips a transcript or store whose id is an IDE
composerData key; cursor keeps them with per-bubble times and models.
Daily cache v73 lets cursor-agent days shrink once.

* fix(cache): drop old cursor-agent slices the IDE parse now explains

On an existing cache, settled days kept their old cursor-agent slice after
v73 because the fresh parse no longer has one there and the merge carries
missing slices forward. While cursor-agent is pending its v73 re-derive, a
day the fresh parse explains with a cursor slice and no cursor-agent slice
drops the old cursor-agent slice; days with no fresh cursor slice keep it.
2026-10-10 07:05:35 +02:00
Resham Joshi
ed3c3f466b
fix(cursor): parse the full lookback regardless of the requested range (#1718)
The session cache keys the Cursor parse on the DB fingerprint alone, but the
parse stopped at the requested range start, so a narrow run (7 days) was served
to every wider range afterwards (30 days showed 2 calls instead of 1,680). The
parse now always reads the full 6 month lookback; the cursor parse version is
bumped so cached narrow entries re-parse.
2026-10-10 07:05:31 +02:00
Resham Joshi
4af19b73c7
fix(pricing): apply Anthropic long-context tiers to Claude calls (#1716)
Claude calls never used the LiteLLM above-threshold rates, so Haiku 5.5
requests over 100k prompt tokens (input + cache read + cache write) billed
at the base rate. claude joins TIERED_PRICING_PROVIDERS and the transcript
paths pass the provider. Long-prompt test fixtures move to Sonnet 4.6, which
has no tier, so their round figures hold.
2026-10-10 07:05:27 +02:00
Resham Joshi
514ef7081d
fix(currency): show USD instead of a foreign symbol when no FX rate is available (#1715)
When the Frankfurter fetch failed (or under CODEBURN_FX_NO_FETCH) with no
fresh cache, the rate fell back to 1 but the foreign code and symbol stayed,
so USD amounts showed as EUR/JPY. Now the last cached rate of any age is used,
and with none the display falls back to USD code and symbol.
2026-10-10 07:05:23 +02:00
Resham Joshi
039a4e483e
fix(overview): group thousands in the integer part of costs only (#1714)
The comma-grouping regex in overview and devices also matched the fraction,
so $0.0028 rendered as $0.0,028. A lookbehind now skips digits after the
decimal point.
2026-10-10 07:05:12 +02:00
Resham Joshi
b62e4a30ee
fix(cache): drop stale cursor-agent slices on days a Cursor import covers (#1710)
Some checks are pending
CI / semgrep (push) Waiting to run
Tests / test (22) (push) Waiting to run
Tests / test (22.13.0) (push) Waiting to run
Tests / test (24) (push) Waiting to run
Tests / test (26) (push) Waiting to run
Tests / test-platforms (macos-latest) (push) Waiting to run
Tests / test-platforms (windows-latest) (push) Waiting to run
Tests / desktop (push) Waiting to run
Tests / vscode (push) Waiting to run
* fix(cache): drop stale cursor-agent slices on days a Cursor import covers

On a day the import fully covers, the parse drops local cursor-agent (and
Grok Bot, when the store has its rows) calls, so the fresh day has no slice
for them and the merge carried the cached one on top of the imported rows.
Adoption and the complete re-derive now drop those slices. Bump to v72 so
caches that already carry them get repaired.

* test(cache): keep Grok Bot slices an import holds no Grok Bot rows for
2026-10-10 03:16:02 +02:00
Resham Joshi
ef58a17b81
fix(cache): keep history exact when a cache upgrade meets a timezone change (#1713)
* fix(cache): adopt the top cache file's timezone, not the machine's

Adoption kept only files in the machine's timezone whenever any file had it, so an older file in that zone pushed out the newest complete one and every day only it still held. A first run under TZ=UTC on a cache with one old UTC file dropped 46 days.
Adopt the top-priority file's timezone and let the existing timezone re-derive re-bucket the result.

* fix(cache): re-bucket an adopted older cache once after a timezone change

Adopting only older-version files built the cache with an empty savings hash,
so hydration skipped the tz subtraction and the partial-survival guard kept
old-zone days over the fresh ones, counting the hours between the two
midnights twice. Adoption now keeps the top file's hash. A tz residual over a
fresh slice with data also replaced that slice instead of adding to it.

* fix(cache): never let a timezone change inflate when the savings hash also changed

With a tz change and a savings hash change in the same re-derive (every
0.9.25 upgrade, since builtin price overrides changed the hash), the tz
subtraction was skipped and the partial-survival guard put old-zone slices back
over fresh ones, counting the hours between the two midnights twice. Now the
old-tz re-aggregation still runs: a baseline slice any surviving source explains
is dropped whole and the fresh slice wins, with no guard swap. compare
--with-history now passes the tz aggregator too.

Tradeoff: in this case the source-gone part of a partly surviving (day,
provider) is lost, since old-priced and new-priced cost cannot be split
(subtracting would carry the price drift as spend). With a matching hash the
exact subtraction still keeps it.

* fix(cache): keep a tz residual's breakdown within its own totals

The tz subtraction reduces an old slice's totals but its project, model and
category maps only key by key, so keys a fresh parse no longer produces (pre-v67
label-only projects, a project now split per worktree, renamed models) stayed
whole and the summed residual stacked them on the fresh slice. Scale each map
back to the residual's totals, keeping the old keys and whole counts.
2026-10-10 02:56:14 +02:00
Resham Joshi
5253b89286
fix(cache): keep midnight-straddling turns whole on the settle reseal (#1709)
The seal-time re-derive parsed from today-7, so a turn crossing that midnight was cut and its later part re-anchored to the window start, while the day before kept the whole turn. Category cost, turn and session counts on the window start were counted twice.
Parse one day earlier when re-deriving already sealed days and keep only the window. A stale watermark still parses from its first unsealed day, as in 0.9.25.
2026-10-10 02:56:08 +02:00
Resham Joshi
18c4d4043f
fix(projects): take project row money from the day set only (#1708)
With a day set, buildPayloadProjects also added live cost for any project
identity the days did not hold. Live per-call resolution (#1689) and bare
cursor-agent labels can put sealed calls under a new identity, so they were
counted twice and project rows summed above the period total. Rows now take
cost, savings and calls from the same days as the headline; live still
supplies sessions, details and paths.
2026-10-10 02:56:00 +02:00
Resham Joshi
ae30d677f8
fix(projects): stop the git origin walk at the folder's own repo (#1707)
The walk-up skipped a .git without an origin and kept climbing, so a
local-only repo nested in another repo, or any folder under a home dotfiles
repo, took the ancestor's origin and merged into that project row.
Now it stops at the first .git (its origin or none) and never uses home as
the repo of a folder below it.
2026-10-10 02:55:54 +02:00
Resham Joshi
7390810a61
fix(codex): count cache writes toward the long-context threshold, tier only above 272k (#1706)
The tier threshold summed input and cache read but left out cache-write
tokens, which codex splits out of input_tokens on gpt-5.6+ and gpt-6. A
280k-token prompt with 80k cache writes priced at base rates. OpenAI also
bills 272,000 exactly as short context, so the tier now starts above the
threshold. The audit recompute follows the same rule.
2026-10-10 02:55:47 +02:00
Resham Joshi
f5906a0c68
fix(copilot): price JetBrains claude-opus-4.7 as Opus 4.7 (#1705)
The dot-minor lookahead from #1531 stops claude-opus-4 matching
claude-opus-4.7, and 4.7 was not in the token list, so those turns fell
back to copilot-anthropic-auto (Sonnet 4.5 rates). Add the token and bump
the copilot session-cache parse tag so cached turns re-parse.
2026-10-10 02:55:34 +02:00
Resham Joshi
c52457faf1
chore: remove stray dist-* build folders committed in #1689 and ignore them (#1704) 2026-10-10 02:53:13 +02:00
Uttam Deb
83a18e1308
fix: make npm run dev work on Windows (#1629)
Some checks are pending
CI / semgrep (push) Waiting to run
macOS Menubar CI / test (push) Waiting to run
Tests / test-platforms (macos-latest) (push) Waiting to run
Tests / test-platforms (windows-latest) (push) Waiting to run
Tests / desktop (push) Waiting to run
Tests / vscode (push) Waiting to run
Windows Menubar CI / check (ubuntu-latest) (push) Waiting to run
Windows Menubar CI / check (windows-latest) (push) Waiting to run
Tests / test (22) (push) Waiting to run
Tests / test (22.13.0) (push) Waiting to run
Tests / test (24) (push) Waiting to run
Tests / test (26) (push) Waiting to run
npm run dev now works on Windows: the NODE_OPTIONS prefix was POSIX-only, so the script runs node --no-deprecation --import tsx directly.
2026-10-09 13:38:06 +02:00
ozymandiashh
a01bf87412
feat(codex): show thread names from session_index.jsonl (#1687)
Codex sessions now show their thread names from session_index.jsonl, applied after the cache, so renames show without a re-parse. Closes #1625.
2026-10-09 13:25:13 +02:00
Resham Joshi
b876a311e2
feat: telemetry for CLI error causes, provider read failures and update results (#1702)
cli_error gains duration, exit, a locally classified reason and the scoped provider. New provider_read_fail (desktop) and update_result (desktop, menubar, tray) events, enums only.
2026-10-09 12:47:49 +02:00
Resham Joshi
a0e66e3fcd
fix: desktop not-found panel gives app advice, not npm (#1701)
For a bundled CLI the not-found panel now tells desktop users to reopen or reinstall the app instead of installing from npm. Strings in all six locales.
2026-10-09 12:31:19 +02:00
Resham Joshi
1bb697b7cf
fix: tell a missing bundled CLI from a refused or failed stat (#1700)
Some checks are pending
CI / semgrep (push) Waiting to run
Tests / test (22) (push) Waiting to run
Tests / test (22.13.0) (push) Waiting to run
Tests / test (24) (push) Waiting to run
Tests / test (26) (push) Waiting to run
Tests / test-platforms (macos-latest) (push) Waiting to run
Tests / test-platforms (windows-latest) (push) Waiting to run
Tests / desktop (push) Waiting to run
Tests / vscode (push) Waiting to run
The not-found telemetry now tells a missing bundled CLI apart from a refused or failed stat: bundled-missing, bundled-denied, bundled-unreadable.
2026-10-08 22:37:37 +02:00
Resham Joshi
3c423996e4
chore: update vulnerable transitive dependencies (#1699)
Lockfile-only updates: @hono/node-server 1.19.17 in the CLI; xmldom, postcss, browserslist, baseline-browser-mapping and shell-quote in the desktop app. No major bumps.
2026-10-08 22:04:31 +02:00
Resham Joshi
1fba972580
fix: Cursor import clears covered days on a new build's first run (#1698)
invalidateProviderDays no longer skips when the build has no daily-cache file yet, so the first Cursor import clears the covered days. cursor joins the pending re-derive list at v71 so stuck caches repair once.
2026-10-08 21:56:22 +02:00
Resham Joshi
9d9ac21d59
chore: refresh bundled LiteLLM price snapshot (#1697)
Regenerated with npm run bundle-litellm. Sonnet 5.5 cache read is now the official $0.10 per million; adds Haiku 5.5, GPT-6.1 Sol and other upstream rows.
2026-10-08 21:33:05 +02:00
Resham Joshi
b875d9ca1d
fix: one timezone per daily cache, re-derive settling days on seal (#1696)
Cache adoption keeps one timezone and prefers complete parses. Sealing a day re-derives the last seven, and a sealed day only takes a fresh parse with at least as many calls.
2026-10-08 20:18:23 +02:00
Resham Joshi
eb51aba46a
feat: project links put a folder in a repo project (#1695)
Adds codeburn project link <folder> <project>, project unlink <folder> and
project links, so a folder that is not a checkout of a repo can join that
repo's project row. Links live in config.json, apply at report time
wherever rows are grouped or filtered, cover subfolders (longest link
wins), and never touch the day cache, so unlink works on cached days.
2026-10-08 17:41:23 +02:00
Resham Joshi
f63fd960f6
fix: fold subagents into top sessions (#1694)
Some checks are pending
CI / semgrep (push) Waiting to run
Tests / test (22) (push) Waiting to run
Tests / test (22.13.0) (push) Waiting to run
Tests / test (24) (push) Waiting to run
Tests / test (26) (push) Waiting to run
Tests / test-platforms (macos-latest) (push) Waiting to run
Tests / test-platforms (windows-latest) (push) Waiting to run
Tests / desktop (push) Waiting to run
Tests / vscode (push) Waiting to run
Top sessions in the JSON report and the menubar/desktop payload ranked each
session by its own cost, so a parent showed without its subagents and a
subagent could show as its own row. Both producers now go through
foldedSessionRows, the same fold the sessions list uses. The Overview model
label matches a top session by provider and id, since its cost and calls
now include subagents.

Co-authored-by: Resham Joshi <resham@codeburn.app>
2026-10-08 13:08:55 +02:00
Resham Joshi
8fb478904e
feat: group a deleted sibling clone with its repository by folder name (#1692)
* feat(app): transient project selector in the desktop top bar

Scopes every report to one project path for the current session through
the same narrowing the VS Code workspace scope uses. The saved project
filter is never written; a restart is back on all projects.

* fix(app): let the name pickers ellipsize before the top bar overflows

* fix: key the daily project split per real path, not per label

A project label can span several paths: every Claude session started from the
home folder shares -Users-<name>, while its cwd puts it in a different project.
The day rollup keyed by label kept the first path it saw, so a rooted
--project headline took the whole label bucket on some days and missed it on
others. Key per (label, path), read old label-keyed days unchanged, bump the
daily cache to v68.

* fix(app): list only selectable, non-zero projects in the top bar picker

Rows with no session cwd (the Cursor and Grok Bot imports, provider label
fallbacks) report their label as the path, so the picker offered names the
bridge refuses and dash-to-slash guesses like eywa/lab. Keep only absolute
paths, and drop rows whose lifetime cost rounds to $0.00. The old test that
rooted a slashless Codex path is replaced: Codex now records the absolute cwd,
and a slashless path is always the label fallback.

* fix(app): show a toast when a project pick is refused

The pick was dropped silently. Also pin that an encoded -Users-... label
never reaches the picker list.

* feat: group projects by git repository

Clones and worktrees that share an origin remote are one project in every
project list (report JSON, By Project, the top bar picker, the terminal
dashboard), with the checkouts listed under the row. A --project path inside
a checkout scopes to the whole repository; --exact-project keeps the old
single-folder match. The origin is learned while the folder exists, kept in
git-origins.json and on each day's project entry (daily cache v69), so a
deleted scratch clone stays in its repository. The report JSON project list
now comes from the durable day set, so a row costs what selecting it reports.

* fix: a picked project row selects that row exactly

The top bar pick sends =<path>: a checkout in a repository still selects the
whole repository, and a plain folder selects itself without the folders under
it, which are rows of their own. So the picker row and the headline it opens
are the same set. Typed --project paths keep their prefix match. Days adopted
from an older cache learn the origin of every checkout that still exists, and
lookups outside a parse are saved on exit.

* fix: key the status snapshot on --exact-project

* feat: one Temporary folders row for scratch folders outside a repository

Every project path under a temp root (os.tmpdir(), /tmp, /var/folders and
their /private spellings) that is not a checkout of a known repository folds
into one row, in the report JSON, By Project, the terminal dashboard, the top
bar picker and the Settings Projects pane. Its pattern @temp selects or hides
all of them. The Projects pane leaves out rows that round to $0.00 unless a
saved pattern names them, and a saved pattern naming any checkout of a
repository row now names the whole row in the renderer too.

* feat: group a deleted sibling folder with its repository by folder name

A deleted folder with no recorded origin, named <checkout>-<suffix> or
<checkout>_<suffix> next to exactly one repository's checkout, joins that
repository row. The checkout entry carries matchedByFolderName and the Spend
drill-down labels it. Existing folders and names two repositories could claim
are left alone.

* feat: the longest checkout name wins a folder-name match

A deleted folder that fits several sibling checkouts joins the one with the
longest name; it is skipped only when the longest fits belong to two
repositories. The report project type declares matchedByFolderName.

* fix(claude): attribute each call to the project of its own cwd

* test: fold the temp roots the tests set, compare checkout ids as identities (Windows)

* test: compare folder-name checkout ids as identities (Windows)

* fix(claude): keep subfolder cwds in their project, count and show a split session once

* fix: an exclude path hides that checkout only, repository rows count a session once

* feat: mark folder-name matches in the CLI report and the project picker

* fix(claude): a deleted subfolder stays its own project
2026-10-08 06:54:41 +02:00
Resham Joshi
bc62059744
feat: group projects by git repository (#1691)
* feat(app): transient project selector in the desktop top bar

Scopes every report to one project path for the current session through
the same narrowing the VS Code workspace scope uses. The saved project
filter is never written; a restart is back on all projects.

* fix(app): let the name pickers ellipsize before the top bar overflows

* fix: key the daily project split per real path, not per label

A project label can span several paths: every Claude session started from the
home folder shares -Users-<name>, while its cwd puts it in a different project.
The day rollup keyed by label kept the first path it saw, so a rooted
--project headline took the whole label bucket on some days and missed it on
others. Key per (label, path), read old label-keyed days unchanged, bump the
daily cache to v68.

* fix(app): list only selectable, non-zero projects in the top bar picker

Rows with no session cwd (the Cursor and Grok Bot imports, provider label
fallbacks) report their label as the path, so the picker offered names the
bridge refuses and dash-to-slash guesses like eywa/lab. Keep only absolute
paths, and drop rows whose lifetime cost rounds to $0.00. The old test that
rooted a slashless Codex path is replaced: Codex now records the absolute cwd,
and a slashless path is always the label fallback.

* fix(app): show a toast when a project pick is refused

The pick was dropped silently. Also pin that an encoded -Users-... label
never reaches the picker list.

* feat: group projects by git repository

Clones and worktrees that share an origin remote are one project in every
project list (report JSON, By Project, the top bar picker, the terminal
dashboard), with the checkouts listed under the row. A --project path inside
a checkout scopes to the whole repository; --exact-project keeps the old
single-folder match. The origin is learned while the folder exists, kept in
git-origins.json and on each day's project entry (daily cache v69), so a
deleted scratch clone stays in its repository. The report JSON project list
now comes from the durable day set, so a row costs what selecting it reports.

* fix: a picked project row selects that row exactly

The top bar pick sends =<path>: a checkout in a repository still selects the
whole repository, and a plain folder selects itself without the folders under
it, which are rows of their own. So the picker row and the headline it opens
are the same set. Typed --project paths keep their prefix match. Days adopted
from an older cache learn the origin of every checkout that still exists, and
lookups outside a parse are saved on exit.

* fix: key the status snapshot on --exact-project

* feat: one Temporary folders row for scratch folders outside a repository

Every project path under a temp root (os.tmpdir(), /tmp, /var/folders and
their /private spellings) that is not a checkout of a known repository folds
into one row, in the report JSON, By Project, the terminal dashboard, the top
bar picker and the Settings Projects pane. Its pattern @temp selects or hides
all of them. The Projects pane leaves out rows that round to $0.00 unless a
saved pattern names them, and a saved pattern naming any checkout of a
repository row now names the whole row in the renderer too.

* fix(claude): attribute each call to the project of its own cwd

* test: fold the temp roots the tests set, compare checkout ids as identities (Windows)

* fix(claude): keep subfolder cwds in their project, count and show a split session once

* fix: an exclude path hides that checkout only, repository rows count a session once

* fix(claude): a deleted subfolder stays its own project
2026-10-08 06:45:26 +02:00
Resham Joshi
d49a6a4eba
fix(claude): attribute each call to the project of its own cwd (#1689)
* fix(claude): attribute each call to the project of its own cwd

* fix(claude): keep subfolder cwds in their project, count and show a split session once

* fix(claude): a deleted subfolder stays its own project
2026-10-08 06:28:32 +02:00
Resham Joshi
d3fecffa9a
feat(sessions): fold subagent sessions into their parent row (#1690)
* feat(sessions): fold subagent sessions into their parent row

The default sessions list (table, JSON, TUI, contributions, desktop) now shows
one row per parent session with its provider-recorded subagents summed in and
listed under subagents. Grouping reuses the work-unit resolver, so only rows
move; totals are unchanged. --by-work-unit keeps the flat rows.

* test: reconcile the session diagnosis with the folded sessions row

* fix(sessions): find and open a parent row by its subagents, count subagents apart from top-level rows
2026-10-08 06:27:58 +02:00
Resham Joshi
1192816407
docs: note the Claude Code usage CodeBurn cannot see in transcripts (#1693)
Some checks failed
CI / semgrep (push) Waiting to run
Tests / test (22) (push) Waiting to run
Tests / test (22.13.0) (push) Waiting to run
Tests / test (24) (push) Waiting to run
Tests / test (26) (push) Waiting to run
Tests / test-platforms (macos-latest) (push) Waiting to run
Tests / test-platforms (windows-latest) (push) Waiting to run
Tests / desktop (push) Waiting to run
Tests / vscode (push) Waiting to run
macOS Menubar CI / test (push) Has been cancelled
Windows Menubar CI / check (ubuntu-latest) (push) Has been cancelled
Windows Menubar CI / check (windows-latest) (push) Has been cancelled
2026-10-08 05:48:29 +02:00
Resham Joshi
687ca2f19c
fix(kimicode): use state.json cwd when workDir is absent (#1688)
Kimi Code now writes cwd instead of workDir. Without it the project path
was decoded from the wd_ directory name, so /x/crewroom-app-mem5 became
crewroom/app/mem5 and never joined its repository. Cost is unchanged;
only the per-project split moves.
2026-10-08 05:48:17 +02:00
Resham Joshi
fce75d5420
feat(app,windows): one-click updates for the desktop app and the Windows tray (#1685)
* feat(desktop): one-click updates through electron-updater on the update-feeds release

* feat(tray): signed one-click updates through tauri-plugin-updater; feed publishing and release docs

* ci(tray): build without the updater key until it is configured

* chore(windows): set the tray updater public key

* ci(windows): skip updater signing in the release build smoke

* ci(windows): build without updater artifacts when no signing key is available

* ci(windows): turn off updater artifacts through TAURI_CONFIG, not CLI flags pwsh mangles

* ci(windows): run tauri build under bash so --no-sign reaches the CLI (pwsh drops the -- separator)
2026-10-08 05:06:55 +02:00
Resham Joshi
5e3308e0b8
feat(menubar): sign and notarize in CI, pin updates to our team, fixed update feed (#1684)
* feat(menubar): CI Developer ID signing, team-pinned installs, update feed

- release-menubar.yml imports the Developer ID cert, signs with hardened
  runtime and timestamp, notarizes with an App Store Connect key, staples,
  and fails when the signing secrets are missing
- the installer refuses bundles not signed by team XRVP7P7F9M or rejected
  by Gatekeeper
- a rolling update-feeds prerelease carries menubar-latest.json, written
  last after the published zip is checked; installer and update check read
  it before scanning mac-v releases
- the update pill skips the CLI step for the desktop app's bundled CLI or
  a CLI with no package manager, explains npm permission errors, and
  allows longer update timeouts
- RELEASING.md matches what CI does and lists the required secrets

* docs(menubar): DISTRIBUTION.md points at CI signing; retry the feed's asset check

* fix(menubar): popover shows only the Update button; command footer appears only after a failed update
2026-10-08 04:52:56 +02:00
Resham Joshi
75d557e87b
feat(app): transient project selector in the desktop top bar (#1680)
Some checks are pending
CI / semgrep (push) Waiting to run
macOS Menubar CI / test (push) Waiting to run
Tests / test (22) (push) Waiting to run
Tests / test (22.13.0) (push) Waiting to run
Tests / test (24) (push) Waiting to run
Tests / test (26) (push) Waiting to run
Tests / test-platforms (macos-latest) (push) Waiting to run
Tests / test-platforms (windows-latest) (push) Waiting to run
Tests / desktop (push) Waiting to run
Tests / vscode (push) Waiting to run
Windows Menubar CI / check (ubuntu-latest) (push) Waiting to run
Windows Menubar CI / check (windows-latest) (push) Waiting to run
* feat(app): transient project selector in the desktop top bar

Scopes every report to one project path for the current session through
the same narrowing the VS Code workspace scope uses. The saved project
filter is never written; a restart is back on all projects.

* fix(app): let the name pickers ellipsize before the top bar overflows

* fix(app): list only selectable, non-zero projects in the top bar picker

Rows with no session cwd (the Cursor and Grok Bot imports, provider label
fallbacks) report their label as the path, so the picker offered names the
bridge refuses and dash-to-slash guesses like eywa/lab. Keep only absolute
paths, and drop rows whose lifetime cost rounds to $0.00. The old test that
rooted a slashless Codex path is replaced: Codex now records the absolute cwd,
and a slashless path is always the label fallback.

* fix(app): show a toast when a project pick is refused

The pick was dropped silently. Also pin that an encoded -Users-... label
never reaches the picker list.
2026-10-08 00:51:31 +02:00
Resham Joshi
01705cf8f2
fix: key the daily project split per real path, not per label (#1679)
A project label can span several paths: every Claude session started from the
home folder shares -Users-<name>, while its cwd puts it in a different project.
The day rollup keyed by label kept the first path it saw, so a rooted
--project headline took the whole label bucket on some days and missed it on
others. Key per (label, path), read old label-keyed days unchanged, bump the
daily cache to v67.
2026-10-08 00:39:18 +02:00
Resham Joshi
1284290743
fix(codex): mask fork replay records against the parent rollout (#1678)
* fix(codex): mask fork replay records against the parent rollout

A fork's replay burst was dropped whole, losing calls that exist only in
the fork. Drop a burst record only when the parent rollout recorded it
before the fork, and count the rest as their own calls. Parent missing or
a burst that does not open with a parent record keeps the old behavior.

Bumps CODEX_CACHE_VERSION to 22 and DAILY_CACHE_VERSION to 66.

* fix(codex): bump the codex parse version for fork masking, fix the comments

Cached forks that dropped the whole burst need to re-parse, so the codex
parse version gains codex-fork-mask-v1. The burst records that now count
are the parent's work its rollout kept only inside a running total, not
fork-only usage.
2026-10-08 00:27:52 +02:00
Resham Joshi
3c186491c3
fix(grok): read per-request usage from logs/unified.jsonl (#1677)
* fix(grok): read per-inference usage from logs/unified.jsonl

Grok Build keeps logging every inference to ~/.grok/logs/unified.jsonl after
its session dirs are gone, so CodeBurn showed $0 for that usage. Read
shell.turn.inference_done records (prompt includes cached, completion includes
reasoning), with the model from the session's model changed event and the
project from session created. Sessions that still have a session dir are
skipped so they are not counted twice. DAILY_CACHE_VERSION 65.

* fix(grok): prefer the unified log over session-dir rollups

A session with inference records in logs/unified.jsonl is now read from the
log, one call per request, and its session dir is skipped. Session dirs only
count for sessions the log no longer holds. This keeps history when session
dirs are deleted after the log was cached, and prices grok-4.6's long-context
tier per request instead of on a session total. Logged calls can move to an
earlier day than the rollup, so grok joins PENDING_REDERIVE at 65.

* fix(grok): re-read skipped session dirs after log rotation, keep their tools

A session dir the unified log holds parses to nothing, and its fingerprint
does not track the log, so a rotated or truncated log left that empty
result cached. Empty grok session-dir entries now re-parse.

The skipped dir's summary, tools, bash commands and subagents now ride on
that session's first logged call, and its model and cwd fill in when the
log names neither. A call whose model nothing names is priced as
grok-build and marked estimated.
2026-10-08 00:14:53 +02:00
Resham Joshi
c826f1a479
fix(models): price kimi-for-coding by the model it served on the call date (#1676)
* fix(models): price kimi-for-coding by the model it served on the call date

kimi-for-coding is a moving alias. It priced as retired K2 Thinking for
every call. It now prices as K2.5 from 27 Jan 2026, K2.6 from 13 Apr and
K2.7 Code from 12 Jun (K2.8 Preview from 11 Sep has no published price,
so it stays on K2.7 Code). kimi-for-coding-highspeed prices at Moonshot's
K2.7 Code HighSpeed rate instead of $0. Daily cache v64.

* fix(models): mark K2.8 Preview kimi-for-coding calls as estimated

From 11 Sep 2026 kimi-for-coding served K2.8 Preview, which has no
published rate and prices as K2.7 Code. Those calls now carry the
estimated flag. The legacy kimi provider prices by the dated model too.

* fix(models): flag the K2.8 Preview stand-in where every call is read

cachedCallToApiCall now marks kimi-for-coding calls from 11 Sep 2026
estimated, so the flag reaches every provider and cached reads without a
parse bump. Calls with a reported cost are left alone. The kimi provider's
own flag and its parse version entry go, as they only duplicated this.
2026-10-08 00:02:38 +02:00
Resham Joshi
d049b38255
fix(cline-cli): stop billing cache tokens twice (#1675)
Cline CLI's metrics.inputTokens is the full prompt, cache reads and writes
included; Cline's own pricing bills max(0, input - cacheRead - cacheWrite)
at the input rate. We treated it as uncached input, so every cache read was
also charged at the full input rate. The split now happens in parseMetrics,
covering per-message and rollup calls.

Bumps the cline-cli parse version so cached calls re-parse and the daily
cache to v63 so settled days re-derive. Call counts are unchanged.
2026-10-07 23:51:10 +02:00
Resham Joshi
4332b1762a
feat: Google AI plan presets and the Antigravity tier label (#1683)
* feat: Google AI plan presets and the Antigravity tier label (#1614)

Plan presets google-ai-pro, google-ai-ultra-5x and google-ai-ultra-20x
at Google's US monthly prices, scoped to Antigravity usage.

The Antigravity quota readers (CLI, desktop, menu bar) now also ask
GetUserStatus when the summary answers and label the windows with
userTier.name. planStatus.planInfo is not used: it says Pro on a free
tier account.

* docs: Antigravity probe comments and README preset list
2026-10-07 23:34:49 +02:00
Resham Joshi
39b9b3adcd
feat(quota): Command Code quota and ClinePass from the Cline sign-in (#1682)
* feat(quota): Command Code quota and ClinePass from the Cline sign-in

Command Code: reads the CLI's ~/.commandcode/auth.json key and the billing
credits and subscription endpoints. 5-hour and weekly windows as used of
cap, remaining credits as a note, plan from planId. Live in the Mac dock
from the local CLI, in codeburn quota and the Windows dock.

ClinePass: without a saved or env key, falls back to the Cline CLI's
providers.json session (accessToken, then apiKey, then auth.apiKey, with
Cline's path overrides). Read-only; an expired session stops before the
network and says to run cline. The Mac catalog adds the local CLI source
so Automatic connects without a key.

* fix(quota): keep retrying after an expired Cline sign-in

Running cline refreshes the session file CodeBurn only reads, so an
expired or rejected Cline session is now a retryable failure that keeps
the last quota and shows the guidance, on the Mac and in the CLI. A
rejected API key and a missing credential stay terminal.

* test(quota): build expected Cline paths with path.join for Windows
2026-10-07 23:34:31 +02:00
Resham Joshi
6639437cd3
feat(mistral-vibe): scan WSL homes for sessions (#1681)
* Scan WSL homes for Mistral Vibe sessions (#1630)

* style(mistral-vibe): indent discoverRoot, drop the issue number from a comment
2026-10-07 23:34:15 +02:00