Commit graph

448 commits

Author SHA1 Message Date
iamtoruk
bfa5fe7fa0 fix(labels): update remaining 'all' period labels to '6 Months'
PR #221 unified the period logic but missed the TUI hotkey bar,
GNOME indicator popup, and macOS menubar app. All surfaces now
consistently show '6 Months' instead of 'All' or 'all time'.
2026-05-04 19:46:20 -07:00
Resham Joshi
32dfa8e165
Merge pull request #221 from ozymandiashh/fix/unify-all-period-semantics
fix(date-range): unify 'all' period semantics between CLI and dashboard
2026-05-04 19:43:28 -07:00
ozymandiashh
9a258a8a99 fix(date-range): avoid all-period month overflow 2026-05-05 05:05:13 +03:00
Resham Joshi
f5cbfe28bb
Overhaul GNOME Shell extension with full-featured UI (#222)
Some checks are pending
CI / semgrep (push) Waiting to run
* Rewrite GNOME extension UI with branded popover matching macOS menubar

Combines PR #212's modular architecture (DataClient, GSettings, Libadwaita
prefs) with the custom St widget UI from feat/tauri-menubar-win-linux.

Adds: branded header, horizontal agent tabs, hero typography, period/insight
pills, 19-day token histogram, 6 content views (Activity, Trend, Forecast,
Pulse, Stats, Plan), currency switcher with FX conversion, findings CTA,
budget alerts, theme detection, payload caching with TTL.

* Add Main.panel.addToStatusArea call to extension entry point

* Align activity/model rows as table with separators, gear icon for prefs

* Add table column headers, oneshot placeholder, currency picker dropdown

* Enhance GNOME extension with scrollable UI, dark mode, charts, and performance fixes

- Add vertical scroll for popup content and horizontal scroll for 6+ provider tabs
- Add token histogram chart with hover tooltips showing date, in/out tokens, cost
- Add skeleton loading animation with stale-while-revalidate caching (5min TTL)
- Add dark/light theme support with force-dark-mode setting
- Add exact costs toggle for full decimal values
- Add right-aligned columns for cost, turns, oneshot, and model data
- Remove unsupported St CSS properties (text-align, letter-spacing)
- Fix post-destroy crash: guard async callbacks, abort Soup session on teardown
- Fix dataClient double-resolve race with settled guard
- Expand PATH resolution for volta, bun, cargo, asdf, fnm, pnpm
- Reduce CLI timeout from 45s to 15s and cache augmented PATH
- Remove unused imports (Pango, Main) and dead constants
- Show 10 top activities, remove Plan pill
2026-05-04 18:05:59 -07:00
ozymandiashh
3dc3e32715 fix(date-range): unify 'all' period semantics between CLI and dashboard
`getDateRange` was duplicated across `src/cli.ts` and `src/dashboard.tsx`
with conflicting semantics for `'all'`. The CLI intentionally bounded
`'all'` to the last 6 months (justified inline: keeps Codex/Cursor parses
responsive on sparse multi-year history). The dashboard returned
`new Date(0)` instead, so the same `--period all` flag silently meant
two different windows depending on which entry point you hit.

`Period`, `PERIODS`, `PERIOD_LABELS`, and `toPeriod` were duplicated as
well, and `cli-date.ts` already existed for date helpers
(`parseDateRangeFlags`) so the consolidation lives there.

Both call sites now go through a single `getDateRange(period: string)`
in `cli-date.ts` that returns `{ range, label }`. The dashboard wraps it
as `getPeriodRange(period: Period)` to keep the strict `Period` type at
the React boundary while letting the CLI continue to accept extras like
`'yesterday'`.

`PERIOD_LABELS.all` becomes `'6 Months'` (short, for the dashboard tab
strip; the previous `'All Time'` was misleading and the long-form
`'Last 6 months'` from `getDateRange().label` already drives CLI output).

Changes:
- src/cli-date.ts: add `Period`, `PERIODS`, `PERIOD_LABELS`, `toPeriod`,
  `getDateRange`. Pull the existing 6-month rationale into a named
  `ALL_TIME_MONTHS` constant.
- src/cli.ts: drop the local copies and import from cli-date.
- src/dashboard.tsx: drop the local copies, route through
  `getPeriodRange`, alias the shared `getDateRange` import to
  `getDateRangeShared` to avoid shadowing the wrapper.
- tests/cli-date.test.ts: 13 cases covering `'all'` regression guard
  (must never silently fall back to `Date(0)`), CLI/dashboard agreement,
  end-of-month clamping tolerance, `'yesterday'` support, and
  unknown-input fallback.
- README.md, CHANGELOG.md: surface the bound and point heavy users at
  `--from`/`--to` for unbounded windows.

The CLI flag `--period all` continues to be accepted; only the dashboard
window changes to match what the CLI was already doing. No public API
or schema change.

Refs #93
2026-05-05 03:53:46 +03:00
Resham Joshi
18335a1f9d
Merge pull request #212 from thameem-abbas/feat/gnome-extension
Some checks are pending
CI / semgrep (push) Waiting to run
Merging GNOME Shell extension as foundation - will enhance UI in follow-up
2026-05-04 10:50:36 -07:00
iamtoruk
6fb05c6813 Fix command injection in yield via execFileSync
Replace execSync with execFileSync and argument arrays so shell
metacharacters in git branch names cannot be interpreted as commands.
Add SAFE_REF_PATTERN validation as defense in depth for branch names
from git symbolic-ref.

Addresses #214.
2026-05-04 10:13:40 -07:00
iamtoruk
15334fac67 Add SHA-256 checksum verification to menubar installer
The installer now downloads and verifies a .sha256 companion file
before extracting and launching the menubar app. Build script and
CI workflow generate the checksum alongside the zip. Adds SECURITY.md
with reporting instructions.

Addresses #215.
2026-05-04 10:08:58 -07:00
thameem-abbas
87e45f43df fix: compact mode toggle updates instantly without restart
Toggle label visibility instead of rebuilding panel children.
Label always added to panel, just hidden when compact=true.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-04 09:46:21 -04:00
thameem-abbas
30b3ad0503 feat: add GNOME Shell extension for Linux panel indicator
GNOME 45+ extension that shows live token costs in the top bar panel
with a dropdown for provider breakdown, top activities/models, cache
stats, and budget alerts. Polls `codeburn status --format menubar-json`
every 30s — same data contract as the macOS menubar app.

Includes GSettings preferences (refresh interval, compact mode, budget
threshold, per-provider enable/disable toggles) with Libadwaita UI.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-04 09:44:35 -04:00
Resham Joshi
cf8c2aa493
Merge pull request #206 from voidborne-d/fix/skill-subcategory-203
Some checks are pending
CI / semgrep (push) Waiting to run
fix(classifier): surface skill name as subCategory for general turns (#203)
2026-05-03 16:42:47 -07:00
Resham Joshi
ac8081bb08
Merge pull request #207 from ozymandiashh/fix/codex-stream-large-sessions
Stream-parse Codex session files to fix oversize-cap drops on heavy users
2026-05-03 16:35:30 -07:00
ozymandiashh
61be92a834 Stream-parse Codex session files to handle 250+ MB rollouts
Heavy Codex users hit MAX_SESSION_FILE_BYTES (128 MB) on long-running
sessions. The file is read in full via readSessionFile and then split on
'\n', so even bumping the cap eventually runs into V8's 512 MB string
limit (split doubles the high-water mark).

readSessionLines is a streaming generator that already exists in
fs-utils for exactly this case but only readFirstLine was using it.
Switch the Codex provider to consume it and let the cap apply only when
streaming would still be unreasonable.

Changes:
- src/fs-utils.ts: introduce MAX_STREAM_SESSION_FILE_BYTES (2 GB) and
  apply it in readSessionLines instead of the full-read cap. Keep
  MAX_SESSION_FILE_BYTES for readSessionFile / readSessionFileSync
  consumers that materialize the whole file.
- src/providers/codex.ts: replace `readSessionFile -> split('\n')` with
  `for await (... of readSessionLines)`. Add sawAnyLine guard so a
  failed/empty stream skips cache write, preserving the previous
  early-return behavior.

Empirical impact on a real account with one 247 MB rollout: 7-day totals
went from 4,536 calls / €358.69 / 20.1M input tokens to 6,111 calls /
€550.67 / 37.3M input tokens. The previously-skipped session is now
included; no other behavior changes.

Refs #204
2026-05-04 02:15:04 +03:00
voidborne-d
c16b21ec50 fix(classifier): surface skill name as subCategory for general turns (#203)
Turns whose only assistant tool is `Skill` collapse to category `general`
because `classifyByToolPattern` returns `'general'` and `refineByKeywords`
only operates on `coding`/`exploration`. In environments that lean on Claude
Code skills, the per-activity dashboard column flattens — every `/init`,
`/review`, `/security-review`, `/claude-api`, plus user-defined skills, all
land in `general` with no signal about which workflow ran.

Implements Option A from the issue:

- `ParsedApiCall.skills: string[]` populated in the Anthropic-path parser
  via a new `extractSkillNames` helper that reads `input.skill || input.name`
  from each `Skill` ToolUseBlock (mirrors `detectGhostSkills` extraction at
  optimize.ts:765 so the two stay in sync).
- `ClassifiedTurn.subCategory?: string` set to the first skill name when the
  resolved category is `general` AND any skill identifier was extracted.
  Top-level category stays `general` — existing aggregations, exports, and
  category-keyed code paths unchanged.
- `SessionSummary.skillBreakdown: Record<string, {turns,costUSD,editTurns,
  oneShotTurns}>` populated in the same per-turn loop that builds
  `categoryBreakdown`. Provider sessions (Codex/Cursor/etc.) keep `skills:
  []` — they don't expose the Skill tool surface today.
- Dashboard `ActivityBreakdown` renders top-N skill sub-rows beneath the
  `general` row when present (indented `/skill-name`, dimmed). Other
  categories render exactly as before; if no skills were invoked, the panel
  is byte-identical to current output.

Existing 419 tests still pass. New `tests/classifier.test.ts` adds 8 cases:
single skill via `input.skill`, single via `input.name`, first-wins for
multi-skill turns, aggregation across multiple assistant calls in one turn,
no-name fallback (`subCategory` stays undefined), `Skill+Edit` promoting to
`coding` and dropping subCategory, non-Skill general turns, and a legacy
ParsedApiCall shape with `skills` field absent (forward-compat). Pre-fix
verification by stashing the source change reproduces 4/8 failures with the
exact "expected 'init', received undefined" diff; restoring → 8/8 pass.

Closes #203.

🤖 AI assistance disclosure: assistant-scaffolded by Claude (Opus 4.7);
author of record reviewed every line, ran the full vitest suite locally
(`npm test` → 32 files / 427 tests pass), `npx tsc --noEmit` clean, and
`npm run build` produces a clean ESM bundle.
2026-05-04 06:26:45 +08:00
iamtoruk
7501aee130 Add Goose and Antigravity providers to README, bump provider count to 18 2026-05-03 12:14:35 -07:00
iamtoruk
6dbd25ce55 Bump version to 0.9.6 2026-05-03 12:12:56 -07:00
iamtoruk
988398abfc Fix $0.0000 display for near-zero costs
Closes #205
2026-05-03 12:11:10 -07:00
iamtoruk
6702d55345 Fix menubar provider view showing $0.00 after idle and refresh race condition
CLI timeout increased from 20s to 45s to handle cold file-cache latency on
provider-specific queries. Loading overlay now appears when the all-provider
payload confirms a provider has spend but its dedicated data hasn't loaded yet.
Manual refresh (force: true) bypasses the in-flight guard so users can always
re-fetch. Tab strip prefers the provider-specific payload cost when available
so it stays in sync with the hero section.
2026-05-03 12:00:03 -07:00
AgentSeal
8cf68e7a16 Fix Antigravity dedup collision and add Codex ChatGPT Plus token estimation (#204)
- Antigravity: use loop index as fallback when responseId is empty to prevent
  all entries in a cascade sharing the same dedup key; bump CACHE_VERSION to
  force re-parse of stale cached data
- Codex: estimate tokens from message text when info is null (ChatGPT Plus/Pro
  subscription sessions), feeding through calculateCost so subscription users
  see API-equivalent spend; add costIsEstimated flag to ParsedProviderCall
- Update LiteLLM pricing snapshot
2026-05-03 19:51:13 +02:00
Resham Joshi
95585febf4
Merge pull request #201 from getagentseal/fix/streaming-dedup
Some checks are pending
CI / semgrep (push) Waiting to run
Fix streaming dedup: keep last message.id occurrence for accurate tokens and tools
2026-05-02 22:30:48 -07:00
iamtoruk
800c106250 Fix streaming dedup: keep last occurrence of each message.id within session files
Claude Code writes the same message.id multiple times during streaming.
The first write has partial tokens (often 1) and no tool_use blocks.
The last write has authoritative token counts and all tool_use/MCP blocks.

Old behavior kept the first occurrence (keep-first), silently dropping
real output tokens (+6.3% undercount) and all MCP tool calls.

New behavior keeps the last occurrence's content but preserves the first
occurrence's timestamp for correct date bucketing.

Validated against 21,390 real session files: 40.5% had duplicate IDs,
output tokens were understated by up to 78% per session.
2026-05-02 22:30:17 -07:00
iamtoruk
341aa46f78 Strip ANSI escapes from bash commands across all providers
Use strip-ansi (already in dep tree via Ink) in extractBashCommands
to prevent terminal escape codes from leaking into dashboard bash
breakdown keys. Route goose, gemini, qwen, and openclaw through
extractBashCommands instead of inline split, which also gives them
multi-command extraction (matching claude/codex/droid behavior).
2026-05-02 20:59:24 -07:00
iamtoruk
292265bf47 Add deno dx as a run method 2026-05-02 20:31:27 -07:00
iamtoruk
fe1007cc63 Add missing Antigravity model aliases for gemini-3-pro, flash-image, flash-lite 2026-05-02 20:26:45 -07:00
Resham Joshi
f5b66861f7
Merge pull request #199 from NihalJain/fix_Antigravity
Good catch on the Antigravity model aliases
2026-05-02 20:26:05 -07:00
Nihal Jain
73cf90cb2c Add Antigravity Gemini model IDs with preview pricing aliases 2026-05-03 05:46:33 +05:30
iamtoruk
87b660e584 Fix hardcoded $ in forecast comparison text
Some checks are pending
CI / semgrep (push) Waiting to run
The "vs last month" line in the forecast section used a hardcoded $
instead of the user's selected currency symbol and rate. Use
asCompactCurrency() which handles both.

Closes #197
2026-05-02 16:16:43 -07:00
iamtoruk
c511627e87 Fix dashboard hang and ExperimentalWarning on Windows
Strip Ink v7 DEC mode 2026 synchronized output markers (BSU/ESU) on
Windows. ConPTY does not implement this protocol and buffers
indefinitely, causing the dashboard to hang with no output. The patch
intercepts standalone BSU/ESU writes on stdout while preserving full
interactivity (keyboard, live refresh, cursor management).

Fix ExperimentalWarning timing: the process.emit patch was restored
synchronously in the finally block, but Node defers the warning via
process.nextTick. Delay restore by one tick so the patch is still
active when the warning fires.

Closes #195
2026-05-02 11:54:58 -07:00
Resham Joshi
db993196cf
Fix menubar ghost status item on macOS Tahoe
Set accessory activation policy in willFinishLaunching before the
focus chain forms. Debounce observation tracking to coalesce rapid
property changes into a single status bar refresh.
2026-05-02 10:14:14 -07:00
Resham Joshi
3ea4a62408
Add Goose provider, fix Codex fork dedup
Some checks are pending
CI / semgrep (push) Waiting to run
Goose: read token usage from ~/.local/share/goose/sessions/sessions.db.
Lazy-loaded, zero overhead for non-Goose users.

Codex: use sessionId instead of file path in dedup key so forked
sessions sharing the same session_id don't double-count tokens.
2026-05-02 09:58:52 -07:00
Resham Joshi
8c845253c2
Add Antigravity IDE provider
Fetch token usage from Antigravity's local language server via RPC.
Falls back to cached results when the IDE is closed.
2026-05-02 08:58:23 -07:00
Nihal Jain
791f2b077d
Add gpt-5.5 model display name for Codex 2026-05-02 08:57:44 -07:00
Resham Joshi
110a1f506d
Merge pull request #189 from ozymandiashh/fix/codex-large-session-meta-buffer
Some checks are pending
CI / semgrep (push) Waiting to run
fix(codex): read complete session_meta line during discovery
2026-05-01 17:32:55 -07:00
ozymandiashh
ffe14fecb7 review: silence stream errors and tighten comment wording
- Attach a no-op `stream.on('error', () => {})` so a late read-ahead
  error that races with a successful first-line yield can never escape
  as an unhandled 'error' event. Defense in depth: empirically the
  destroy() in finally already swallows it on Node 18+, but the listener
  removes any version-dependent surprise.
- Tighten the comment to say "up to FIRST_LINE_READ_CAP" instead of
  "regardless of length"; the cap is real and worth being precise about.
2026-05-02 02:38:36 +03:00
ozymandiashh
ff8b20a79e review: drop streamError flag, add multi-chunk and torn-write tests
- Stop tracking a separate streamError flag. createReadStream's default
  64 KiB highWaterMark means the stream may already be reading chunk 2
  when we break out of the loop after yielding the first line; if that
  later chunk errors, the flag could reject an otherwise-valid line.
  readline's async iterator already re-throws stream errors on Node 16+,
  which the existing catch handles.
- Test: 120 KB session_meta line forces multi-chunk line assembly.
- Test: truncated mid-write first line is rejected, not parsed as half
  an object.
2026-05-02 02:34:41 +03:00
ozymandiashh
98bbe5b678 review: cap first-line read size and add edge-case tests
- Cap createReadStream at 1 MiB so a malformed file with no newline
  cannot make readline buffer indefinitely (real session_meta lines
  are 22-27 KB).
- Capture stream errors explicitly; readline's async iterator does
  not always re-throw underlying stream errors per Node docs.
- Test: assert project is extracted from the >16 KB session_meta to
  prove the line was actually parsed, not just discovered.
- Test: session_meta line with no trailing newline is still accepted.
- Test: empty rollout file is silently skipped.
2026-05-02 02:30:17 +03:00
ozymandiashh
945da9f0ba fix(codex): read full first line for session validation
`readFirstLine` allocated a fixed 16 KB buffer, but Codex CLI 0.128+
embeds the entire base_instructions / system prompt in the
`session_meta` line, pushing it past 20 KB. When the buffer doesn't
catch a newline, `isValidCodexSession` rejects the session, so every
recent Codex session is silently excluded from totals.

Switch to a streaming readline read so the first line is captured
regardless of length, and add a regression test that creates a
40 KB session_meta payload.

Locally, this changes my 30-day Codex total from €267 (only ~half
of sessions parsed) to €878 (all sessions parsed).
2026-05-02 02:17:53 +03:00
iamtoruk
033da415c5 Bump version to 0.9.5
Some checks are pending
CI / semgrep (push) Waiting to run
2026-05-01 08:16:14 -07:00
Resham Joshi
ffc0e486d3
Merge pull request #188 from getagentseal/feat/menubar-hardening
Harden menubar: refresh loop, concurrency, data sync, edge cases
2026-05-01 08:03:03 -07:00
iamtoruk
39fc05595c Harden menubar: fix refresh loop, concurrency, data sync, and edge cases
- Fix refresh loop: proper while loop with 30s sleep and force:true
  instead of single-fire Task that never repeated
- Fix loading overlay: counter-based isLoading so concurrent fetches
  don't flicker the overlay on/off
- Fix rapid tab switching: cancel previous switchTask, check
  Task.isCancelled after CLI returns to discard stale results
- Fix tab strip vs hero desync: fetch provider-specific and all-provider
  data in parallel so costs arrive from same data snapshot
- Fix stale menubar icon after wake: forceRefresh now fetches today/all
  in parallel alongside the current selection
- Fix accent color: ThemeState is now @Observable so color changes
  propagate via observation, removing .id() view hierarchy teardown
- Fix currency flash: defer store.currency and symbol update until a
  rate is available so symbol and rate apply atomically
- Fix export: terminationHandler instead of waitUntilExit (no UI freeze),
  HHmmss in filename to prevent overwrite on double-export
- Fix CurrencyState: @MainActor isolation with proper Sendable
  conformance, nonisolated on pure static functions
- Fix streak count: iterate calendar days instead of sparse history
  entries so gaps are counted as streak-breakers
- Fix TrendBar identity: stable date-based id instead of UUID
- Add GPT-5.3 and DeepSeek model display names
2026-05-01 08:01:25 -07:00
Resham Joshi
bbe99fa298
Merge pull request #180 from josteinaj/locate-workspaceStorage-in-vscode-dev-container
Some checks are pending
CI / semgrep (push) Waiting to run
VSCode: correctly locate workspaceStorage when working inside a dev container
2026-04-30 18:41:20 -07:00
Resham Joshi
78ad04c77f
Merge pull request #186 from getagentseal/fix/menubar-timezone-184
Fix timezone handling for non-UTC users
2026-04-30 17:33:27 -07:00
iamtoruk
68c6f2c710 Fix timezone handling: menubar UTC bugs, --timezone flag, DST-safe dates
Three fixes for issue #184:

1. Menubar Swift code used UTC instead of local timezone in two places:
   computeHistoryStats hardcoded TimeZone("UTC") and
   effectiveTokensInLast7Days used ISO8601DateFormatter (UTC default).
   Both now use .current to match CLI-produced local date keys.

2. Add --timezone flag and CODEBURN_TZ env var to override the system
   timezone for all date grouping. Sets process.env.TZ before any Date
   operations so all existing local-timezone code works unchanged.

3. Replace MS_PER_DAY arithmetic with Date constructor day-of-month
   math for yesterday/backfill computations. Subtracting 86400000ms
   from midnight skips a day on DST spring-forward (23-hour day).

Fixes #184
2026-04-30 17:33:02 -07:00
Resham Joshi
7ceef6b464
Merge pull request #185 from getagentseal/feat/codex-result-cache
Some checks are pending
CI / semgrep (push) Waiting to run
Add per-file result cache for Codex provider
2026-04-30 16:44:26 -07:00
iamtoruk
8ab9ea916b Add per-file result cache for Codex provider
Fixes #183. Users with large Codex session directories (45 GB, 10K+
files) experienced CPU pegging because every 30-second refresh re-parsed
all session files from scratch.

Three optimizations:

1. readFirstLine now reads 16 KB via fs.open() instead of loading the
   entire file through readSessionFile. Cuts discovery I/O from ~45 GB
   to ~160 MB for 10K files.

2. Per-file result cache (codex-results.json) with mtime+size
   fingerprinting. Parsed results are cached on first run; subsequent
   runs return cached data instantly for unchanged files.

3. Cache-accelerated discovery skips header validation for cached files,
   pulling the project name directly from the cache manifest.

Cache safety: fingerprint captured before read (no TOCTOU), atomic
write via temp+fsync+rename, 0o600 permissions, Object.hasOwn for
prototype pollution defense, eviction of deleted files on flush,
try/finally ensures flush even on parse errors.
2026-04-30 16:43:41 -07:00
Jostein Austvik Jacobsen
2de8909823
locate workspaceStorage in vscode dev container 2026-04-30 22:51:52 +02:00
iamtoruk
f35400f199 Fix menubar refresh stuck after first load (#179)
forceRefresh() was missing force:true, so the cache TTL guard
silently skipped every LaunchAgent and wake-triggered refresh.
Also adds right-click context menu and version label in footer.
2026-04-30 09:22:38 -07:00
Resham Joshi
78aa6fc534
Merge pull request #181 from davidg-h/fix/copilot-vscode-insiders-integration
Some checks are pending
CI / semgrep (push) Waiting to run
fix(copilot): discover VS Code Insiders transcripts
2026-04-30 07:53:57 -07:00
David
116388427e fix(copilot): discover VS Code Insiders transcripts 2026-04-30 16:27:22 +02:00
Resham Joshi
2e354834e6
Update README.md
Some checks are pending
CI / semgrep (push) Waiting to run
2026-04-29 16:43:06 +02:00