Commit graph

1192 commits

Author SHA1 Message Date
iamtoruk
90f1d9ae1a fix(cli): optimize accepts --from/--to for custom date ranges
The desktop app's getOptimizeReport handler already appends --from/--to
when a custom range is active; without these options commander rejects
the invocation and the Optimize screen errors under a custom range.
2026-07-16 01:14:25 -07:00
Resham Joshi
405489f460
Merge pull request #665 from Enclavet/kiro_v2
Kiro: IDE v2 session store support + credit-based pricing across all formats
2026-07-16 00:18:11 -07:00
Andrew Lee
bdf4f3fe24 kiro: price v1 executions from credits; unify fallback across parsers
v1 modern execution files carry the same metered credits as v2
(usageSummary[].usage, unit "credit" — the predecessor of v2's
promptTurnSummaries), but the parser only harvested usedTools from
that array and priced executions from estimated tokens. Since v2 only
ships in brand-new IDE builds, v1 is the format nearly all Kiro IDE
users are on today. Sum usage across usageSummary entries and price at
the public overage rate.

Align all three credit parsers (CLI, v1, v2) on one fallback contract —
gate on summed credits > 0 and fall back to token-estimated pricing
with costIsEstimated: true:

- CLI turns without metering_usage were priced at a frozen $0
- CLI turns with an EMPTY metering_usage array (75 of 10,105 real turn
  metadatas — meta written before metering lands) passed the truthy
  presence check and froze $0 marked as real cost
- legacy .chat calls now carry costIsEstimated: true, which was always
  the reality but never stated

Validated against a real machine: 221 of 277 v1/legacy calls now carry
metered cost ($20.11) instead of token estimates that had overstated
them ~5x; verified usageSummary values are per-turn amounts, not
cumulative counters (sequences fluctuate). Call counts unchanged before
and after — nothing gained, lost, or double-counted.

Also document the companion-file fingerprint blind spot at
fingerprintFile: kiro CLI credits and v2 modelId live in companion
files the single-file fingerprint never sees, so a parse racing the
companion write can cache fallback values that only self-heal while
the transcript keeps changing.

AI-Origin: ai-generated
AI-Tool: kiro
2026-07-14 22:36:08 +00:00
Andrew Lee
7dcd618898 kiro: preserve credit-based cost through the session cache
providerCallToCachedCall drops provider-computed costUSD unless the
provider is allowlisted, and cachedCallToApiCall then re-prices from
token counts. Kiro's cost now comes from metered credits, which token
pricing cannot reproduce — reports were understating real kiro spend
~18x (e.g. $130.72 of metered CLI credits reported as $7.20 of token
estimates). Add kiro to the pass-through allowlist, same as the other
platform-billed providers (mistral-vibe, devin, hermes, ...).

Both persistence layers froze pre-fix dollar values and neither
self-invalidates (historical session files never change), so bump:

- session cache: CACHE_VERSION 4 -> 5 (cached kiro entries carry
  costUSD: undefined and would keep being token re-priced forever)
- daily cache: DAILY_CACHE_VERSION 10 -> 11 with MIN_SUPPORTED_VERSION
  raised (finalized days carry token-estimated kiro costs off by up to
  16x per model), same as the v10 cursor precedent

Test: end-to-end through parseAllSessions — a CLI fixture with 2.5
metered credits must report $0.10; fails with the token re-price
($0.000048) when the allowlist entry is removed.

Docs: document the pricing contract in docs/providers/kiro.md — metered
credit cost is frozen at parse time, so price-override / model-alias
do not affect kiro dollar amounts (shared tradeoff of all allowlisted
providers).

AI-Origin: ai-generated
AI-Tool: kiro
2026-07-14 22:35:51 +00:00
Andrew Lee
a1f8f4c4ff kiro: add IDE v2 session store support with credit-based pricing
Kiro's new IDE builds write sessions to ~/.kiro/sessions/<hash>/sess_<id>/
(session.json + messages.jsonl event log) instead of globalStorage. Add a
v2 parser and discovery, plus fixes surfaced while validating against a
real upgraded machine:

- Parse v2 event-sourced turns (user/turn_start/assistant/tool_call/
  tool_result/usage_summary/turn_end) with per-execution dedup keys
  (kiro-v2:<session>:<execId>) and defensive flushes for out-of-order
  events and in-progress sessions
- Price turns from real metered credits at the public overage rate
  (USD_PER_KIRO_CREDIT = $0.04/credit, individual plan: $20/mo for
  1,000 credits), falling back to token estimation only when a turn has
  no usage_summary (aborted/in-flight); costIsEstimated distinguishes
  the two
- Fix pre-existing CLI parser bug: metering_usage values are credits,
  not dollars — costs were overstated 25x at the real rate
- Count v2 tool_result content as input context (matching the CLI
  parser's ToolResults treatment); previously only the user prompt was
  counted, undercounting input ~25x on agentic turns
- Keep reasoningTokens disjoint from outputTokens: downstream
  aggregation (models-report, audit-report, parser) sums the two
  fields, so folding reasoning into output would double-count. Combine
  them only for the token-pricing fallback, matching codex/gemini
- Take the real modelId from session.json, so v2 sessions are not
  mislabeled kiro-auto
- Extract parseWorkspaceSession from the inline createParser block for
  parity with the other four format parsers
- Add v2SessionsRootOverride and stop deriving the v2 scan root from
  the cliDir parent when only agentDirOverride is set (tests were
  scanning the system tmpdir)
- Tests: v2 parsing/discovery/dedup/routing, credit vs fallback
  pricing, tool_result turn scoping, reasoning disjointness, cli-dir
  skip guard, and a mixed-format coexistence suite (legacy .chat + v1
  executions + workspace-sessions + CLI + v2 on one machine) asserting
  exact aggregate counts and no double counting
- Docs: v2 store layout, credit pricing, dedup namespaces, and the
  disjoint-store verification (v1->v2 is a clean cutover, no
  migration/dual-write observed)

AI-Origin: human
2026-07-14 22:35:51 +00:00
Resham Joshi
e5625c68fe
Merge pull request #661 from getagentseal/iamtoruk-patch-2
Some checks failed
CI / semgrep (push) Has been cancelled
Fix punctuation and improve README clarity
2026-07-13 23:43:54 -07:00
Resham Joshi
51f7d5bb5f
Fix punctuation and improve README clarity
Corrected punctuation and clarified descriptions in the README.
2026-07-14 08:43:04 +02:00
Resham Joshi
67f0df0020
Merge pull request #660 from Enclavet/feat/sync
Some checks are pending
CI / semgrep (push) Waiting to run
feat: `codeburn sync` — push usage telemetry to a team backend (preview)
2026-07-13 11:58:31 -07:00
Andrew Lee
d8a7b2a95f fix(sync): address PR review — https enforcement, keychain test isolation, golden ID pins
Before-merge items:
1. HTTPS enforced on every remote endpoint (RFC 8252 §8.3): baseUrl,
   issuer, authorization/token/revocation endpoints, and the traces
   endpoint all reject non-https, with a loopback (127.0.0.1/::1/
   localhost) exception for offline tests and local dev. Enforcement is
   central (assertHttps) — the browser-open guard is no longer the only
   check whose failure was swallowed.
2. Credential store test isolation: CODEBURN_SYNC_TOKEN_STORE=file
   forces the file store (honors HOME) so the offline suite never
   touches the real macOS login keychain. Set in the e2e suite.
3. Golden pins for deriveSpanId/deriveTraceId/deriveDeviceId with fixed
   inputs and expected hex — the idempotency contract depends on these
   encodings being stable across releases; a green-tests encoding change
   would silently double-count history on span-ID-keyed backends.
   getDeviceId refactored over a pure deriveDeviceId(host, user).

Smaller review items:
- Callback server: ready promise resolves the actually-bound port from
  the listening event (kills the 100ms-sleep race after port fallback);
  Connection: close on all responses + closeAllConnections() on
  shutdown (pooled keep-alive sockets from a closed server could
  swallow requests aimed at a later server on the same port); error
  handler guarded so a post-bind error can never rebind to a different
  port than advertised; optional ports param ([0] = ephemeral) removes
  fixed-port contention between parallel test workers.
- fetchOidcConfig verifies the issuer claim matches the fetch origin
  (OIDC Discovery §4.3 mix-up defense).
- partialSuccess.rejectedSpans wrapped in Number() — proto3 int64 JSON
  mapping sends strings from strict protojson servers; += would
  concatenate.
- Ledger writes are atomic (temp + rename); corrupt-ledger recovery and
  no-tmp-left-behind tests added; XDG_CACHE_HOME honored (ledger is
  reconstructible state, not config).
- Mock IdP now implements /oauth2/authorize (registers PKCE challenge,
  302s to redirect_uri) and verifies S256 code_verifier + single-use
  codes at the token endpoint. The e2e drives the real redirect flow
  and asserts wrong-verifier and code-reuse are rejected — PKCE binding
  is now exercised end to end.
- sync reset calls clearLedger() instead of reimplementing the path.
- push sets exit code 1 on rate-limited/server-error outcomes so cron
  and script callers can detect incomplete pushes.

Deferred (noted for fast-follow): macOS 'security -i' stdin mode
(untestable on this Linux box), ai.cost_estimated as a real
ParsedApiCall flag (touches core parser types).

Sync suite: 81 passing (5x stable), 5 developer-only.

AI-Origin: human
2026-07-13 16:45:39 +00:00
iamtoruk
a8351bfd1a fix(app): daily charts empty/flat on real data — use real last-N days
contiguousDailyWindow rebuilt a calendar window from the client clock and looked
up days by date key; on real CLI data every lookup missed and zero-filled, so the
Spend chart went empty and the Overview chart went flat. Use the real last-N
backfilled entries of history.daily directly (Spend last-15, Overview
last-max(30, periodDaily)) and remove the dead helper.

typecheck clean; 147/147 tests pass.
2026-07-12 17:06:46 -07:00
iamtoruk
a216b841ae feat(app): rebuild Plans on live quota (real 5h/weekly windows + auto-detected tier)
Replace the $-budget model as the primary view: per-provider cards (Claude/Codex)
from getQuota show the real 5-hour/weekly windows (% used, resets-in, severity
colors), the auto-detected subscription tier, connection states, and the credit
footer. Manual budget plans demoted to a secondary section.

typecheck clean; 148/148 tests pass. Needs a full relaunch for live quota.
2026-07-12 16:48:58 -07:00
iamtoruk
880f84d593 feat(app): live quota fetch module + getQuota bridge (Phase 4 backend)
Port the menu bar's OAuth quota fetch to the Electron main:
- app/electron/quota/{claude,codex,index,security}.ts reads the local Claude/
  Codex credentials, hits the usage APIs, normalizes to QuotaProvider (5h/weekly
  windows, auto-detected tier, resets-at) with 429 backoff + single-flight
- getQuota IPC bridge (main + preload + renderer types); needs a full relaunch

Security: tokens are never returned or logged (redact Bearer/sk-ant/sk-/JWT,
strip NUL, truncate 240); credential reads refuse symlinks (O_NOFOLLOW/lstat) and
insecure modes; Anthropic refresh is never POSTed (single-use, shared with CLI).

typecheck clean; 147/147 tests pass; Electron build passes.
2026-07-12 16:43:53 -07:00
iamtoruk
905d94253a feat(app): actionable Optimize — wire the CLI's rich findings + copy-paste fixes
- new getOptimizeReport bridge (main + preload + renderer types) running
  `codeburn optimize --format json` (needs a full relaunch)
- restore the Waste / Reverts / Abandoned / Fixes tabs
- Waste findings expand inline to show the explanation (why you're losing
  tokens) + a copy-paste fix block with a Copy button, like the TUI
- summary header: findings count / potential savings / health score

typecheck clean; 133/133 tests pass.
2026-07-12 16:28:47 -07:00
iamtoruk
82f0402abd feat(app): Spend chart — fixed 15-day window + date axis, no gridlines
- extract contiguousDailyWindow + formatChartDate to lib/period (shared)
- Spend "Daily spend by model": fixed contiguous 15-day window (zero-filled)
  with an .ov-xax date axis, matching the Overview chart
- remove the horizontal gridlines from both charts (they read like data lines)

typecheck clean; 129/129 tests pass.
2026-07-12 16:21:41 -07:00
iamtoruk
185f25f8d1 feat(app): fixed-height + scrollbar on Spend list panels
By-project and the Activity/Tools/MCP/Subagents breakdown panels cap at 300px
with a slim internal scrollbar, so they stay a consistent compact size instead
of growing unbounded with the data.

typecheck clean; 126/126 tests pass.
2026-07-12 15:56:07 -07:00
iamtoruk
9d25fc3866 feat(app): Spend chart matches Overview + caps to 15 days
Drop the 11px stacked-segment cap so the bars fill their columns like the
Overview .chart; render only the last 15 days.

typecheck clean; 126/126 tests pass.
2026-07-12 15:54:44 -07:00
iamtoruk
0bab74c18d feat(app): flatten Optimize to one page (no tabs)
Drop the Waste/Reverts/Abandoned/Fixes tabs. One scrolling page: findings
(count + potential in the header), then Reverted and Abandoned session sections;
empty sections hidden. The redundant Fixes tab folds into the findings header.

typecheck clean; 126/126 tests pass (removed 2 now-moot tab-isolation tests;
impact-badge + section coverage preserved).
2026-07-12 15:34:16 -07:00
iamtoruk
bd32624afb feat(app): flatten Spend to one page (no tabs)
Drop the Projects/Activity/Tools/MCP/Subagents lens tabs. Everything shows on
one scrolling page: chart + By-project, Cost-flow Sankey, then the breakdown
sections in a responsive grid. Empty sections are hidden. All reflects the
selected date range.

typecheck clean; 128/128 tests pass.
2026-07-12 15:30:00 -07:00
iamtoruk
642a12b7ff feat(app): remove the Nearest-limit quota ring from Overview
Drop the FuelRing (and its now-unused plans polling) from the ov-stats3 card;
the stats row is now Month-to-date + Projected month (2 equal columns).

typecheck clean; 128/128 tests pass.
2026-07-12 15:25:00 -07:00
iamtoruk
49a2811093 feat(app): Settings — custom dropdowns, more currencies, fix pane layout
- new Dropdown component (our .pop menu style, keyboard-accessible) replacing
  every native <select> (currency, period, plan preset, export, Compare pickers)
- expand currencies to 30 common ISO codes (engine handles any valid currency)
- fix the Settings pane so rail + content anchor top-left and fill the area

typecheck clean; 128/128 tests pass.
2026-07-12 14:02:52 -07:00
iamtoruk
76a5db4f55 feat(app): Optimize organization + gear icon, more logos, drop relative-cost column
- Optimize: colored impact badges (High/Medium/Low) + fixed-column layout;
  fix the dead "Fixes" tab; findings no longer look falsely clickable
- Optimize nav icon: gear + magnifying glass (was a lightning bolt)
- remove the "Relative cost" bar column from the Overview models table
- provider logos: Goose / Pi / Warp + Cursor Agent (own logo) from repo assets

typecheck clean; 128/128 tests pass.
2026-07-12 13:56:07 -07:00
iamtoruk
a02ae15b6b feat(app): rebuild Sessions — fixed columns, clean paths, inline expand
- share a shortenProjectPath helper (Sankey + Sessions) so rows show
  "projects/eywa" instead of the dash-mangled full path
- fixed-column table layout so values align and stop shifting row-to-row
- TUI-style inline row expansion: click a row to unfold its 8-stat detail in
  place (one at a time, chevron + aria-expanded); replaces the navigate-away view

typecheck clean; 128/128 tests pass.
2026-07-12 13:38:45 -07:00
iamtoruk
44ef875a6d fix(app): adaptive K/M/B token counts on Models (was forced to M)
Models used a local fmtCompact that forced every token count to "M" (0.0M, 0.5M).
Switch to the shared adaptive formatCompact (K/M/B, whole numbers under 1000).

typecheck clean; 128/128 tests pass.
2026-07-12 13:32:46 -07:00
iamtoruk
1c236a47eb fix(app): only show used providers in picker + bottom-align hero activity
- provider dropdown: filter to providers with actual usage (value > 0) instead
  of every known/detected key (Pi, Goose, Warp, etc. no longer show)
- Overview hero: bottom-align the activity heatmap (space-between) so its grid
  lines up with the left column's Saved-to-date line

typecheck clean; 128/128 tests pass.
2026-07-12 13:26:19 -07:00
iamtoruk
144d2b3363 fix(app): strip prose em-dashes from UI copy
Replace em-dashes used as sentence punctuation (Plans, Settings, Compare,
Overview, CliErrorPanel) with cleaner punctuation; keep the standalone "—"
empty-value placeholders (a no-data convention). Update affected copy assertions.

typecheck clean; 128/128 tests pass.
2026-07-12 13:13:31 -07:00
iamtoruk
34333dc2c5 feat(app): more provider logos + drop redundant session dot
- ProviderLogo: add Copilot/Gemini/Qwen/OpenCode marks; reuse the Cursor logo
  for Cursor Agent; single-color logos (Claude, Gemini) via a SINGLE_LOGOS map
- remove the redundant model-series dot from Overview "Most expensive sessions"
  (the row already names the model in its sub text)

typecheck clean; 128/128 tests pass.
2026-07-12 13:09:53 -07:00
iamtoruk
6f4b2bef38 feat(app): About panel + working social links (+ LinkedIn)
- add a shell.openExternal bridge (main ipc handler + preload + renderer type)
  so links open in the default browser (requires a full relaunch)
- wire the sidebar social icons to real URLs and add LinkedIn
- AboutModal: flame + wordmark, version, tagline, the five social links, and a
  "Check for updates" link to the GitHub releases page

typecheck clean; 128/128 tests pass.
2026-07-12 13:07:38 -07:00
iamtoruk
428caab6fd feat(app): real provider logos in the picker and Settings
- add Claude/OpenAI/Cursor/Grok brand SVGs under app/renderer/assets/providers
- ProviderLogo component: brand-orange Claude in both themes; light/dark
  monochrome variants for OpenAI/Cursor/Grok swapped per active theme
- show the logo in the provider dropdown (trigger + menu items) and in
  Settings > Providers, left of each provider name

typecheck clean; 128/128 tests pass.
2026-07-12 13:00:43 -07:00
iamtoruk
3f40aeee97 feat(app): Sankey slash-paths + Models "By task" regroup
- Sankey project labels now show the last 2-3 path segments joined by "/"
  (dropping the users/home prefix) instead of the dash-mangled full path
- Models "By task" regrouped CI-style: a per-model group header (series dot +
  model + aggregate calls/cost/saved) with indented task sub-rows and aligned
  columns, replacing the flat list that repeated the model name on every row

typecheck clean; 128/128 tests pass.
2026-07-12 12:58:15 -07:00
iamtoruk
4186ad393a feat(app): color Fable as its own series (aqua)
Fable was bucketing into grey "Other" despite being a large chunk of spend.

- add `fable` SeriesKey across modelSeries.ts (label, css-var, class, matcher)
- validated CVD-safe --s-fable token (aqua #1baf7a light / #199e70 dark) in all theme blocks
- StackedBars now uses a fixed CVD-safe series order [opus, fable, haiku, gpt, sonnet, other]
  for both legend and stack, so aqua never sits adjacent to the magenta (Sonnet)

typecheck clean; 128/128 tests pass.
2026-07-12 12:52:12 -07:00
iamtoruk
b0299c57ac feat(app): design reskin — token unification, a11y, and chart color + shading
Design-consistency pass (from the audit):
- unify the indigo→plain grey/border token families (alias --t1/2/3, --hair/2 onto --ink/mut/mut2, --line/2); fix a leftover hardcoded chevron color
- accent :focus-visible rings on SegTabs, chart bars, calendar, buttons, Settings toggles; ov-link hover
- theme-aware Spend legend swatches + Sankey (fixes a light-mode contrast failure)
- wire Models "Compare…" → Compare and Plans "Add plan…" → Settings pane; drop the fake-affordance Plans label; Settings loading captions
- Compare card radius/title, set-input, alias CTA color, outer-border tokens, session mono numbers, frame spacing to match the mockup
- scope a date-flaky Overview test assertion to its card

Reskin batch 1 — color + shade (current tone):
- validated CVD-safe model-series palette via dedicated --s-* tokens (light+dark), applied to the daily bars, Sankey, and series dots
- subtle soft card elevation via --card-shadow on the main card containers

typecheck clean; 128/128 tests pass.
2026-07-12 12:36:50 -07:00
Andrew Lee
cec61e3b30 docs(sync): user guide, developer/protocol reference, README section
- docs/sync/README.md: setup, push, status, logout, reset; privacy
  guarantees; FAQ
- docs/sync/DEVELOPER.md: architecture, discovery/OTLP protocol,
  sent-ledger design rationale, partial-success and rate-limiting
  semantics, server contract, testing guide
- README.md: sync command group listed under Commands (preview label)

AI-Origin: human
2026-07-12 16:05:34 +00:00
Andrew Lee
163842edac test(sync): unit, mock-IdP e2e, and developer-only integration tests
Offline, CI-safe (70 tests):
- sync.test.ts (26): discovery parsing, PKCE, auth URL, scope
  negotiation, callback server (state mismatch, IdP error, timeout,
  port fallback), config round-trip
- sync-ledger-otlp.test.ts (23): deterministic ID derivation, OTLP
  structure/attributes, batching, ledger append/dedup/prune/clear
- sync-push.test.ts (15): pipeline against a scriptable mock OTLP
  server — success+ledger+cost, partial-success batch NOT ledgered,
  401 stop, 429 wait-and-retry / persistent-429 give-up / Retry-After
  parsing (delta-seconds, HTTP-date, garbage), 5xx deferral,
  idempotent failure recovery
- sync-e2e.test.ts (6) + fixtures/mock-idp.ts: full setup→refresh→
  rotate→logout round-trip against an in-process mock IdP

Developer-only (skip unless env vars set, never CI):
- sync-headless-e2e.test.ts (1): real browser PKCE flow via Playwright
- sync-infra-e2e.test.ts (4): push/auth-reject/batch/idempotent
  re-push against a deployed backend

AI-Origin: human
2026-07-12 16:05:34 +00:00
Andrew Lee
ca39a69b6b feat(sync): push AI usage telemetry to a team OTLP backend (preview)
Adds an opt-in `codeburn sync` command group: setup, push, status,
logout, reset. Developers authenticate via standard OIDC browser login
(Authorization Code + PKCE, provider-agnostic — Cognito, Auth0, Okta,
Keycloak, etc.) and push per-call usage metadata to a team-operated
OTLP/HTTP endpoint.

Privacy is structural: the payload builder has no field that can carry
prompts, responses, file contents, or bash commands. Only metadata
leaves the machine (provider, model, tokens, cost, project, tool names,
timestamps). There is deliberately no flag to include more.

Setup derives everything from a single URL:
  GET {base}/.well-known/codeburn-export.json
  → issuer, client_id, traces_path, max_batch_size

Modules:
- discovery.ts   discovery doc fetch/validation (version-gated)
- auth.ts        OIDC discovery, PKCE, localhost callback (:19876-78),
                 token exchange/refresh/revoke
- credentials.ts refresh token in OS keychain (macOS security / Linux
                 libsecret / Windows DPAPI / 0600 file fallback). All
                 subprocess calls use execFileSync arg arrays; tokens
                 flow via stdin or env var — never shell-interpolated
- config.ts      ~/.config/codeburn/sync.json
- ledger.ts      client-side sent-ledger for exact dedup (no watermark
                 races), 6-month prune
- otlp.ts        ParsedApiCall[] → ExportTraceServiceRequest JSON with
                 deterministic IDs: span=SHA256(dedupKey)[:8],
                 trace=SHA256(sessionId)[:16] — every retry idempotent
- push.ts        orchestration with typed outcomes; pushes run to
                 completion — 429 Retry-After honored (≤120s/wait,
                 3 retries/batch) before deferring; partial_success is
                 batch-atomic (nothing ledgered, whole batch retries);
                 50K safety valve, no routine cap
- cli.ts         command layer; --dry-run reports exact counts/cost
                 without sending

Preview feature: protocol may change between releases.

AI-Origin: human
2026-07-12 16:05:34 +00:00
iamtoruk
1de907ac8b feat(app): Settings part 2 — Plans, Export, Devices actions, theme on boot
- Plans tab: add/remove budget presets via `plan set`/`plan reset`, lists
  configured plans, links to the full Plans screen
- Export tab: format + provider + native folder picker (electron dialog)
  → runs `codeburn export`, reports the result
- Devices: real Remove (`devices rm`) + Refresh; visibility is read-only
  from `share status`; pairing shows an honest "pair from terminal" note
  instead of a dead Approve button; combine row is read-only status
- Apply the persisted theme at app startup (not only when General mounts)
- Settings gets onNavigate for the "Open Plans" link

Only one-shot, non-interactive CLI commands are wired as buttons; the
interactive share daemon and pairing flow stay honestly read-only.
2026-07-11 17:31:32 -07:00
iamtoruk
55e9fa51f6 feat(app): functional Settings — rail nav + General/Providers/Aliases/Privacy
Settings was a dead shell (rail didn't switch, all buttons disabled).
Now the rail navigates and four tabs are wired to the real CLI:
- action bridge: spawnCliAction + runAction (text output, not JSON) with
  getAliases/getProxyPaths reads and setCurrency/resetCurrency/addAlias/
  removeAlias actions
- General: theme switcher (System/Light/Dark, persisted) + live currency
  (reads status, changes via `currency`) + default-period preference
- Providers: real detected-tools list with spend
- Model aliases: full add/remove against real config
- Privacy: honest local-only info

Devices content preserved as-is; Plans/Export are placeholders for Part 2.
2026-07-11 17:24:04 -07:00
iamtoruk
ec0b80207b feat(cli): --format json list output for model-alias and proxy-path
Adds JSON list mode so the desktop Settings screen can read current
config: `model-alias --list --format json` emits AliasRow[] ({from,to},
sorted by from) and `proxy-path --list --format json` emits string[].
Text output and all mutation behavior are unchanged.
2026-07-11 17:17:04 -07:00
iamtoruk
1efc0ceb44 fix(app): daily-spend chart fills its card, bars bottom-aligned
The StackedBars chart lived in a fixed 96px band, so when the grid
stretched its card to match the taller "By project" panel the bars
floated at the top over a large empty gap. Make the panel/body flex so
the chart fills the card height (min 120px) with bars bottom-anchored;
round stacked-segment corners only at the top/bottom of each column.
2026-07-11 17:06:00 -07:00
iamtoruk
ea56ed33f0 fix(app): dev CLI beats a persisted/global codeburn path
The dev-mode repo dist/cli.js fallback ran AFTER the persisted-path file,
so a stale globally-installed codeburn (e.g. a Homebrew build lacking the
new sessions/compare commands) shadowed the repo build and every Sessions
call errored. Move the Vite-dev fallback ahead of the persisted-path
lookup; CODEBURN_BIN still overrides, and production (no VITE_DEV_SERVER_URL)
is unchanged.
2026-07-11 16:48:36 -07:00
iamtoruk
781d37674b feat(app): error boundary so a crashing screen shows the error, not a blank
A render error in any section previously white-screened the whole app
(no boundary). Wrap the section content in an ErrorBoundary keyed by
section: the error message + component stack render in a card, the
sidebar stays usable, and navigating away recovers. Logs to the console
for diagnosis.
2026-07-11 14:33:16 -07:00
iamtoruk
d9c56e3c6b feat(app): production-ready Sessions screen
Search (project/model/id), sort (cost/recent/turns/tokens), group-by-
provider toggle, and a summary bar (count · cost · tokens) over the
filtered set. Dependency-free "show more" paging keeps large lists fast;
provider headers are sticky and the list flows in the page scroll.

Richer detail: 8 real stat cards (cost/calls/turns/saved/input/output/
cache read+hit%/cache write), full date range + duration, Esc-to-back,
selection tracked by id so background refreshes keep the detail live.

Centralizes formatCompact/date/duration helpers in lib/format ("184K"
not "0.2M"); Compare now uses the shared helper. Search-aware empty state.
2026-07-11 13:50:58 -07:00
iamtoruk
e331c7da63 feat(app): Sessions and Compare screens
Sessions: provider-grouped list of every session in range (project,
models, turns, cost, tokens) with a lightweight real detail — no
fabricated titles, no unbacked context-window widget.

Compare: two-model picker (defaults to top two by cost) across
Performance, Efficiency, Category head-to-head, Working style, and a
derived Context panel, all mapped straight from `compare --format json`.

Nav reordered to match the design: Overview, Sessions, Spend, Optimize,
Models, Compare, Plans, Settings (⌘1-7).
2026-07-11 12:37:04 -07:00
iamtoruk
6023067bdc feat(app): bridge for sessions/compare + dev-mode CLI fallback
Adds getSessions / getCompareModels / getCompare IPC channels (argv for
the new CLI JSON emitters), mirrors SessionRow + compare-stats types into
the renderer, and — in Vite dev — resolves the repo's own dist/cli.js so
newly-added commands work without setting CODEBURN_BIN.
2026-07-11 12:37:04 -07:00
iamtoruk
fc1920d4f1 feat(cli): add compare and sessions JSON emitters
compare --format json: list mode (aggregateModelStats for pickers) +
full mode via --model-a/--model-b, emitting
{period, modelA, modelB, metrics, categories, workingStyle}.
Reuses computeComparison/computeCategoryComparison/computeWorkingStyle/
scanSelfCorrections; TUI path unchanged.

sessions --format json: new src/sessions-report.ts, uncapped flat
SessionRow[] (id, project, provider, models, cost, tokens, turns,
duration) via aggregateSessions; table + json formats.

Enables the desktop app's Sessions + Compare screens (Phase 3b).
2026-07-11 12:16:45 -07:00
iamtoruk
22c5eabd21 style(app): move daily-spend chart up to a full-width row under the stats card
The trend chart is the headline breakdown; pull it out of the rail into
a prominent full-width row (row 3), above the insight/analytics bands.
2026-07-11 12:04:00 -07:00
iamtoruk
a39b2630c5 style(app): arrange Overview body into a balanced dashboard
Re-arrange everything below the two top cards so it reads as a dashboard:
- Insight band grouping the coach pacing line + anomaly callouts.
- Analytics row: Cost-per-outcome | Routing what-if (equal 2-up).
- Height-balanced 2-column body — Left: Models table + Most expensive
  sessions; Right: Top activities + Daily spend — so the left column no
  longer dead-ends into a big empty gap.
- Consistent gaps, align-items:start, single-column reflow under 900px.
typecheck clean, 88 tests pass.
2026-07-11 12:00:33 -07:00
iamtoruk
a50389b076 style(app): Overview into divided 3-column cards + metallic grade medal
- Top card: one card, three equal columns split by dividers —
  current spend (with Saved-to-date) | daily activity | efficiency
  scorecard. Removed the duplicate one-shot/cache ratings column and the
  separate efficiency card (EfficiencyScorecard + FuelRing gain a 'bare'
  mode).
- Stats: one card, three equal divided columns — Month-to-date |
  Projected | Nearest-limit fuel ring.
- Efficiency grade is now a circular brushed-metal medal (one subtle
  gradient + inset highlight + depth shadow), tiered A/B-C/D/F, tokenized
  for light+dark — premium, not the flat AI-looking pill.
- Tightened spacing/dead space; 1-column reflow under 900px.
typecheck clean, 88 tests pass.
2026-07-11 11:47:30 -07:00
iamtoruk
4950abad71 style(app): compact the daily-activity head (no space-between gap)
'68 active days' was pushed to the far right; place it inline next to
'Daily activity' above the chart and top-align the heatmap section.
2026-07-11 11:35:46 -07:00
iamtoruk
a4259720f2 style(app): 3-section hero card + fuel ring into the stats row
- Hero card now splits into three divider-separated sections: current
  spend | daily-activity heatmap | one-shot/cache/saved ratings.
- Move the Nearest-limit fuel ring next to Month-to-date and Projected
  (fills the previously-empty third stats column). Efficiency scorecard
  takes the row above.
2026-07-11 11:34:36 -07:00
iamtoruk
9bc06e74ad style(app): merge hero + daily-activity heatmap into one split card
Per feedback, the hero (number + KPIs) and the git-style daily-activity
heatmap now share a single card, split left/right with a divider.
ActivityHeatmap gains a 'bare' mode (renders head+grid without its own
card wrapper). Efficiency scorecard + fuel ring move to a row below.
2026-07-11 11:30:15 -07:00