Commit graph

2420 commits

Author SHA1 Message Date
Dan Caldr
1e83611289
feat(antigravity): align tool parsing, MCP attribution, and activity classification (#1620)
* feat(antigravity): align tool parsing, MCP attribution, and activity classification

Extends Antigravity tool classification and MCP normalization:
- Classify manage_task as planning and search_web/read_url_content as exploration in TASK_TOOLS/SEARCH_TOOLS.
- Recognize invoke_subagent in hasAgentSpawn alongside Agent in parser.ts to categorize delegation turns.
- Implement and export normalizeAntigravityToolCall to normalize both eager mcp_<server>_<tool> and lazy call_mcp_tool into canonical mcp__<server>__<tool>.
- Connect toolDisplayName to normalizeAntigravityToolCall.
- Bump ANTIGRAVITY_CACHE_VERSION to 7 and PROVIDER_PARSE_VERSIONS.antigravity to worktree-project-grouping-v7 so existing cached sessions re-parse and gain eager MCP attribution.
- Add comprehensive unit tests in classifier and provider suites.

* refactor(antigravity): map tool names in the provider, not the shared classifier; daily cache bump

---------

Co-authored-by: Resham Joshi <65915470+iamtoruk@users.noreply.github.com>
2026-10-04 20:05:07 +02:00
dependabot[bot]
5be059702f
chore(deps-dev): bump axios from 1.18.1 to 1.20.0 in /app (#1602)
Some checks are pending
CI / semgrep (push) Waiting to run
Tests / test (22.13.0) (push) Waiting to run
Tests / test (24) (push) Waiting to run
Tests / test (22) (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
Bumps [axios](https://github.com/axios/axios) from 1.18.1 to 1.20.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.18.1...v1.20.0)

---
updated-dependencies:
- dependency-name: axios
  dependency-version: 1.20.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-04 00:04:56 +02:00
dependabot[bot]
e4cb1b01ec
chore(deps): bump ip-address from 10.7.0 to 10.7.3 (#1601)
Bumps [ip-address](https://github.com/beaugunderson/ip-address) from 10.7.0 to 10.7.3.
- [Release notes](https://github.com/beaugunderson/ip-address/releases)
- [Commits](https://github.com/beaugunderson/ip-address/compare/v10.7.0...v10.7.3)

---
updated-dependencies:
- dependency-name: ip-address
  dependency-version: 10.7.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-03 23:36:14 +02:00
Uttam Deb
09778253a5
Restore input usage in Copilot chat-session journals (#1607)
* Add regressions for request-level Copilot journal usage

* Read request-level input tokens from Copilot journals

* Refresh cached Copilot journal usage and settled days

* Use local date keys in the journal cache regression
2026-10-03 23:32:28 +02:00
dependabot[bot]
c0c80805b2
chore(deps): bump fast-uri from 3.1.7 to 3.1.8 (#1600)
Bumps [fast-uri](https://github.com/fastify/fast-uri) from 3.1.7 to 3.1.8.
- [Release notes](https://github.com/fastify/fast-uri/releases)
- [Commits](https://github.com/fastify/fast-uri/compare/v3.1.7...v3.1.8)

---
updated-dependencies:
- dependency-name: fast-uri
  dependency-version: 3.1.8
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-03 23:12:44 +02:00
Resham Joshi
aded4c2326
feat(devin): plan and quota from the Devin CLI cache (#1606)
Some checks failed
Tests / desktop (push) Has been cancelled
Tests / test-platforms (windows-latest) (push) Has been cancelled
Windows Menubar CI / check (ubuntu-latest) (push) Has been cancelled
Windows Menubar CI / check (windows-latest) (push) Has been cancelled
CI / semgrep (push) Has been cancelled
Tests / test (22) (push) Has been cancelled
Tests / test (22.13.0) (push) Has been cancelled
Tests / test (26) (push) Has been cancelled
Tests / test-platforms (macos-latest) (push) Has been cancelled
Tests / test (24) (push) Has been cancelled
macOS Menubar CI / test (push) Has been cancelled
* feat(quota): Devin plan quota from the Devin CLI's local cache

Reads the newest ~/.cache/devin/cli/user_status.*.bin and walks only the
plan status message of its protobuf payload: plan name, daily and weekly
remaining percent and their resets. No network call and no API key; each
reading says how old the cache is. Any out-of-range field fails the read
instead of showing a number, and a window whose reset has passed since
the fetch is dropped.

CLI reader feeds codeburn quota and the Windows dock; the Mac Capacity
Dock gets the same decoder, and Devin moves from browser session to
local CLI, live.

* docs(windows): count twelve quota readers

* fix(app): list Devin among menu bar quota providers
2026-10-02 16:43:15 +02:00
Resham Joshi
bf91dc17cb
feat(devin): read usage from sessions.db (#1605)
* feat(devin): read usage from sessions.db

Devin keeps every request in sessions.db message_nodes; the transcript
exports hold only a few sessions. Usage now comes from the store, one
source per non-hidden session, read in node_id keyset batches with only
the needed JSON fields pulled. Sibling retries share a request_id and
dedup on it; off-main-chain requests count. SQLITE_BUSY is rethrown so
the refresh retries. Transcripts are read only when the database is
missing or has no message_nodes, so the two never double count.

The legacy metadata.metrics path no longer carves cache reads out of an
input_tokens count that never included them.

sessions.db sources rely on the WAL-folded fingerprint instead of a
forced reparse. Parse version sessions-db-v1; daily cache v43 with devin
in PENDING_REDERIVE, since transcript-era days dated steps on the
session's last activity.

* fix(devin): take only text user content as the prompt

* test(daily-cache): include devin in pending re-derive expectations
2026-10-02 16:42:57 +02:00
Resham Joshi
a7ca8bdb94
test(mac): fixed names for scratch settings suites (#1576)
* test(mac): clean up scratch UserDefaults suites, guard against new leaks

* test(mac): fixed suite names so late cfprefsd write-backs reuse one file per test

* test(mac): start every scratch suite clean
2026-10-02 16:18:38 +02:00
Resham Joshi
c17e7b05aa
fix(amp): Windows guard reads the AMP_DATA_DIR list and watches threads/ (#1604)
* fix(amp): update stale ledger comment; split AMP_DATA_DIR list in the Windows guard

* fix(amp): watch thread subfolders under each Amp root in the Windows guard
2026-10-02 15:59:08 +02:00
ozymandiashh
15e789ba53
fix(zcode): attribute PR-linked spend by reading user prompts from the transcript tables (#1581)
Some checks are pending
CI / semgrep (push) Waiting to run
macOS Menubar CI / test (push) Waiting to run
Tests / desktop (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 / test (22) (push) Waiting to run
Tests / test (22.13.0) (push) Waiting to run
Windows Menubar CI / check (ubuntu-latest) (push) Waiting to run
Windows Menubar CI / check (windows-latest) (push) Waiting to run
* fix(zcode): attribute PR-linked spend by reading user prompts from the transcript tables

The ZCode provider emitted every call with an empty userMessage and no
prLinks, so the shared attribution layer had nothing to correlate and
ZCode sessions never appeared under attributed pull requests - even
though the references sit right there in the same SQLite database: a
user message's anchor.turnId matches model_usage.turn_id, and its text
(metadata.inputIntent.text, else the message's text parts) carries the
GitHub PR URLs.

Read the message/part tables per session and emit per-turn prompt text
plus the session-wide PR URL set. The parser layer then extracts
per-turn prRefs from userMessage and seeds the cached file's
session-level prLinks, exactly like every other provider. A DB without
the transcript tables degrades to the previous behavior.

Parse version bumped (pr-attribution-v1) so cached ZCode sessions
re-parse once and gain the fields.

* fix(zcode): rethrow busy db, read only user parts, daily cache v45

---------

Co-authored-by: Resham Joshi <65915470+iamtoruk@users.noreply.github.com>
2026-10-02 12:13:37 +02:00
dependabot[bot]
042eac04e9
chore(deps-dev): bump undici from 6.27.0 to 6.29.0 in /app (#1588)
Bumps [undici](https://github.com/nodejs/undici) from 6.27.0 to 6.29.0.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v6.27.0...v6.29.0)

---
updated-dependencies:
- dependency-name: undici
  dependency-version: 6.29.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-02 11:53:38 +02:00
Uttam Deb
ce19e28ca6
Count Claude queued prompts as turns (#1582)
* Add regression coverage for Claude queued prompts

* Count queued Claude human prompts in turn grouping

* Cover queued prompts through Claude session cache

* Reparse cached Claude turns for queued prompts

* Refresh daily categories after Claude turn regrouping

* fix(claude): count only human queued prompts, skip peer agent messages

---------

Co-authored-by: Resham Joshi <65915470+iamtoruk@users.noreply.github.com>
2026-10-02 11:48:12 +02:00
Resham Joshi
fd54831891
feat(menubar): Cost/Tokens toggle on the Trend chart, Cost by default (#1603)
* feat(menubar): Cost/Tokens toggle on the Trend chart, Cost by default

Bar height tracked tokens, so a cheap high-token day looked bigger than an
expensive low-token one. The choice is remembered across launches.

* test(menubar): cover the trend Cost/Tokens toggle default and fallback

---------

Co-authored-by: Jay Johnston <750504+jayjohnston@users.noreply.github.com>
2026-10-02 11:18:57 +02:00
dependabot[bot]
286f2ebbb8
chore(deps): bump the minor-and-patch group in /dash with 2 updates (#1589)
Bumps the minor-and-patch group in /dash with 2 updates: [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) and [tailwind-merge](https://github.com/dcastil/tailwind-merge/tree/HEAD/packages/tailwind-merge).


Updates `@tanstack/react-query` from 5.102.8 to 5.104.0
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.104.0/packages/react-query)

Updates `tailwind-merge` from 3.6.0 to 3.7.0
- [Release notes](https://github.com/dcastil/tailwind-merge/releases)
- [Commits](https://github.com/dcastil/tailwind-merge/commits/tailwind-merge@3.7.0/packages/tailwind-merge)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query"
  dependency-version: 5.104.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: tailwind-merge
  dependency-version: 3.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-02 11:10:17 +02:00
dependabot[bot]
bc504fac1d
chore(deps-dev): bump the minor-and-patch group in /app with 2 updates (#1591)
Bumps the minor-and-patch group in /app with 2 updates: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) and [electron](https://github.com/electron/electron).


Updates `@types/node` from 26.5.1 to 26.6.3
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `electron` from 43.7.0 to 43.7.5
- [Release notes](https://github.com/electron/electron/releases)
- [Commits](https://github.com/electron/electron/compare/v43.7.0...v43.7.5)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 26.6.3
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: electron
  dependency-version: 43.7.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-02 11:10:03 +02:00
dependabot[bot]
ac9bcd9607
chore(deps): bump the minor-and-patch group with 5 updates (#1592)
Bumps the minor-and-patch group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk) | `1.30.0` | `1.30.1` |
| [undici](https://github.com/nodejs/undici) | `7.27.2` | `7.30.0` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `22.19.17` | `22.20.4` |
| [tsx](https://github.com/privatenumber/tsx) | `4.23.13` | `4.23.15` |
| [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `3.2.6` | `3.2.7` |


Updates `@modelcontextprotocol/sdk` from 1.30.0 to 1.30.1
- [Release notes](https://github.com/modelcontextprotocol/typescript-sdk/releases)
- [Commits](https://github.com/modelcontextprotocol/typescript-sdk/compare/1.30.0...1.30.1)

Updates `undici` from 7.27.2 to 7.30.0
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v7.27.2...v7.30.0)

Updates `@types/node` from 22.19.17 to 22.20.4
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `tsx` from 4.23.13 to 4.23.15
- [Release notes](https://github.com/privatenumber/tsx/releases)
- [Changelog](https://github.com/privatenumber/tsx/blob/master/release.config.cjs)
- [Commits](https://github.com/privatenumber/tsx/compare/v4.23.13...v4.23.15)

Updates `vitest` from 3.2.6 to 3.2.7
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v3.2.7/packages/vitest)

---
updated-dependencies:
- dependency-name: "@modelcontextprotocol/sdk"
  dependency-version: 1.30.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
- dependency-name: undici
  dependency-version: 7.30.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: "@types/node"
  dependency-version: 22.20.4
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: tsx
  dependency-version: 4.23.15
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
- dependency-name: vitest
  dependency-version: 3.2.7
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-02 11:09:48 +02:00
ozymandiashh
9a4a5fca82
Classify GLM-5.3 and Flash spend tiers (#1598) 2026-10-02 10:47:05 +02:00
ozymandiashh
157347aa99
feat: Amp support - read the local thread mirror (#1572) (#1578)
* feat: Amp support - read the local thread mirror (#1572)

Amp (Sourcegraph's coding agent) mirrors every thread it serves as one
JSON document per thread at ~/.local/share/amp/threads/ (AMP_DATA_DIR
honored, comma-separated). Each file is { id, messages,
usageLedger?{events} }; the ledger's events are the per-request record
(tokens.input/output, cache tokens joined from the billed message
through toMessageId -> messages[].messageId), with a per-assistant-
message usage fallback for threads without a ledger and a total-only
record billing as output.

Amp bills a subscription and records no charged dollars, so every call
is priced from the underlying model's token rates and marked
costIsEstimated; the recorded credits field is ignored (no published
per-credit dollar rate). Thread files carry no cwd, so sessions group
under the provider name. Registered eager; parse version
usage-ledger-v1; no artwork yet (mono-initial fallback, like Codebuff).

Surfaces: CLI registry + doctor probe roots, Electron sandbox read
paths + menubar catalog (Amp after Cursor, matching the Swift order),
Windows tray tab color + usage_guard root, GNOME prefs dropdown, macOS
ProviderConnectionCatalog, docs/providers/amp.md, README tool list,
CHANGELOG.

* fix: address Amp provider review feedback
2026-10-02 10:36:05 +02:00
Swizzy
d3929746ae
fix(dock): serialize claudeProfiles in camelCase on DockQuota::Ready (#1594)
serde's rename_all on an internally tagged enum only renames the
variant tag, not the fields of a struct-like variant, so this field
shipped as claude_profiles. The frontend reads answer.claudeProfiles,
so the Claude profiles settings row and the per-config dock rings
from #1570 never showed.

Adds a field-level rename plus a test pinning the serialized key.
2026-10-02 10:28:54 +02:00
ozymandiashh
986d72ce1e
fix(pricing): restore the DeepSeek v4 and gpt-5.6-codex repricing invariants (#1134) (#1577)
Some checks failed
CI / semgrep (push) Has been cancelled
Tests / desktop (push) Has been cancelled
Tests / test-platforms (windows-latest) (push) Has been cancelled
Tests / test (22) (push) Has been cancelled
Tests / test (22.13.0) (push) Has been cancelled
Tests / test (24) (push) Has been cancelled
Tests / test (26) (push) Has been cancelled
Tests / test-platforms (macos-latest) (push) Has been cancelled
* fix(pricing): restore the DeepSeek v4 and gpt-5.6-codex repricing invariants (#1134)

The 0.9.21 snapshot caught the 2026-08-24 repricings mid-transition and
relaxed two tests/models.test.ts invariants. Upstream has since synced:

- DeepSeek v4: LiteLLM now carries the official peak rates for both the
  bare and the deepseek/-namespaced rows (pro 1.32/3.96 per million,
  flash 0.30/1.20), so the stale hand-pinned MANUAL_ENTRIES (from before
  PR #27056 merged) are removed and prefixed-equals-bare is asserted
  again.
- gpt-5.6-codex / -max: still absent from LiteLLM, so their
  MANUAL_ENTRIES remain but now mirror the repriced gpt-5.6 base row
  verbatim (4/20 per million, tier block included). codex-equals-base
  is asserted again, and the long-context tier test now expects the
  codex SKUs to carry the base tier.

The refresh also exposed a pass-2 ordering defect in
scripts/bundle-litellm.mjs: a reseller row like
openrouter/deepseek/deepseek-v4-pro could claim the empty
deepseek/deepseek-v4-pro slot before the official row was reached (the
winner was decided purely by upstream JSON key order), pricing the
namespaced id at the resale rate. A prefixed row may now claim only a
stripped slot that is not itself an upstream entry name; multi-segment
ids that exist only as reseller rows keep resolving as before.

Bundled snapshot regenerated: 24 rows moved by upstream drift
(claude-sonnet-5-5 family added, deepseek-v4.1-flash repriced,
zai/glm-4.6 cache-write filled), plus the deepseek/codex corrections.
Token-priced calls re-price on read; no re-parse is needed.

* fix(pricing): repin cline-cli parse version and cover #1134 shadow bug

- session-cache.ts: bump the cline-cli parse version so cached estimated
  costs (e.g. offline DeepSeek v4.1 flash) re-price on read, since
  cline-cli is in REPORTED_COST_PROVIDERS.
- CHANGELOG.md: note the bundler fix also reprices zai/glm-4.6 from the
  vercel_ai_gateway resale row to the official row, and moves the two
  mistral embed models to the fallback table.
- bundle-litellm.test.ts: add a fixture covering a reseller-prefixed row
  that sorts before the official row it would otherwise shadow.

---------

Co-authored-by: Resham Joshi <65915470+iamtoruk@users.noreply.github.com>
2026-09-29 15:05:37 +02:00
Uttam Deb
12d764c134
Account for Codex response usage records (#1571)
* Add Codex usage record accounting regressions

* Read Codex response usage records

* Reparse cached Codex usage after source handover

* Document Codex usage source handover

* Account for Codex in daily cache migration tests

* Cover Codex usage handover after fork replay
2026-09-29 14:33:02 +02:00
ozymandiashh
b8a9f3cc52
fix(openclaw): read the per-agent sqlite transcript store the 2026-09-01 migration writes (#1526)
Some checks failed
CI / semgrep (push) Waiting to run
Tests / desktop (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
Windows Menubar CI / check (ubuntu-latest) (push) Has been cancelled
Windows Menubar CI / check (windows-latest) (push) Has been cancelled
* fix(openclaw): read the per-agent sqlite transcript store the 2026-09-01 migration writes

OpenClaw 2026.8.1 moved sessions from agents/<agent>/sessions/*.jsonl to
agents/<agent>/agent/openclaw-agent.sqlite, so discovery resolved to zero
sources and doctor reported the provider empty (#1259).

transcript_events keeps each JSONL envelope verbatim in event_json, so the
JSONL event reducer is extracted and shared: both eras parse, dedup and
cost identically, and migrated sessions keep their original ids. Sessions
are listed per store and parsed in keyset batches of 2000 rows so a
gigabyte store never loads whole. agent-schema 23 lets a row carry its
event as an event_zstd BLOB instead; those decode on Node 22.15+ and skip
with one notice below that.

Fixes #1259

* test(openclaw): batch fixture inserts in a transaction; hash id-less events before the created_at fallback

---------

Co-authored-by: ozymandiashh <ozymandiashh@users.noreply.github.com>
Co-authored-by: Resham Joshi <65915470+iamtoruk@users.noreply.github.com>
2026-09-28 19:17:20 +02:00
ozymandiashh
700e4d1a27
fix(pricing): carry long-context tier rates through bundling, applied where billing evidence exists (#1478)
* fix(pricing): carry long-context tier rates through bundling and price them where billing evidence exists

LiteLLM publishes *_above_<n>k_tokens rates for 418 models - OpenAI's
gpt-5.4/5.5/5.6 family above 272k, Anthropic above 200k, and 128k/256k/
512k tiers elsewhere - but the bundler flattened every entry to the
fixed five-slot tuple and calculateCost had no threshold dimension, so
a request past its threshold priced at the base rate forever (#1076).

The tuple gains an optional sixth slot {threshold, input, output,
cacheWrite, cacheRead}, the threshold parsed from the key suffix
because LiteLLM ships no numeric field (272k means 272,000; #1075
verified assuming 128k fabricates +64% spend). Old bundles parse
unchanged; CACHE_SCHEMA_VERSION moves to 5 (4 is taken on main by the
implicit cache-write billing) so a stale on-disk live-pricing cache
cannot reintroduce the old behavior; the live-fetch parser picks the
same tier up; service-tier _priority/_flex variants and the 1-hour
cache-write combination are not context thresholds and stay out.

A tier applies when the request's prompt tokens (input + cached input,
the existing grok-4.6 definition) reach the threshold, each published
rate replacing its base and omitted slots keeping the base.
Application is gated on billing evidence via TIERED_PRICING_PROVIDERS:
codex today, where the maintainer's corpus measurement shows the
surcharge passing through; a real Copilot session on gpt-5.6-terra
with ~6M-token prompts billed at the BASE rate, so Copilot keeps base
pricing until such evidence exists - applying it there would fabricate
spend, the exact class #1075 warned about. The audit report recomputes
through the same tier swap so recomputedTotalUSD keeps tracking
attributedCostUSD.

* fix(pricing): read tier rates only from the chosen threshold; e2e codex tier test

Repair pass from review: both tierOf implementations now collect rates
per threshold and read only from the largest one, so a hypothetical
two-tier entry can never mix the smaller tier's rates under the bigger
threshold; the bundler validates tier values exactly like the live
parser (finite, non-negative). A codex end-to-end test drives a real
rollout past gpt-5.5's 272k prompt threshold and asserts the tiered
arithmetic explicitly (a typo'd provider string in codex.ts would
leave the call at base rates and fail it), alongside the no-provider
base-rate control that keeps the real Copilot billing pin intact.
Comment fixes: the priceOverride wording, the grok pin's actual
resolution branch, and the threading note on TIERED_PRICING_PROVIDERS
for whoever adds the next provider.

* fix(pricing): recompute the audit tier per call and re-derive warm daily caches

Both review blockers:

- audit-report no longer feeds a bucket's SUMMED tokens into the
  per-call 272k threshold (a \,979 phantom gap on the reviewer's
  corpus, any tiered codex model clearing the threshold on the sum
  alone). The recompute accumulates per call, through the same tier
  swap calculateCost applies, with each call's own prompt total; a new
  fixture mixes one 300k call with 200 small ones whose sum blows past
  the threshold and pins that only the big call tiers. Web search
  stays on the base rates - it never participates in a tier.
- DAILY_CACHE_VERSION 33 -> 34 with MIN_SUPPORTED_VERSION raised to
  match, the cfdaa685 convention: a 33 file written under tierless
  pricing is below the floor, is not adopted as the finalized base,
  and its days re-derive off the warm session cache (\ of codex
  spend on the reviewer's corpus lives only in the daily cache). The
  migration tests pin the new floor contract: no version-diff repairs
  merge into a below-floor file, and the v30 adoption test tracks
  CURRENT.

Nits from review: the kimi precision tightening is reverted to (8, 5),
and the tieredCostsFor comment is rewrapped.

Measured on this machine's corpus, tier-only (branch vs the refresh
branch, same data): +\.43 lifetime codex - this corpus runs far
more sessions past 272k than the reviewer's 8-of-51,801 (+\.012964);
both numbers are real, the corpora differ.

* fix(pricing): preserve base alias selection when bundling context tiers

* fix(pricing): address the 28 Sep review - floor stays at 28, tier bills the implicit cache-write rate

Restore main's two carry-forward tests: with MIN_SUPPORTED_VERSION kept
at 28 (per the review's correction, warm caches re-derive identically
under 41/28, so raising the floor is unnecessary) a v33 file sits in
the adopt-with-repairs window again and main's expectations hold; the
tier's warm-cache coverage stays in daily-cache-version-rederivation.

The tier-omits-slot test bills an implicit cache-write at the input
rate of the costs object in effect (#1544), so the tiered expectation
is 1_000 * cacheWriteCostPerToken('gpt-5.5', tieredCosts).

Note on the Codex estimate path: an estimated prompt can cross a
long-context threshold and tier itself; measured corpora hold no
estimated calls that cross.

* fix(pricing): pin claude-opus-4 primary and keep carried fallback rows hygienic in the refreshed snapshot

The requested regeneration surfaced two upstream moves beside the tier
work. LiteLLM dropped `claude-opus-4`; a refresh carries dropped ids
into the fallback tier, but the Cursor-style alias `claude-4-opus`
resolves against primary rows, so the bare id fell to the snowflake
gateway row and under-priced by 3x. Pinned at Anthropic's list price
in MANUAL_ENTRIES so it stays primary. LiteLLM also repriced
grok-4.6's base input 2e-6 -> 1.25e-6 (tier rates unchanged); the
below-threshold literal follows. Both changes reproduce identically
with main's unchanged bundler on the same live responses.

Today's drops also exposed a gap in the #1483 carry-forward: primary
files legitimately hold @pin, date-suffixed and free-on-both rows, and
carrying those verbatim imports exactly what
tests/pricing-fallback-data.test.ts keeps out of the fallback file
(main's own next refresh fails those tests today). The carry now skips
@pin/date-suffixed keys (no query can arrive in those forms) and
free-on-both rows (an unpriced model falls to expected-free handling);
vendor-prefixed keys stay carriable since queries match them verbatim.

---------

Co-authored-by: Resham Joshi <65915470+iamtoruk@users.noreply.github.com>
2026-09-28 19:10:39 +02:00
ozymandiashh
59ed66b977
feat(dock): one Claude ring per config directory, with its own sessions and today (#1570)
* feat(dock): one Claude ring per config directory, with its own sessions and today (#1523)

Rate limits are per account, so a machine with a work and a personal
~/.claude cannot be served by one Claude ring. When the CLI knows two or
more Claude config directories:

- `codeburn quota --format json` adds a top-level `claudeProfiles` array,
  one entry per directory (`providers[]` unchanged). Each entry carries
  the directory's own windows, read from its own `<dir>/.credentials.json`
  (the macOS Keychain fallback stays reserved for the default ~/.claude),
  plus that directory's own today totals from a single Claude-only,
  cache-backed parse of today's range, filtered per source id exactly like
  the menubar's per-config payloads.
- Live sessions carry `claudeConfigSourceId`, so a per-profile ring claims
  only its own sessions. Claude Desktop sessions keep their own bucket id
  and belong to no profile.
- The Windows Capacity Dock gains a `claudeProfiles` preference (combined,
  default; separate draws one captioned ring per directory). Profile rings
  keep addressing the `claude` provider id for the provider set, glyphs,
  colors and the connect button; the settings row appears only when the
  CLI reports more than one profile.
- Captioned rows are taller by two new metrics (caption line + gap),
  mirrored in TS and Rust: the page tells Rust the rail is captioned in
  the layout request, and the frame carries the effective row extent the
  hit-test uses. Non-captioned rails are pixel-identical to before.
- The desktop app's shared dock-prefs schema parses and sanitizes the new
  key, so its pane cannot strip it from windows-dock.json.

Closes #1523

* review: opt-in profile reads, today timeout, missing-dir filter (#1570)

- `quota --claude-profiles` gates the per-directory reads: without it the
  payload lists profiles ({id,label,path}) only, so a combined rail and
  WSL users pay nothing; the Windows dock passes the flag only while its
  claudeProfiles preference is separate, and an unknown option from an
  older CLI reads as CliOutdated.
- The default ~/.claude profile reuses the claude provider row's result —
  no second request, no second macOS Keychain read.
- claudeTodayBySource races the same timeoutMs and answers an empty map
  on loss, so a silent child cannot cost the dock every provider's quota.
- Missing config directories are filtered before the >1 check.
- `captioned` applies only while a Claude ring is in the selected set;
  profile rows tolerate a list-mode answer; comments trimmed; merge with
  #1560 keeps both keepExpanded and claudeProfiles.

* test(quota): set USERPROFILE for the default-dir check; drop issue refs

---------

Co-authored-by: Resham Joshi <65915470+iamtoruk@users.noreply.github.com>
2026-09-28 19:06:53 +02:00
ozymandiashh
c166e69e46
Track peak vs off-peak usage for first-party DeepSeek and Z.ai routes (#1561)
Consumption-share split in `codeburn models`, reworked per review:

- First-party routes only: the split applies to `dsh` (DeepSeek API) and
  `zcode` (Z.ai plan) calls. The same model behind a gateway never had
  the vendor discount, and reported-cost providers may already carry it;
  the gate set stays disjoint from REPORTED_COST_PROVIDERS.
- The numbers agree by construction: both legs are shares of the stored
  list-rate cost (peakUSD + offPeakUSD == costUSD, pinned in tests).
  The 0.5x off-peak discount stays on the vendors' bills; nothing is
  repriced here. peakCostMultiplier and OFF_PEAK_MULTIPLIER are gone.
- Calendars: unverified 2027 projections dropped; the Z.ai
  2026-09-25..10-07 all-day off-peak promotion is honored as a temporary
  range; deepSeekHolidayCoverageYears() plus a test fail when the
  current year falls out of the holiday list.
- Output shape: JSON carries the five peak keys only on rows with a
  split, so a report without DeepSeek/Z.ai first-party usage keeps its
  exact historical shape; the Z.ai quota note is removed.
- The `codeburn peak` live-status command is left out (scheduling tool,
  not usage tracking); it survives on a separate branch for its own PR.
2026-09-28 18:48:38 +02:00
ozymandiashh
0259392a20
fix(models): name dot-form Claude minors and future GPT ids consistently (#1531)
* fix(models): name dot-form Claude minors and future GPT ids consistently (#1530)

One model id resolved to different display names per provider, and new
models showed truncated names until a hand-maintained entry landed:

- deriveClaudeShortName now accepts the dot-form minor some doors write
  on disk (GitHub Copilot's session store: claude-opus-4.8), so the name
  keeps its minor instead of truncating to "Opus 4".
- Unknown dotted-version GPT ids derive their display name (gpt-5.7-terra
  -> "GPT-5.7 Terra") the way unreleased Claude versions already do, so a
  new release needs no SHORT_NAMES entry. Legacy bare-major /
  date-packaged ids (gpt-9, gpt-4-1106-preview) stay raw, and curated
  labels keep winning.
- Pi/OMP/Copilot local display tables now match keys on segment
  boundaries via modelKeyMatches, so a bare `gpt-5` key can no longer
  capture `gpt-5.5` / `gpt-5.6-luna`; unmatched ids fall through to the
  global resolver, making one id show one name on every provider.
- The JetBrains token scan rejects a trailing dot, so `gpt-5` /
  `claude-opus-4` cannot match inside `gpt-5.6-luna` / `claude-opus-4.8`.

Fixes #1530

* fix(copilot): list the current JetBrains model ids in the token scan (#1530)

Review of #1531: the tighter #1530 boundary is right, but with no token
entries the newer ids fell through to copilot-anthropic-auto and priced
as Sonnet 4.5. Add the current dotted ids, longest first per the list's
order, so "model":"gpt-5.5", gpt-5.6-luna and claude-opus-4.8 resolve to
their own priced, correctly named rows; unknown future versions (a dot
followed by a digit) still return no token.
2026-09-28 18:48:21 +02:00
Swizzy
b6a977dd7c
Capacity Dock: setting for the hover bubble's surface (#1573)
* menubar: dock preference for the hover bubble's surface

* menubar: let the dock's hover bubble keep its own surface

* menubar: setting for the dock's hover bubble surface

* docs: dock hover bubble surface setting
2026-09-28 18:47:51 +02:00
sm0keyyy
1795fbdfa3
Count OMP model_usage side calls (find, judge, cache warming) (#1575)
OMP logs decision and warming calls outside the transcript as model_usage entries. The parser read only assistant messages, so that spend never reached a report. Each side call now counts at its reported cost, with its purpose in the tools column. Bumps the omp parse version and the daily cache to v41.
2026-09-28 18:47:35 +02:00
Uttam Deb
37f3ff4ed1
Preserve Codex work after fork replay (#1569)
Some checks failed
CI / semgrep (push) Waiting to run
Tests / test (22.13.0) (push) Waiting to run
Tests / test (22) (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
Windows Menubar CI / check (ubuntu-latest) (push) Waiting to run
Windows Menubar CI / check (windows-latest) (push) Waiting to run
macOS Menubar CI / test (push) Has been cancelled
* Add Codex fork replay boundary regressions

* Fix Codex fork replay boundary

* Account for Codex in daily cache migration tests

* fix(codex): cap fork replay burst at 5s, drop codex rederive exemption, cache v17

---------

Co-authored-by: Resham Joshi <65915470+iamtoruk@users.noreply.github.com>
2026-09-27 17:18:05 +02:00
yi111
162bc5e937
fix(menubar): pick the CLI package manager from the resolved symlink (#1563)
* fix(menubar): pick the CLI package manager from the resolved symlink

Homebrew's node sets the npm global prefix to the Homebrew prefix, so a
global npm install puts the codeburn launcher at <prefix>/bin/codeburn
pointing at <prefix>/lib/node_modules/codeburn. The directory substring
test saw /homebrew/ there and chose brew upgrade, which exits non-zero
with "codeburn not installed". Resolve the launcher first and branch on
the target: /Cellar/codeburn/ is brew, /node_modules/codeburn/ is npm.
The manual hint used the same substring test, so route it through the
same decision.

refs #1557

* test(menubar): pin symlink resolution in brew path tests

---------

Co-authored-by: Yi-111-a <>
Co-authored-by: Resham Joshi <65915470+iamtoruk@users.noreply.github.com>
2026-09-27 17:17:51 +02:00
Pedro Escaleira
5eb9ac6566
feat(gnome): show combined usage from paired devices (#1566) 2026-09-27 16:14:53 +02:00
Swizzy
d5880796bc
menubar: dock preference to keep every ring out at rest (#1560) 2026-09-27 16:14:22 +02:00
Resham Joshi
2a7d9588d8
fix: mouse tracking off by default so text selection works, m toggles it (#1562)
Some checks failed
CI / semgrep (push) Has been cancelled
Tests / test-platforms (windows-latest) (push) Has been cancelled
Tests / desktop (push) Has been cancelled
Tests / test (22) (push) Has been cancelled
Tests / test (22.13.0) (push) Has been cancelled
Tests / test (24) (push) Has been cancelled
Tests / test (26) (push) Has been cancelled
Tests / test-platforms (macos-latest) (push) Has been cancelled
2026-09-25 20:17:07 +02:00
Resham Joshi
34db32361d
feat(cursor): import Cursor's usage CSV to replace local estimates (#1558)
Some checks are pending
CI / semgrep (push) Waiting to run
Tests / test-platforms (windows-latest) (push) Waiting to run
Tests / desktop (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
* feat(cursor): import Cursor's usage export to replace local estimates (#1545)

* Price Cursor-hosted grok-4.6-high like grok-4.6 in the Cursor import

* Skip no-op Cursor re-imports and price cursor-grok-4.6-high ids locally

* test(cursor-import): write agent fixtures under os.homedir() so Windows finds them
2026-09-25 05:27:57 +02:00
Resham Joshi
d076d4935b
fix(cursor-agent): read CLI sessions that exist only in ~/.cursor/chats store.db (#986) (#1556)
* fix(cursor-agent): read CLI sessions that exist only in ~/.cursor/chats store.db (#986)

A session with no exported transcript is read from its store.db; one with
a transcript is read from the transcript alone, so nothing counts twice.
Store turns follow the transcript accounting, take their time from the
prompt's <timestamp> tag and their model from the reasoning block, and
merge every conversation root so summarized history is kept. Daily cache
moves to v39 so settled days re-derive.

* cursor-agent: price store.db turns at the Cursor (auto) rate like transcripts
2026-09-25 05:16:29 +02:00
Resham Joshi
151509a1fb
fix(cache-lock): coalesce heartbeat ticks; make time-sensitive tests deterministic (#1559)
* fix(cache-lock): coalesce heartbeat ticks so the fence never waits behind a backlog

Each interval tick queued a full heartbeat in the owner serializer, so an
interval firing faster than a tick completes grew the queue without bound and
verifyStillOwner waited behind all of it. The 1ms-heartbeat fence test hit its
30s timeout on a loaded runner and retried up to 10 times, which is the silent
cache-lock suite hang in CI.

* test(menubar): hold off the helper's SIGTERM until the stand-in app records its status

The relaunch helper signals the app as soon as the CLI child is reaped, which
could land between the stand-in's fopen and fclose and leave an empty status
file. Also wait for the recorder's full line instead of a fixed sleep.

* test: pin day-boundary tests so they pass at any time of day

CLI children that query "today" now run in a fixed-offset zone where it is
about noon on the UTC date (tests/fixtures/noon-tz.ts), so fixtures a little in
the past are always today; the old clamp to UTC midnight put them in the future
for the first minutes of the day and zeroed the counts. The month-scoped budget
and project-filter fixtures get the same treatment (the latter also failed on
days 1-5 of every month), the cursor lookback case derives its start from now
instead of a date that ages out on 1 Oct, and the renderer tests that format a
stamp from a few hours back pin the clock to mid-day. The session drawer date
is formatted in the local zone, so its expectation is too.

* test: derive dated fixtures from the clock so rolling windows never age them out

The six-month --period all window and the sync ledger's six-month prune
dropped fixtures fixed at April-July 2026 from 1 Nov 2026 on. CLI fixtures now
sit 30 days back (utcDaysAgo), the ledger and push tests pin Date to July 2026,
the --to-only range uses yesterday, and the date-picker tests pin mid-month so
two days back is on the calendar they open (they failed on the 1st and 2nd of
every month). The noon-tz helper moves to tests/fixtures/clock.ts.

* test(desktop): give spawned stand-ins room to boot before the silence window

The watchdog and graceful-kill tests used 1-1.5s silence windows, and the
window before a child's first byte includes node's boot. On a loaded machine
the child was signalled before it installed its handler or wrote its byte.
The windows are now 3s and the last-byte test measures from the byte the child
stamps. The killAll and fallback-scheduler tests wait on their condition with
a 15s deadline instead of a 2-3s one.
2026-09-25 05:06:43 +02:00
Resham Joshi
f270e06d49
fix(copilot): attribute OTel conversations to their VS Code workspace (#1529) (#1555)
Some checks failed
CI / semgrep (push) Waiting to run
Tests / desktop (push) Waiting to run
Tests / test-platforms (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
Tests / test-platforms (macos-latest) (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
Copilot Chat OTel spans carry no github.copilot.git.repository, so every
agent-traces.db conversation fell back to copilot-chat. Match the
conversation id (or copilot_chat.chat_session_id / parent_chat_session_id)
to the workspaceStorage/<hash>/chatSessions file of the same id and name it
from workspace.json, including multi-root and remote folders. Totals are
unchanged; copilot re-parses once and the daily cache moves to v38 so
settled days re-derive the project split.
2026-09-25 01:36:38 +02:00
Resham Joshi
ab73bd33b4
fix(windows): read the Claude quota credential from running WSL distros (#1061) (#1554) 2026-09-25 01:35:41 +02:00
Resham Joshi
82469eab68
fix(cursor): connect Enterprise team seats on the team on-demand meter (#1553)
usage-summary for an Enterprise seat has no individualUsage.plan, a null
individualUsage.overall.limit and teamUsage.onDemand instead of pooled, so
decodeCursorUsage returned null and the adapter reported an unrecognized
response. Fall back to the team on-demand meter, list it beside the
monthly window when both exist, and decode meter amounts as Double in the
menu bar so a fractional amount cannot fail the whole decode.

Settings no longer appends sign-in guidance to transient failures.

Reported in #1546.
2026-09-25 01:33:41 +02:00
Jayly
6b7f672af7
fix(copilot): include copilot legacy chat sessions (#1232)
* feat(copilot): legacy JSON chat session parser and auto-mode resolution

* fixed copilot naming

* revert: remove unrelated jetbrains and env-isolation changes

* revert priority change

* fix(copilot): route legacy JSON chat sessions cleanly and fix calculateCost web search param

* fix(copilot): legacy chat session parsing and pricing

* fix(copilot): strip github.copilot-chat/ namespace from legacy model ids

found github.copilot-chat prefix in my chat sessions

* fix(copilot): revert comments

* fix(copilot): model names

* fix(copilot): model display name edge cases

* feat(copilot): only keep legacy parser source

* fix(copilot): legacy sessions skip binary tool outputs and use recorded thinking tokens

A screenshot or other binary tool result was base64-decoded as UTF-8 and
char-counted as input, so one 200 KB PNG billed 50k input tokens. Only
text/* payloads count now.

A round's recorded thinking.tokens was compared with the char estimate of
the same text via Math.max, so the estimate won whenever it was larger.
Each round now uses its recorded count when present and the estimate only
otherwise, summed across rounds.

Docs list the flat .json files and the transcript gate covering them.

* fix(models): price Copilot's dotted spellings of Claude 3.5, 3.7 and Opus 4.1

Copilot writes claude-3.5-sonnet, claude-3.7-sonnet,
claude-3.7-sonnet-thought and claude-opus-4.1, which resolved to no
pricing row and billed $0. They alias to the dashed rows now.

---------

Co-authored-by: Resham Joshi <65915470+iamtoruk@users.noreply.github.com>
2026-09-25 01:32:46 +02:00
Resham Joshi
aa9b8c9a40
fix(opencode): Vertex sessions no longer show $0 (#1552)
* fix(opencode): price Vertex turns on a Vertex row and keep an unpriceable recorded cost through the cache (#1547)

OpenCode records the cost of each turn. For an id CodeBurn cannot price the
parser fell back to that cost, but the session cache stored no cost and
re-priced the cached tokens on every read, so the call showed $0. The
recorded cost now rides on the cached call as fallbackCostUSD and applies
only while the tokens price at $0, so a later catalog row or price
override still wins.

The session-level rollup used provider/model while per-message turns use
the bare id since #1543; it now uses the bare id too. google-vertex and
google-vertex-anthropic map to a metered Vertex route.

OpenCode and Kilo Code re-parse once; daily cache v37 re-derives settled days.

* fix(opencode): keep a declared-free id at $0 instead of its recorded cost

A model the user marked flat-rate, priced at a zero rate, or that looks
local prices at $0 on purpose. The recorded-cost fallback now skips those
ids at parse time and on cache read, through one guard in models.ts.
2026-09-25 00:01:02 +02:00
Resham Joshi
fe560f7f4d
chore: remove Roo Code support (#1551)
Roo Code was discontinued in May 2026 (its repository is archived).
Cached Roo sessions and daily history slices are dropped on load.
2026-09-24 21:34:39 +02:00
Ilia Alshanetsky
4e22a8e09f
fix: count every Cursor Agent assistant message instead of one turn per user message (#1513)
* fix: count every Cursor Agent assistant message instead of one turn per user message

Agentic loops emit dozens of assistant messages per user message and
the parser kept only the first (on one real corpus: 247 of 4,946
messages, ~4% of assistant text). Each message now carries the last
user message forward, tool_use inputs join the output text, and input
tokens use the full user text while the display stays truncated at
500 chars. Parse version bumped so cached sessions re-parse.

* cursor-agent: a transcript that ended before any assistant message is not an unrecognized format

* cursor-agent: bill the user text once per user message, not once per assistant message

* cursor-agent: re-derive finalized days and cached sessions under the new accounting

---------

Co-authored-by: Resham Joshi <65915470+iamtoruk@users.noreply.github.com>
2026-09-24 21:02:00 +02:00
Resham Joshi
e5dff62fa1
perf: store the session cache in day pieces (#1550)
* Store the session cache in day pieces with a per-provider index

Layout v10: a provider's files live in pieces by the UTC day of their
newest call, each with a key file, and an index row per file (piece,
fingerprint, call span, v9 month) read on every load. A ranged load reads
the index, the key files and only the members it reports on; a save
rewrites only the pieces it touched. Rows keep v9's full-load order and
month scope, so orphans, the first-paint snapshot and dedup see what they
saw on v9. The v9 month shards re-lay out once, streaming, and are removed
after v10 publishes.

* Skip cached transcripts outside a narrow query's months when unchanged

v9 could not see them, so every narrow query re-parsed each older Claude
transcript it discovered and republished the cache. The index knows their
fingerprint; an unchanged one needs nothing, a changed one still re-parses
as if uncached.

* Read piece members in batches through one buffer, and full loads concurrently

* Write piece key files without a sync; rebuild lost keys from the piece

* Changelog: day pieces

* Seed dedup with the keys of unchanged transcripts outside the query's months before a whole-file parse

* Upgrade-path check: verify the v10 envelope, indexes, pieces and key files
2026-09-24 20:45:35 +02:00
Resham Joshi
3f14d95118
fix(menubar): older menubar apps load again, and in-app Update restarts the app (#1548)
* fix(menubar): always emit avgCostPerSession for older menubar apps

Menubar 0.9.14-0.9.24 decode topProjects[].avgCostPerSession as required,
so omitting it for partial session counts broke Today with any 0.9.25 CLI.
Emit the 0.9.24 value again and keep sessionCountBasis so 0.9.25+ hides
a partial average. Add a test that checks the payload against the
required keys of every released menubar app.

* fix(menubar): restart the app after an in-app update

The app runs `codeburn menubar --force` as its child, and pgrep/pkill
skip their own ancestors, so the running app was never stopped and
`open` re-activated the old copy. Find the app with pgrep -a; when it is
an ancestor, swap the bundle while it runs, exit, and let a detached
helper stop it and open the new bundle. The terminal path stops the app
first as before.

Reported in #1541, thanks @AleksandrLiadov.
2026-09-24 20:07:25 +02:00
Resham Joshi
22ebfd463e
perf: load only the session-cache members a date range can use (#1542)
* Write session shards one member per line

A shard is still one JSON object, so older builds read it unchanged, but it
is written through a stream and never exists as one string. Past V8's string
limit the save used to throw and the cache silently never persisted; reads of
such a shard now go member by member.

* Hold cached files a ranged query cannot report on as stubs

A ranged load streams its in-scope shards and keeps in full only the files
with a call in the range, spawn anchors, failure markers, turn-less files and
WSL paths. Every other file becomes a stub: its fingerprint, bucket, PR flag,
dedup keys per turn and where its member line lives. A stub stands in for its
entry everywhere but the summaries it cannot contribute to: reconcile, the
seenMsgIds and parser dedup pre-seeds, the query-time key replay in serve
order, orphan surfacing, eviction and the emptiness checks. A stub whose file
changed loads its member first, so the append or re-parse runs as before, and
a wider request in the same process loads the stubs it now needs.

A bucket holding stubs is rewritten as a full load would write it, copying
the stubs' lines from the shard they came from; unchanged, the published
shard is kept. A single-line shard from an older build is rewritten on the
next save. Providers whose parse reads cached entries no report shows
(hermes, quickdesk, antigravity, devin, gemini) still load in full.

* Discover codex projects from a small index

Discovery only needs each rollout's project, but it loaded the whole codex
results file (hundreds of MB on a large corpus) on every run to get it.
flushCodexCache now also writes codex-projects.v15.json, keyed by the same
fingerprint, and discovery reads that. A missing index is built once from the
results file.

* Load the session cache once for status today and month

status asks for today, then the month. A command can now declare the union of
its ranges, so the first load already holds the month in full and the second
request finds it there; each request keeps its own month scope and summaries.

* Release the pre-lock cache view before reloading

Once the refresh lock is acquired or another process completed the refresh,
the snapshot loaded before the wait is never used again, but it stayed
referenced while the reload read a second view.

* Test the first-paint snapshot serves stubs in load order

* Parse a shard whole when the range covers all its months

A range that spans a shard's months needs nearly every member, and streaming
it one member at a time only added allocation churn (about 200MB more RSS on
report -p all over a 1GB cache). The streaming reader also reuses one read
buffer instead of allocating a fresh one per chunk.

* Parse a shard whole once the range reaches its oldest month

The previous rule also required the range to reach past the shard's newest
month, which a range ending now never does, so report -p all still streamed
every shard.

* Carry a shard line that spans reads as decoded text

Members of a megabyte and more span the 1MB reads, and joining their pieces
as Buffers allocated off-heap memory that only a GC returns: report -p all
over a 1GB cache peaked about 170MB above main in RSS. Decoding the pieces
with a StringDecoder keeps them on the heap and brings every streamed range
below main, so the whole-file parse for wide ranges goes again.

* Changelog: bounded session-cache load
2026-09-24 19:52:42 +02:00
Resham Joshi
e84889762c
fix(windows): Store installs get no GitHub update offer, and codeburn menubar opens the Store copy by its app id (#1520) (#1549) 2026-09-24 19:51:04 +02:00
Resham Joshi
6dc81f5ce6
fix: four cost accuracy bugs in export and pricing (#1544)
Some checks are pending
CI / semgrep (push) Waiting to run
Tests / test-platforms (windows-latest) (push) Waiting to run
Tests / desktop (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
* fix: four cost accuracy bugs in export and pricing

- export daily rows bucket each call on its own day (same rule as the day
  aggregator) and no longer skip a turn without a timestamp
- cache-write tokens on a non-Anthropic model with no published write rate
  bill at the input rate instead of a fabricated 1.25x (calculateCost and
  audit); daily cache v35 and pricing schema 4 so stored figures re-derive
- OpenCode/Kilo messages with output but no usage, and Copilot transcript
  calls with no token count, are marked estimated
- export records keep unrounded cost and gain estimated/unpriced columns

* fix: plain-decimal CSV costs, re-parse cached copilot transcripts for the estimated flag

* ci(upgrade-path): compare copilot records at cent precision across the export rounding change
2026-09-24 15:55:23 +02:00
Resham Joshi
09f5856bcf
fix(opencode): keep pre-upgrade history on OpenCode 2 databases (#1543)
* fix(opencode): keep pre-upgrade history on OpenCode 2 databases and price v2 turns like 1.x

OpenCode 2 copies 1.x sessions into session_v2/session_message on first
start, but the copy drops compaction summary and task-tool turns, skips
messages it cannot decode, and can stop partway. A session present in both
generations now reads its frozen legacy turns first and adds only the v2
turns legacy does not hold (migrated rows keep their ids, so dedup skips
the copies).

v2 turns also used a provider/model id that failed pricing for ids such as
opencode/claude-haiku-4-5; they now use the bare id 1.x stored.

Reported by a user.

* Changelog: OpenCode 2 unpriced ids showed as $0
2026-09-24 15:26:55 +02:00
Resham Joshi
5dd0061f8d
chore(pricing): add Opus 5.5 to the bundled snapshot (#1537)
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
2026-09-24 02:54:54 +02:00