Commit graph

112 commits

Author SHA1 Message Date
AgentSeal
b9dffc16ec chore(optimize): remove dead versions plumbing + name remaining magic numbers
- ScanData.versions and ScanFileResult.versions were collected but never
  read in scanAndDetect. Per-call version lives on ApiCallMeta.version
  which is what detectCacheBloat actually uses. Dropped the unused
  aggregation path end-to-end.
- Extract DEFAULT_CACHE_BASELINE_TOKENS, CACHE_BASELINE_QUANTILE,
  CACHE_VERSION_MIN_SAMPLES, CACHE_VERSION_DIFF_THRESHOLD as named
  module-scope constants. Honors the "no magic numbers" project rule
  across the full optimize engine.
2026-04-16 07:09:20 -07:00
AgentSeal
707d2faff1 feat(optimize): UX polish
- Rename "ctx" column to "overhead" with wider padding for legibility
  in the By Project panel.
- Name magic numbers for the project column widths.
- Empty-state now includes a one-line description of what optimize
  does, so first-time users with no findings still understand the
  feature.
2026-04-16 06:59:07 -07:00
AgentSeal
a9ca2a1134 feat(optimize): fix tracking via recent vs baseline split
Solves the problem where users who fixed an issue continued to see
the finding for the remainder of the period. Findings now show
visible progress or disappear entirely.

Mechanism (no state file, no new I/O):
- ToolCall and ApiCallMeta gain a `recent` boolean, set when the
  entry's timestamp falls inside a rolling 48-hour window.
- Each session-based detector counts recent vs total occurrences.
- computeTrend classifies each finding:
    active    -- recent rate matches baseline
    improving -- recent rate under half of baseline (green arrow)
    resolved  -- zero recent waste AND confirmed recent activity
- Resolved findings are suppressed. Improving findings render with
  a green "improving down-arrow" badge next to the impact label.
- When no recent activity exists, findings default to active so a
  user who simply paused is not told everything is fixed.

Applies to the four session-based detectors: junk reads, duplicate
reads, low read:edit ratio, cache bloat. The filesystem detectors
(missing .claudeignore, bloated CLAUDE.md, unused MCP, ghost agents
/ skills / commands, bash limit) already self-heal on next run.

5 new tests cover computeTrend edge cases. 126 tests pass.
2026-04-16 06:53:08 -07:00
AgentSeal
7e4edf66b6 perf(optimize): mtime pre-filter, parallel reads, result cache
- runWithConcurrency helper runs file reads with configurable parallelism
  (default 16) instead of sequential await.
- isFileStaleForRange skips files whose mtime is older than the date range
  start, avoiding unnecessary reads for narrow periods.
- Result-level cache keyed on (dateRange, project fingerprint) with
  60s TTL. Warm dashboard 'o' press now hits cache instead of rescanning.
- Early-return when projects array is empty so empty-state path does not
  trigger filesystem walk.

Measured CLI cold scan on 12K files, 1833 sessions week:
  before: 12-17s
  after: 6-7s
Dashboard warm cache hit: <50ms.
2026-04-16 06:35:39 -07:00
AgentSeal
be45045fd8 refactor(optimize): correctness, constants, and real tests
Phase 1 hardening pass.

Bug fixes:
- Move cwd/version collection inside date-range filter. 7d and 30d
  now produce different findings for filesystem detectors.
- detectGhostSkills threshold aligned with peer detectors.
- detectUnusedMcp gets 24-hour grace period via config file mtime so
  newly added servers are not flagged as unused.
- detectCacheBloat replaces hardcoded 50K baseline with user-derived
  p25 of cache writes. Flags only when median exceeds 1.4x baseline.
- detectBashBloat scans user shell profiles instead of the auditor's
  process.env.
- @-import pattern requires ./ ../ or / to avoid matching email
  addresses or npm scopes.
- Command usage pattern requires leading whitespace/start-of-line
  before /cmd so path references like /tmp are not counted as usage.
- AVG_TOKENS_PER_READ lowered from 1500 to 600 and
  CLAUDEMD_TOKENS_PER_LINE lowered from 25 to 13 for realistic
  prose/config sizing.

Code quality:
- Every magic number extracted to named module-scope constants.
- Dead code removed (IMPACT_ORDER, unused stat import).
- Shared loadMcpConfigs helper deduplicates config walking.
- Shared shortHomePath, isReadTool, inRange helpers.
- All detectors and computeHealth exported for real tests.
- Ghost detectors run in parallel via Promise.all.
- Cost rate defaults to 0 when unknown so UI can suppress instead of
  showing fabricated numbers.

Tests:
- Replaced 17 fake tests that re-implemented detector logic with
  26 tests importing and exercising the real exports.
- Cover threshold boundaries, impact scaling, edge cases.
- 121 tests pass.

UX header: "Setup" renamed to "Health", issue count shown inline.
CLAUDE.md: adds rule against "steal/copy/rip-off" wording in
public-facing text.
2026-04-16 06:30:15 -07:00
AgentSeal
b88f2cd730 feat: ghost detectors, health grade, @-import expansion
Expanded the optimize engine with new detectors and scoring:

1. Health score + letter grade (A-F) in optimize header. Weighted
   per-impact with caps. Gives users an instant "is my setup healthy"
   read that doubles as a shareable number.

2. Urgency score replaces impact-enum sort. Weighted 0.7 * impact
   + 0.3 * normalized tokens. Produces better-ranked findings.

3. Three new ghost detectors:
   - Ghost agents: files in ~/.claude/agents/ never invoked via
     Agent/Task tool
   - Ghost skills: SKILL.md directories never triggered
   - Ghost slash-commands: ~/.claude/commands/ files never referenced
     in user messages

4. @-import chain expansion for CLAUDE.md. Recursively follows
   @path/to/file imports (max depth 5) so bloat detection counts
   transitive load, not just the base file. Fixes undercounting for
   users with modular CLAUDE.md setups.

9 new tests covering health scoring and import expansion.
2026-04-16 05:09:01 -07:00
AgentSeal
710316053e feat: add optimize command, in-TUI optimize view, and per-project context budget
Optimize engine detects 8 waste patterns from Claude Code session data:
- Junk directory reads (node_modules, .git, dist, etc.)
- Duplicate file reads per session
- Unused MCP servers (configured but never called)
- Missing .claudeignore in projects with junk dirs
- Bloated CLAUDE.md files (>200 lines)
- Uncapped BASH_MAX_OUTPUT_LENGTH
- Low Read:Edit ratio (edit-without-reading, per #42796)
- High cache_creation overhead (per #46917)

Each finding includes impact rating, token/cost savings estimate, and
exact fix (paste, command, or file content).

Dashboard integration:
- o key switches to in-TUI optimize view, b key goes back
- Background scan on load, o button only when findings exist
- Per-project Context Budget column in By Project panel showing
  estimated per-call overhead (system + MCP tools + skills + CLAUDE.md)

CLI: codeburn optimize [-p period] [--provider]
2026-04-16 04:04:37 -07:00
AgentSeal
9794b5450a 0.5.7 2026-04-16 02:21:48 -07:00
AgentSeal
22b096a841 docs: add reading-the-dashboard guide to README
Lists common signals in the dashboard (cache hit, retry rate,
model mix, tool patterns) and what each typically means.
Points readers toward interpreting their own data without
overpromising automatic diagnosis.
2026-04-16 02:15:19 -07:00
AgentSeal
55d82a4526 Merge branch 'feat/pi-provider' 2026-04-16 02:14:53 -07:00
AgentSeal
5e095bf86e chore: polish Pi provider integration
- 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.
2026-04-16 02:11:48 -07:00
AgentSeal
1a101b586c chore: map Pi dispatch_agent to Agent for activity classification
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.
2026-04-16 02:08:07 -07:00
AgentSeal
97c0869763 chore: hoist Pi model sort + cover bash-utils edge cases
- 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.
2026-04-16 02:02:32 -07:00
AgentSeal
d92d5b3f26 chore: normalize Pi tool names via toolNameMap
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.
2026-04-16 01:57:39 -07:00
Damian Jackson
7ac512a7e4 feat: add Pi provider for tracking Pi agent sessions
- 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.
2026-04-16 01:54:42 -07:00
AgentSeal
e2b8632d2c 0.5.6 2026-04-16 01:51:04 -07:00
AgentSeal
45572e43f2 feat: cache hit % per model + correct calculation
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.
2026-04-16 01:50:19 -07:00
AgentSeal
4bbad76d06 0.5.5 2026-04-16 01:25:51 -07:00
AgentSeal
9a45470674 0.5.4 2026-04-16 01:25:32 -07:00
AgentSeal
e12b8e31d7 fix: load all 2,659 LiteLLM models, not just 192
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.
2026-04-16 01:25:15 -07:00
AgentSeal
897005dac8 0.5.3 2026-04-16 01:04:01 -07:00
AgentSeal
fc99087e3a
Merge pull request #28 from chmsant/feat/menubar-30day-window
feat: add rolling 30-day window to menubar status
2026-04-16 09:53:57 +02:00
Christopher Sant
5cdcd2c2ee feat: add rolling 30-day window to menubar status
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.
2026-04-15 21:48:20 -07:00
AgentSeal
475ab0da61 fix: case-insensitive Codex originator check
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).
2026-04-15 16:06:28 -07:00
AgentSeal
7c7ab32865 0.5.2 2026-04-15 14:29:59 -07:00
AgentSeal
13acaa6d45 0.5.1 2026-04-15 14:29:41 -07:00
AgentSeal
e7e8273bb4 docs: add OpenCode to README 2026-04-15 14:28:49 -07:00
AgentSeal
2d114d9393 feat: add OpenCode provider
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.
2026-04-15 14:24:37 -07:00
AgentSeal
3612c5a994 v0.5.0: Cursor IDE support, SQLite adapter, result caching
Major release adding Cursor as the third supported provider.
Lazy-loaded SQLite, file-based result cache, provider-specific
dashboard layouts, debounced period switching, broader classifier.
2026-04-15 05:48:22 -07:00
AgentSeal
0d1a51ed3c docs: add Cursor to README, repo description, and topics
- Cursor listed as supported provider with data location and caveats
- Auto mode pricing estimation explained
- Languages panel and cache behavior documented
- Project structure updated with new files
- Repo description and topics updated on GitHub
2026-04-15 05:46:25 -07:00
AgentSeal
2afab5f71a fix: final review cleanup
- Remove unused vi import from cursor test
- Move LANG_DISPLAY_NAMES to module scope (was re-created per render)
- Remove redundant 'script' regex (scrip?t already covers it)
- Unexport getDbFingerprint (internal to cache module)
- Move beforeEach inside describe block (only cursor tests need it)
2026-04-15 05:35:11 -07:00
AgentSeal
94762ca1f4 fix: address review findings before merge
- getProvider() now async, eliminates race condition with cursor loading
- cursor:edit pseudo-tool prevents inflating Claude's Edit count in --provider all
- Tightened SCRIPT_PATTERNS to avoid false positives (run requires file context)
- Removed duplicated LANG_NAMES from cursor.ts (dashboard handles display)
- Test no longer assumes cursor always loads (CI-safe)
- Removed unnecessary type assertion and setTimeout yield
2026-04-15 05:31:51 -07:00
AgentSeal
91edd6f14a chore: remove 120-day period, shrink Cursor lookback to 35 days
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.
2026-04-15 05:24:34 -07:00
AgentSeal
3fabc105d8 perf: file-based result cache for Cursor DB
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.
2026-04-15 05:11:30 -07:00
AgentSeal
6ba3691d24 fix: broader activity classification for informal messages
- File extension patterns (.py, .json, .ts, etc.) trigger Coding
- Script/API keywords (run, script, api, query, etc.) trigger Coding
- URL patterns trigger Exploration
- HTTP status codes (404, 500) trigger Debugging
- "make a/me/the" and "write a/me/the" trigger Feature Dev
- Catches informal Cursor messages that missed strict patterns
2026-04-15 05:03:15 -07:00
AgentSeal
4597cbbd16 fix: combine user + assistant text for better activity classification 2026-04-15 05:00:39 -07:00
AgentSeal
effe5b2438 fix: map language IDs to readable names in Languages panel 2026-04-15 04:56:25 -07:00
AgentSeal
caa0464832 fix: strip lang: prefix in Languages panel display 2026-04-15 04:55:01 -07:00
AgentSeal
5c6c266c85 fix: improve Cursor activity classification and language panel
- 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
2026-04-15 04:53:07 -07:00
AgentSeal
d6c6e827ea fix: clean language names, remove diagnostic scripts 2026-04-15 04:49:09 -07:00
AgentSeal
7b23fbb57b fix: pass provider to static dashboard for correct panel titles 2026-04-15 04:48:03 -07:00
AgentSeal
11cdcaa89d feat: activity classification + language breakdown for Cursor
- 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
2026-04-15 04:46:12 -07:00
AgentSeal
ea5fd90a68 fix: remove incremental cache, always read full lookback window
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.
2026-04-15 04:34:06 -07:00
AgentSeal
8120f1937f chore: add debug query script 2026-04-15 04:31:06 -07:00
AgentSeal
c7195c4a17 fix: handle ISO string timestamps from Cursor database
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.
2026-04-15 04:17:56 -07:00
AgentSeal
f2999da15f fix: rename diagnostic script to .cjs 2026-04-15 04:15:12 -07:00
AgentSeal
0454e65fad chore: add timestamp diagnostic script 2026-04-15 04:09:59 -07:00
AgentSeal
5da6e772e4 feat: change 90-day period to 120 days 2026-04-15 04:05:12 -07:00
AgentSeal
76c9edd811 feat: debounce arrow key period switching (600ms)
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.
2026-04-15 04:04:23 -07:00
AgentSeal
5ead1e9c07 perf: yield to event loop before heavy SQLite query
Adds a setTimeout(0) before parseBubbles so Ink can render
the Loading state before the synchronous query blocks.
2026-04-15 04:01:17 -07:00