Commit graph

301 commits

Author SHA1 Message Date
iamtoruk
2ed1d5275c chore: add firstlook workflow for PR author reputation check
Runs on every PR open/reopen/synchronize against getagentseal/firstlook
and fails the check when the author's score is 'unknown' (new or
untracked accounts). Skips bot accounts so dependabot and renovate pass
through.

This screens the same drive-by pattern that landed in PR #118 (octo-patch,
fresh automation account) without requiring a manual tier check on every
submission.
2026-04-21 06:17:56 -07:00
Resham Joshi
8ee84b0041
Merge pull request #119 from getagentseal/fix/revert-aicrowd-cache-rewrite
Revert source cache, fix stale Today totals
2026-04-21 05:24:06 -07:00
iamtoruk
2467578a52 fix(menubar): run prefetchAll in a detached task so the refresh loop starts immediately
prefetchAll was awaited inside the refresh loop after the first cycle.
On large corpora the All Time parse takes 60+ seconds and kept the Today
refresh blocked for that whole window, so the status label got stuck for
minutes at a time while the CLI was returning fresh numbers.

Detach prefetchAll into its own @MainActor task. The popover still gets
the benefit of pre-warmed period caches, the refresh loop ticks every 15
seconds regardless.
2026-04-21 05:22:34 -07:00
iamtoruk
f2a2b53ae7 Merge remote-tracking branch 'origin/main' into fix/revert-aicrowd-cache-rewrite 2026-04-21 05:08:31 -07:00
iamtoruk
5a4e14f0f6 docs: remove stray Unreleased heading, note removed --no-cache flag
Also adds a regression test for the midnight-straddle bucketing invariant
that was flagged by the pre-push review: if someone reverts the assistant-
timestamp bucketing back to user-timestamp, this test will catch it.
2026-04-21 04:54:50 -07:00
iamtoruk
07d2fb07aa chore: bump version to 0.8.5, add changelog entry explaining revert
Reverts the persistent source cache added in 0.8.2 back to v0.8.1's
full-reparse path for Claude sessions; keeps the plan pill, pricing fix,
cursor-agent provider, and the Mac menubar prefetch+timezone work added
between 0.8.2 and 0.8.4.
2026-04-21 04:44:23 -07:00
iamtoruk
b491a1f590 fix: bucket turns by assistant timestamp, filter at turn level
A turn that straddles midnight (user typed at 23:58, assistant responded
at 00:30) was bucketed and filtered inconsistently across call sites.
parseSessionFile filtered entries by timestamp, producing orphan assistant
calls that groupIntoTurns pushed as turns with empty timestamp. Some
downstream code counted those (buildPeriodData summing project totals)
and other code dropped them (renderStatusBar's empty-timestamp skip).

The menubar showed today = $32 while the terminal status showed today = $27
for the same dataset; each was internally consistent but used a different
turn-bucket rule.

Fix both: parseSessionFile now builds all turns first, then filters each
turn by its first assistant call timestamp (the moment cost was incurred).
renderStatusBar buckets the same way. day-aggregator.ts already bucketed
on assistant time, so it is now consistent too.

Net effect: a turn is counted in the day the API call actually ran in.
2026-04-21 04:40:44 -07:00
iamtoruk
68e9c63088 fix(cursor-agent): drop unused SessionSource fields reintroduced by revert
cursor-agent was authored on top of the Sharada cache rewrite and referenced
fingerprintPath, cacheStrategy, progressLabel, and parserVersion. With the
persistent source cache reverted, these fields no longer exist on SessionSource.
Strip the references; cursor-agent continues to work on the v0.8.1 discover +
parse path like every other provider.
2026-04-21 04:23:20 -07:00
iamtoruk
41839edd96 fix(menubar): prefetch periods and align dashboard dates with local timezone
Loading overlay no longer flashes on every 15s poll. isLoading now only
toggles when the cache is cold, and all periods prefetch once on launch
so tab switching is instant.

Heatmap tooltip, trend bars, forecast, and all-time stats were computing
on UTC dates while the CLI reports on local dates, so the two disagreed
at day boundaries. Switched every date formatter and calendar in these
paths to .current so the menubar matches codeburn today output.
2026-04-21 04:22:10 -07:00
iamtoruk
0725fe2fbb fix(cursor-agent): preserve raw model name for unknown Cursor models
The fallback path in modelDisplayName returned "Auto (Sonnet est.) (est.)"
for any model not listed in modelDisplayNames, double-tagging the est.
suffix and hiding the real model ID. New Cursor model IDs now surface as
their raw name with a single (est.) suffix until the display map is
updated. Adds a regression test.
2026-04-21 04:21:06 -07:00
iamtoruk
9de0b1ad7b chore: remove CLAUDE.md from public repo
Internal development rules do not belong in a public repository.
File is kept locally and added to .gitignore.
2026-04-21 04:21:06 -07:00
iamtoruk
c336adf2f1 docs: add cached-vs-uncached verification rule for parser PRs 2026-04-21 04:21:05 -07:00
Matt Van Horn
620ca32219 feat(cursor-agent): add provider for cursor-agent CLI sessions
Discovers transcripts at ~/.cursor/projects/*/agent-transcripts/*.txt
and joins against ~/.cursor/ai-tracking/ai-code-tracking.db for model
attribution. Token counts are estimated from transcript character
length since the attribution DB does not carry them; the model label
surfaces the estimation with an (est.) suffix on every row.

Deduplication keys prefix cursor-agent: to stay disjoint from the
existing cursor: prefix so the two providers do not cross-dedupe
on shared conversationId namespaces.

Tests cover: empty ~/.cursor/projects/, single transcript, multiple
projects, missing ai-code-tracking.db, unrecognized transcript format
skip, non-UUID filename fallback, and sqlite metadata join.

Closes #55
2026-04-21 04:21:01 -07:00
iamtoruk
0803005083 fix(config): restore catch-all in readConfig to prevent CLI crash on malformed config 2026-04-21 04:20:55 -07:00
Trevin Chow
2c43ec1ad0 fix(plan): resolve type errors in plan summary and isActivePlan guard
Two pre-existing type errors surfaced during the rebase against main:

1. JsonPlanSummary.id was hardcoded to four plan ids, but PlanId now
   includes 'none' (PLAN_IDS was extended when 'codeburn plan clear'
   was added). toJsonPlanSummary only runs for active plans at runtime,
   but the static type still had to be widened. Use PlanId directly
   instead of the hand-rolled union.

2. isActivePlan used Boolean(plan) as the nullish guard, which doesn't
   narrow plan's type in TypeScript. Switch to an explicit
   'plan !== undefined' so the subsequent .id and .monthlyUsd accesses
   type-check.

npx tsc --noEmit is now clean; all 285 tests still pass.
2026-04-21 04:20:55 -07:00
Trevin Chow
cb4c3ee305 fix(plan): scope TUI plan row to billing period, use currency-aware formatting
Address review feedback on #74:

1. TUI plan row previously used the active tab's filtered projects as
   plan spend, so 'Today' showed today's cost as plan spent. Switch
   renderDashboard and reloadData to getPlanUsageOrNull(), which uses
   the plan's own billing period regardless of tab.

2. Plan row rendered via a local formatUsd that hardcoded USD. Replace
   every call with formatCost so 'codeburn currency EUR' flows through.
   Removes the adjacent '$3,425.52' vs '$32.07' style mismatch.

3. renderPlanBar capped filled width at 100%, so 105% and 1700% looked
   identical. Past 100%, render a full bar plus chevron tail sized by
   order of magnitude (log10): 1.05x -> 1 chevron, 17x -> 2, 170x -> 3.

4. 'running on API overage pricing' is wrong for Claude Pro/Max (rate
   limited, not charged overage). Drop that claim; keep the Nx-over
   multiplier and match the under/near projection line structure.

5. Spell out 'equiv' as 'API-equivalent' in the plan label.

Dead code cleanup: getPlanUsageOrNullForProjects is now unused; remove
it. getPlanUsageFromProjects stays (unit tests still use it).
2026-04-21 04:20:54 -07:00
Trevin Chow
3f7470d29b feat(plan): subscription plan tracking with usage progress bar
Adds `codeburn plan set <id>` to configure a subscription plan (Claude Pro,
Claude Max, Cursor Pro, or custom). When set, the Overview panel renders
an API-equivalent progress bar against subscription price with a
projected month-end cost.

Closes the loudest demand signal on the repo: issue #11 ("Subscription
vs API Use") from two independent voices, plus the routing-decision use
case raised in #12.

- src/config.ts: extends CodeburnConfig with Plan, adds readPlan/savePlan/clearPlan
- src/plans.ts: presets (claude-pro $20, claude-max $200, cursor-pro $20)
- src/plan-usage.ts: getPlanUsage, resetDay-aware period math (1-28),
  median-of-7-day-trailing projection
- src/cli.ts: `codeburn plan [show|set|reset]` subcommand, plan wired
  into JSON outputs for report/today/month/status (only when active)
- src/dashboard.tsx: Plan row in Overview, color-coded (green under 80%,
  orange near, red over), with days-until-reset
- README.md: Plans section with honest framing (API-equivalent vs
  subscription price, not token allowance)
- tests/plan-usage.test.ts, tests/plans.test.ts, tests/cli-plan.test.ts:
  period math, presets, CLI round-trip

Resets respect resetDay across month boundaries. Uses median daily spend
(not mean) so one huge day doesn't distort the month-end projection.

Fixes #11
2026-04-21 04:20:50 -07:00
iamtoruk
8e39a89fe0 fix: pricing accuracy, stream leak, CSV injection hardening
- Remove bidirectional fuzzy match in getModelCosts that could return
  wrong pricing when a short canonical name prefix-matched a longer key
- Use explicit undefined check in parseLiteLLMEntry so free models with
  zero cost are not silently dropped from the LiteLLM pricing database
- Destroy read stream in finally block of readSessionLines to prevent
  file descriptor leaks when the generator is abandoned early
- Extend CSV injection escaping to cover tab and carriage-return prefixes
- Add optional chaining fallback for empty periods in exportCsv/exportJson
- Add regression tests for all fixes (models, export, fs-utils)
2026-04-21 04:20:46 -07:00
iamtoruk
361b9a7f76 docs: add star history chart to README 2026-04-21 04:20:43 -07:00
iamtoruk
31367f2c01 fix(menubar): use numeric version comparison for update check
Compare versions with .orderedDescending instead of != to prevent
showing update button when installed version is newer than cached.
2026-04-21 04:20:42 -07:00
iamtoruk
9e7916d24d docs: credit CodexBar as inspiration 2026-04-21 04:20:42 -07:00
iamtoruk
fec5868379 chore: update readme badges and menubar screenshot
Remove bundlephobia and monthly downloads badges, update menubar
screenshot to 0.8.0.
2026-04-21 04:20:38 -07:00
iamtoruk
28c825ff15 Merge PR #117: cursor-agent provider
Some checks are pending
CI / semgrep (push) Waiting to run
Adds a cursor-agent provider that reads sessions from
~/.cursor/projects/*/agent-transcripts/*.txt and joins against the
ai-code-tracking.db for model attribution, closing issue #55. Token
counts are estimated from transcript character length since neither the
transcript nor the attribution DB carries real counts, and every row
carries an (est.) label to surface that.

Contributed by @mvanhorn.
2026-04-20 19:26:32 -07:00
iamtoruk
3c2aab2207 fix(menubar): prefetch periods and align dashboard dates with local timezone
Loading overlay no longer flashes on every 15s poll. isLoading now only
toggles when the cache is cold, and all periods prefetch once on launch
so tab switching is instant.

Heatmap tooltip, trend bars, forecast, and all-time stats were computing
on UTC dates while the CLI reports on local dates, so the two disagreed
at day boundaries. Switched every date formatter and calendar in these
paths to .current so the menubar matches codeburn today output.
2026-04-20 19:25:14 -07:00
iamtoruk
ed5512144a fix(cursor-agent): preserve raw model name for unknown Cursor models
The fallback path in modelDisplayName returned "Auto (Sonnet est.) (est.)"
for any model not listed in modelDisplayNames, double-tagging the est.
suffix and hiding the real model ID. New Cursor model IDs now surface as
their raw name with a single (est.) suffix until the display map is
updated. Adds a regression test.
2026-04-20 19:20:15 -07:00
iamtoruk
988060cd09 chore: bump version to 0.8.4, update changelog 2026-04-20 18:28:02 -07:00
iamtoruk
bf17d20476 fix: remove noCache override for menubar-json format
Source cache fixes (empty-session guards, date range reordering) make
the cache safe for menubar use. Forcing noCache on every 15s poll was
re-parsing 5800+ files each time, causing the menubar to hang.
2026-04-20 18:25:43 -07:00
iamtoruk
78438e52f2 chore: remove CLAUDE.md from public repo
Internal development rules do not belong in a public repository.
File is kept locally and added to .gitignore.
2026-04-20 18:24:18 -07:00
iamtoruk
594013c5ce docs: add cached-vs-uncached verification rule for parser PRs 2026-04-20 18:08:38 -07:00
iamtoruk
f2195c12a1 chore: bump version to 0.8.3, update changelog 2026-04-20 18:08:11 -07:00
iamtoruk
b7ad5c5505 fix: source cache empty-session poisoning, TUI refresh, menubar stale data
Source cache entries with zero sessions now treated as cache misses instead
of serving stale empty data. Date range skip moved after fingerprint check
so changed files are never incorrectly excluded. TUI refresh timer bypasses
in-memory CachedWindow cache. Menubar-json forces noCache. Swift menubar
adds explicit refreshStatusButton calls to avoid observation race.
2026-04-20 18:07:37 -07:00
Matt Van Horn
554036d2a7
feat(cursor-agent): add provider for cursor-agent CLI sessions
Discovers transcripts at ~/.cursor/projects/*/agent-transcripts/*.txt
and joins against ~/.cursor/ai-tracking/ai-code-tracking.db for model
attribution. Token counts are estimated from transcript character
length since the attribution DB does not carry them; the model label
surfaces the estimation with an (est.) suffix on every row.

Deduplication keys prefix cursor-agent: to stay disjoint from the
existing cursor: prefix so the two providers do not cross-dedupe
on shared conversationId namespaces.

Tests cover: empty ~/.cursor/projects/, single transcript, multiple
projects, missing ai-code-tracking.db, unrecognized transcript format
skip, non-UUID filename fallback, and sqlite metadata join.

Closes #55
2026-04-20 17:49:45 -07:00
iamtoruk
508edcd62b chore: bump version to 0.8.2, update changelog and readme 2026-04-20 15:56:09 -07:00
iamtoruk
e18a1ef2f7 fix: tighten types, remove dead exports, prevent FD leak 2026-04-20 15:52:18 -07:00
Sharada Mohanty
7594fa0254 feat: optimize parse caching across providers 2026-04-21 00:07:07 +02:00
Sharada Mohanty
563f9c4f1b refactor: share provider presentation metadata 2026-04-21 00:04:29 +02:00
Sharada Mohanty
eb3737f756 docs: document persistent cache behavior 2026-04-21 00:03:49 +02:00
Sharada Mohanty
140e50b702 test: stabilize local-date aggregation 2026-04-21 00:03:49 +02:00
Sharada Mohanty
ff442c71f2 perf: cache provider discovery metadata 2026-04-21 00:03:49 +02:00
Sharada Mohanty
2a9daec0ea feat: add cache rebuild flag and progress 2026-04-21 00:03:49 +02:00
Sharada Mohanty
1b8e0f8289 fix: harden Claude append cache refresh 2026-04-21 00:01:46 +02:00
Sharada Mohanty
ad5366472a feat: cache Claude sources by session file 2026-04-21 00:01:46 +02:00
Sharada Mohanty
862be251e5 refactor: move providers onto shared cache metadata 2026-04-21 00:01:46 +02:00
Sharada Mohanty
303a9256c5 feat: reuse cached parsed sources 2026-04-21 00:01:46 +02:00
Sharada Mohanty
a2593ceb1e fix: harden source cache validation 2026-04-21 00:01:46 +02:00
Sharada Mohanty
ac5dd8c3e9 fix: tighten source cache validation 2026-04-21 00:01:46 +02:00
Sharada Mohanty
0d4d103627 fix: tighten source cache validation 2026-04-21 00:01:46 +02:00
Sharada Mohanty
a0bad07c19 feat: add persistent source cache storage 2026-04-21 00:01:46 +02:00
iamtoruk
e25922030d fix(config): restore catch-all in readConfig to prevent CLI crash on malformed config 2026-04-20 15:00:03 -07:00
Trevin Chow
c0d24cc191 fix(plan): resolve type errors in plan summary and isActivePlan guard
Two pre-existing type errors surfaced during the rebase against main:

1. JsonPlanSummary.id was hardcoded to four plan ids, but PlanId now
   includes 'none' (PLAN_IDS was extended when 'codeburn plan clear'
   was added). toJsonPlanSummary only runs for active plans at runtime,
   but the static type still had to be widened. Use PlanId directly
   instead of the hand-rolled union.

2. isActivePlan used Boolean(plan) as the nullish guard, which doesn't
   narrow plan's type in TypeScript. Switch to an explicit
   'plan !== undefined' so the subsequent .id and .monthlyUsd accesses
   type-check.

npx tsc --noEmit is now clean; all 285 tests still pass.
2026-04-20 14:55:07 -07:00