- Add Pi entry to PROVIDER_COLORS (pink) and PROVIDER_DISPLAY_NAMES.
- Update README with Pi in supported providers, requirements,
command examples, and the data-format section.
dispatch_agent is Pi's delegation tool. Mapping it to Agent makes
the classifier route those turns into the Delegation category
instead of Conversation, matching the existing semantics for the
task tool.
- Move modelDisplayEntries sort to module scope so it runs once
instead of on every modelDisplayName call.
- Add bash-utils tests for the env var prefix and true/false
skip behaviors that came in with the Pi commit.
Verified Pi token semantics against real session data:
input + cacheRead + cacheWrite + output equals totalTokens
exactly, confirming Anthropic-style accounting (cached tokens
disjoint from input). No double-counting.
Maps Pi's lowercase tool names (bash, read, edit, write...) to
the capitalized form used by every other provider, so the
dashboard shows consistent tool names across providers and the
activity classifier works without extra lowercase entries.
Reverts the lowercase additions to classifier.ts since the
provider now normalizes tool names at the source.
- Adds support for Pi (pi.ai) as a new session provider.
- Pi sessions are stored as JSONL files under `~/.pi/agent/sessions/<project-dir>/` and use OpenAI-compatible model IDs (gpt-5, gpt-5.4, gpt-4o, etc.).
- `src/providers/pi.ts` (new): Pi provider - discovers JSONL session files, parses assistant turns, extracts token counts, tool calls, and bash commands, deduplicates via response ID with line-index fallback
- `src/providers/types.ts`: added bashCommands field to `ParsedProviderCall` so all providers carry extracted bash command lists
- `src/providers/index.ts`: registered Pi as a core provider alongside Claude and Codex
- `src/providers/codex.ts`, `cursor.ts`: added `bashCommands: []` to satisfy the new required field on `ParsedProviderCall`
- `src/parser.ts`: fixed bug where `providerCallToTurn` always emitted an empty bashCommands array instead of passing through the parsed commands
- `src/classifier.ts`: added lowercase tool name variants (bash, edit, read, write) to match Pi's tool naming convention in JSONL output
- `src/bash-utils.ts`: exclude `true`, `false`, and shell variable assignments from extracted commands; scan past leading `NAME=val` tokens so `FOO=bar ls` correctly records `ls` rather than being dropped
- `package.json`: added pi to keywords
- `tests/providers/pi.test.ts` (new): 16 unit tests covering session discovery, multi-turn parsing, tool/bash extraction, deduplication, zero-token filtering, and display name mapping
- `tests/provider-registry.test.ts`: updated core provider list to include pi
- [X] Unit tests pass (`npx vitest run`, 56 tests across 6 files);
- [X] Manually verified via `npx tsx src/cli.ts` report and showing Pi sessions alongside Claude and Codex in the dashboard.
Adds a cache hit percentage column to the By Model panel and
fixes the cache hit math in the Overview panel. Both were
treating cache_creation tokens as cache hits, when they are
actually cache misses being written to cache for future use.
The corrected formula counts both fresh input and cache writes
in the denominator, so a heavy Claude Code session now shows
~97% cache hit instead of the misleading 100%.
Also extracts column widths into named constants per CLAUDE.md
no-magic-numbers rule, and tightens the model name column to a
fixed 14 chars so columns hug the name like the Activity panel.
The pricing fetcher was filtering out every model name containing
'/' or '.', which discarded provider-prefixed entries like
'anthropic/claude-opus-4-6' and version-suffixed ones like
'gemini-2.0-flash-001'. That dropped 93% of LiteLLM's catalog
(2,467 of 2,659 models), leaving most non-Anthropic models
priced at $0.
Now we load every entry and additionally index each one under its
stripped name so 'claude-opus-4-6' resolves whether or not the
caller includes the provider prefix.
Add a '30 Days' section to the menubar format output, positioned between
'7 Days' and 'Month' to match the tab order in the interactive report.
The rolling 30-day date range logic already existed (used by report and
export commands) - this wires it into the status menubar renderer.
Both 30 Days (rolling window) and Month (calendar month) are shown,
giving useful context early in the month when the calendar month total
is nearly empty.
Codex Desktop on Windows uses "Codex Desktop" as the originator
string instead of "codex_cli" or "codex_vscode". The startsWith
check was case-sensitive, rejecting these sessions silently.
Fixes#1 (comment by @JiglioNero).
Reads session data from OpenCode's SQLite databases at
~/.local/share/opencode/. Reuses the existing better-sqlite3
adapter (same as Cursor), lazy-loaded so users without OpenCode
see no difference. Adds bashCommands to the provider interface
so shell command breakdowns work across all providers.
31 tests, schema validation, diagnostic stderr on failures.
Also fixes a pre-existing tsc error in currency.ts.
120 days was for testing. Max dashboard period is 30 days, so
Cursor SQL lookback is now 35 days (30 + margin for This Month).
Smaller scan window = faster cold starts, smaller cache file.
First run parses the 21GB DB (slow, ~40-80s). Writes parsed
results to ~/.cache/codeburn/cursor-results.json. Subsequent
runs check DB mtime+size -- if unchanged, load from cache
(instant). Cache auto-invalidates when Cursor modifies the DB.
- Fetch actual user messages (type 1 bubbles) for keyword classification
instead of using assistant response text
- Synthetic Edit tool when codeBlocks present so classifier detects coding
- Languages use lang: prefix to separate from tool classification
- Dashboard filters lang: entries for Languages panel, hides from Core Tools
- Extract user text from bubbles for activity classifier
- Extract codeBlocks languageId for programming language breakdown
- Show Languages panel instead of Core Tools/Shell/MCP for Cursor
- Adaptive dashboard layout based on active provider
- 120-day daily activity range for longer periods
The incremental cache saved a timestamp watermark but not the parsed
data, so subsequent runs found no new entries and returned empty.
Removed the cache layer entirely -- the 120-day SQL time filter
already limits the scan sufficiently.
Cursor stores createdAt as ISO strings ('2026-02-23T06:00:51.123Z'),
not numeric timestamps. Was comparing string against number, so all
rows were filtered out. Now uses ISO string comparison throughout.
Arrow keys now wait 600ms before loading data, so quickly
scrolling through periods (7d -> 30d -> 90d) skips intermediate
loads. Number keys (1-5) still load immediately.
Cursor module (sqlite.ts, better-sqlite3) now only loads when
cursor provider is actually requested. Claude/Codex startup
is unaffected -- cursor import never happens unless needed.
The dashboard was pre-loading data for ALL detected providers
on startup, causing unnecessary SQLite scans when Cursor was
detected. Now only loads data for the active provider.
Instead of scanning all 300K+ rows on every load, only query
entries from the last 90 days. Eliminates the full table scan
that caused slow provider switching on large databases.
Reads token usage from Cursor's local state.vscdb database.
Supports per-request input/output tokens, model tracking,
and incremental caching for large databases.
- better-sqlite3 as optionalDependency (lazy-loaded, no impact on Claude/Codex)
- Parameterized SQL queries, read-only mode, per-row error handling
- Schema detection with clear error on format changes
- Cache layer with timestamp watermark for incremental reads
- Provider colors and [p] key cycling in dashboard
- 39 tests passing, zero regressions
The two menubar action items were built as `bash -c "cd ~/codeburn &&
npx tsx src/cli.ts ..."`, which:
1. assumes a `~/codeburn` source checkout that npm-installed users
don't have, and
2. interacts badly with how SwiftBar serialises `param2=` on long
quoted strings — only the `cd` half ends up reaching `bash -c`,
so the `npx tsx` fallback runs from `$HOME` and fails with
`ERR_MODULE_NOT_FOUND: /Users/<u>/src/cli.ts`.
Replace with the resolved `${bin}` plus separate `paramN=` args,
which SwiftBar/xbar deliver as discrete argv entries — no shell
quoting, no checkout assumption.
While here, fix the currency submenu the same way: the items were
emitting `${bin} config currency XXX`, but the real CLI subcommand
defined in `src/cli.ts` is `codeburn currency [code]` (with
`--reset` for USD). The previous form silently failed on click.
That's #27.
Closes#32Closes#27
Verified by running `npm run build` (clean) + `npm test -- --run`
(28/28 pass), and inspecting the rendered output of `codeburn status
--format menubar` to confirm the action lines now look like:
Open Full Report | terminal=true shell=<bin> param1=report
Export CSV to Desktop | terminal=false shell=<bin> param1=export param2=-o param3=<HOME>/Desktop/codeburn-report.csv
--US Dollar (USD) * | terminal=false refresh=true shell=<bin> param1=currency param2=--reset
--British Pound (GBP) | terminal=false refresh=true shell=<bin> param1=currency param2=GBP
- Remove agent-*.jsonl exclusion filter that was dropping ~46% of API calls
- Scan subagents/ directories for subagent session files
- Normalize Codex token semantics: OpenAI includes cached tokens inside
input_tokens, subtract them to match Anthropic's separate reporting
- Fixes cost double-counting and 100% cache hit display for Codex users
- Use Ink's useWindowSize() hook for reactive terminal reflow (PR #18)
- Raise width cap from 104 to 160 columns for wide screens
- Move Activity panel from full-width to half-width row with Model panel
- Pair Tool + Bash panels, MCP goes full-width at bottom
- Addresses issue #23 (UI responsiveness)
- Remove CurrencyPicker component and all related state from dashboard
- Promote 'codeburn config currency' to top-level 'codeburn currency'
- Strip JSDoc comments that explain WHAT not WHY
- Remove forceRender hack and unused imports
Press c in the dashboard to open a searchable currency picker modal.
Type to filter, arrow keys to navigate, enter to select, escape to
cancel. Shows 24 common currencies with the active one marked, and
accepts any valid ISO 4217 code typed directly.
Session-only switch -- does not write to config, so users can quickly
compare costs in different currencies without changing their default.
Adds a Currency submenu to the SwiftBar/xbar dropdown with 16 common
currencies. Clicking one runs codeburn config currency and refreshes
the plugin. Active currency is marked with *.
The full 162 ISO 4217 currencies are available via the CLI for any
not listed in the menubar.
Display costs in any of 162 ISO 4217 currencies. Exchange rates are
fetched from frankfurter.app (ECB-backed, free, no API key) and cached
for 24h alongside the existing LiteLLM pricing cache.
Currency symbols and decimal rules come from Node's built-in Intl API
rather than hardcoded tables.
New command: codeburn config currency <code>
Reset: codeburn config currency --reset
Config stored at ~/.config/codeburn/config.json.
All internal calculations remain in USD -- conversion is display-only.
Add a '30days' period that shows the last 30 days of usage data, distinct
from 'month' which shows the current calendar month.
- New period available via `--period 30days` and keyboard shortcut `3`
- Dashboard cycles: Today > 7 Days > 30 Days > This Month
- Fix export command to use actual 30-day range instead of calendar month
for the '30 Days' export label