94 Commits

Author SHA1 Message Date
Akshay Prabhu 05a7a449f0 Add OpenCode Go usage API support (#2879)
* Add OpenCode Go usage API support

* Preserve OpenCode Go Zen balance with API usage

* Update OpenCode Go capability gate

* Format OpenCode Go API overlay
2026-08-19 08:51:02 -07:00
Yuxin Qiao 5436112ea7 Document custom-pricing overlays and Usage & Spend (#3033)
* Document custom-pricing overlays and the current Usage & Spend surface.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Clarify custom-pricing overlay scope and cost JSON shapes.

The overlay only affects native Codex scans, and CLI cost JSON is not the Usage & Spend export schema.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Document Linux custom-pricing path and bare-key precedence.

The overlay lives in Application Support on every platform, and a bare model key wins over provider/model when both exist.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-18 08:15:39 -07:00
Elijah Friedman c20c3a49e1 feat: add TOON usage output 2026-08-17 19:50:08 -04:00
Peter Steinberger 199b96b393 fix: remove Claude statusLine feed (#3006)
Reverts the unreleased statusLine integration from #2769 while retaining the independent subprocess timing stabilizations.
2026-08-17 01:02:18 -07:00
luisgonzaleznf 09d2d0140d Claude: opt-in statusLine usage feed (#2769)
* Add the opt-in Claude statusLine usage feed

Implements the owner ruling on #2733: Claude Code publishes rate_limits to
whatever statusLine command the user configured, and reading what it publishes
does not cross the credential-ownership boundary the Keychain rules protect.

Off by default. When enabled, a .statusline step joins the app Auto order
behind .oauth and ahead of .cli, so it fills the gap while the polled sources
cool down and never pre-empts a successful OAuth read. When disabled the plan
is byte-identical to today: the step is inserted, not present-but-unavailable,
because planner order is asserted directly by tests and shown in debug output.

The source is never user-selectable. Pinning a feed that goes silent whenever
the user is not running Claude Code would strand the card, so it is excluded
from the picker and persists as Auto if it ever reaches settings.

Fail soft throughout: bad JSON, an unknown envelope version, wrong types, an
out-of-range percentage or a drifted schema all read as absence, which leaves
the polled sources in place rather than surfacing an error. The status line is
the user's own configuration and Claude Code owns the payload schema.

Observations are matched to the reporting profile by CLAUDE_CONFIG_DIR and
bounded to 15 minutes, so one account's numbers cannot render under another's
card and a stale live value cannot outrank a fresh poll. The snapshot asserts
no identity or plan, and the card labels the numbers as coming from the user's
own statusLine config.

* Document the statusLine feed and its drop-file contract

Describes the envelope, a minimal shim, and the profile/freshness rules, so the
feed is usable by hand while the managed-install question is open.

* Make the statusLine feed toggle actually reachable

The opt-in flag was read by the planner but nothing ever populated it: there
was no SettingsStore property, no defaults key, and no UI control, so it was
false in every build and the feed could not be switched on at all.

Wires it end to end — stored default (off), settings snapshot, menu
observation, and a Claude provider toggle — and adds a test that asserts the
user-facing switch reaches the snapshot field the planner reads.

The existing planner tests could not catch this: they construct
ClaudeSourcePlanningInput directly, so they pass whether or not anything
carries the user's choice into it. Removing the snapshot line again fails the
new test with the exact symptom that shipped.

* Require a capture time on statusLine observations

The parser defaulted a missing capturedAt to the parse time, so a drop file
that had sat on disk for hours read as current and the staleness bound stopped
protecting anything — a dead session could outrank a live poll indefinitely.

An observation that cannot be aged is now absence. The previous test asserted
the fallback as intended behaviour, which is why the suite stayed green; it now
asserts the drop instead.

* Cap how far ahead a statusLine capture time may sit

Future timestamps were accepted without bound to tolerate clock skew, so an
observation dated arbitrarily far ahead stayed fresh forever — the same defect
as a missing capture time, in the opposite direction. Skew is now tolerated up
to five minutes and rejected beyond it.

The previous test asserted the unbounded behaviour as intended, so the suite
stayed green; it now covers both the tolerated and the rejected case.

* Compose the statusLine feed over the last poll instead of replacing it

Addresses both P1 findings on the draft, now that #2675 has landed.

The feed carries only the 5h/7d windows. Publishing its result whole blanked
identity, plan, model-scoped weekly, Daily Routines, extra usage and cost —
the opposite of the "composes with, never replaces" constraint in the owner
ruling. Its windows are now merged over the last polled Claude snapshot, and a
window the observation omits means "no update" rather than "cleared".

Composition also carries the account guard the feed cannot supply itself.
Matching CLAUDE_CONFIG_DIR cannot distinguish an account switch within one
profile, so an observation is discarded outright when the active account has
changed since the snapshot it would compose over. Publishing it there would
render one account's windows beneath another account's identity.

Follows the existing shape of this apply path, which already reconciles
results against previous state for Codex, CommandCode, DeepSeek and reset
backfill. The helper lives in its own file and the call site replaces an
existing binding, so the refresh function stays within its length budget.

The card note keeps precedence over the dataConfidence note added by #2675: a
composed snapshot inherits its confidence from the previous poll, so a prior
CLI scrape would otherwise label live statusLine windows as CLI-sourced.

* Address the three Codex findings on the statusLine feed

Persist the opt-in toggle. The setter only updated the in-memory defaults
state, so the feed silently switched itself off on the next launch. It now
writes the key and notifies the background-work path, matching the adjacent
provider toggles.

Stop promoting a weekly-only observation into the session lane. This snapshot
is composed over a previous one where primary is the session row, so a
promoted 7-day figure rendered as the 5-hour limit while the real weekly row
survived beside it. A weekly-only payload is now absence rather than a
lane-shifted guess.

Verify ownership of the rows being composed over. The active-account
observation only proves the account held still during a fetch; if the user
switches accounts and the next refresh is served by the statusLine file,
nothing in that fetch re-read the account, so stability alone would let the
new account's windows sit beneath the old account's identity. The account
behind each polled snapshot is now recorded and must still be active for the
feed to compose over it, and a snapshot the feed itself produced never becomes
that evidence.

* Keep the statusLine opt-in through launch

The launch reset that clears Claude web extras outside CLI mode was also clearing
the statusLine feed. The planner emits the feed's step only under `.auto`, which is
exactly the branch that reset covers, so an enabled user lost the opt-in on every
launch and the feature was unreachable after a restart.

The reset is CLI-scoped by design; the statusLine line never belonged in it.

No test caught this because the reset lives in the non-test branch of an
`isRunningTests` gate, so the suite never executed it. Adding
`writesLaunchResetsToRawState` — mirroring the existing
`performInitialProviderDetection` seam — lets a test take the production path.
Verified by reintroducing the defect and watching the new test fail on both
assertions before it passed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* Restore the provider architecture gatekeeper on this branch

`cross provider case clusters are derived or specifically justified` passes on
main and failed on this branch. The allowlist pins each guarded construct to an
exact line with a text anchor, and earlier commits here inserted lines into
UsageStore+Refresh.swift, UsageStore.swift and MenuCardView+ModelHelpers.swift,
so 44 entries drifted off their anchors and every orphaned entry then cascaded
into an unjustified-construct failure.

- Recompute the 44 drifted line numbers against their anchors.
- Justify the two Claude constructs in the composition file, which were added
  with no marker at all. The first reads better hoisted into a named local than
  as a comment buried in an argument list.
- Update the MenuCardView cluster fingerprint: the statusLine note sits between
  the .kiro and .kilo checks, so the gatekeeper now sees one three-provider
  cluster where the entry expected two. The maintainer's reason text still
  describes it accurately and is left alone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* Keep the Claude chain moving when a feed observation cannot be attributed

Composition returned nil when a statusLine observation could not be attributed to
the stored rows. By then the fetch pipeline had already accepted the statusLine
result, so nothing fell through to the CLI probe: the refresh published nothing
and the card kept whatever it was showing.

Three things combined to make that permanent rather than transient:

- Feed-stored snapshots recorded no owner at all, so the first feed-only publish
  created rows that no later feed refresh could ever attribute. The account UUID
  is read from the environment, not from the observation, so recording it for
  feed snapshots is evidence about when the rows were stored — exactly what the
  next composition needs to ask about.
- The record lived only in memory while the snapshots it describes are persisted,
  so every relaunch began with an unknown owner against restored rows.
- Rejection was a decision about whether to publish rather than about which rows
  to trust.

Ownership is now three-state. "Cannot tell" is not "belongs to someone else":
only the latter justifies discarding rows the user can currently see, so an
unreadable account republishes the previous snapshot rather than blanking
identity, plan and extra rows on a guess.

This does not gate the step at plan time as the review suggested, which would
mean plumbing composability from UsageStore through the settings snapshot into
the Core planner. The stall it protects against no longer exists.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* Make statusLine ownership a condition of the source, not a decision after it

An unowned observation was being resolved after the fetch had already committed
to it, where every remaining option was wrong: publish rows that cannot be
attributed, publish nothing and stall the chain, or blank verified rows on a
guess. Ownership is now part of whether the step is offered at all. When the
stored rows are not provably owned by the active account the source is not
planned, OAuth -> CLI -> web runs as it did before the feed existed, and a poll
that carries its own identity re-establishes ownership on its own.

Two findings this closes:

- A feed observation no longer records who owns the rows it produced. The account
  UUID is read from the environment, so it is evidence about when the rows were
  stored, not about whose usage they count. The drop file is scoped to the
  profile rather than the account and its freshness window is minutes wide, so a
  file written by the previous account's session was being stamped as the new
  account's and composed beneath its identity on the next refresh.
- Composition reports whether the published rows came from the fetched result,
  and the source label only moves when they did. A discarded observation
  republishes the previous rows, and claiming its label made the card attribute
  an old OAuth or CLI reading to the user's status line.

Worth recording for whoever owns this next: the payload carries no account
identity of any kind, and its drop file is shared by every account on a profile.
The feed cannot attribute itself. It can only ever supplement rows whose owner is
already established, which is what the planning gate now enforces structurally.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* feat: add Keychain-free Claude statusLine feed

Co-authored-by: Luis Gonzalez <luis@getduckbill.com>

* test: stabilize subprocess timing under load

* fix: import CoreFoundation for Linux statusLine build

* test: register statusLine localization fallbacks

* style: wrap statusLine localization fallback

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-16 22:55:00 -07:00
Peter Steinberger 804838dd0c Merge pull request #2854 from Yuxin-Qiao/codex/feat-cli-session-grouping
feat(cli): add Codex session cost grouping
2026-08-16 11:34:32 -07:00
Peter Urda d55a1b7fc4 fix: follow app privacy setting on serve dashboard
The serve dashboard ignored the app's "Hide personal information"
toggle and always served full account emails unless --identity was
passed. Resolve the identity mode per request when the flag is
absent, so the toggle applies without a serve restart, and fold the
resolved mode into the response cache key so a body cached before a
toggle cannot be replayed after it. An explicit --identity still
wins. codexbar dashboard keeps its full default.
2026-08-15 20:38:26 -07:00
Yuxin Qiao 7a851ad7f8 feat(cli): add Codex session cost grouping 2026-08-11 11:59:37 +08:00
Peter Steinberger 4a83b87aff Fix Claude CLI fallback availability 2026-08-09 12:05:20 -07:00
Peter Steinberger 338820e239 feat(cli): default dashboard identity to full emails (#2748)
Redaction was the dashboard-v1 default at every layer; the --identity
flag already existed on both the one-shot command and serve. Flip the
default to full identity and keep --identity redacted as the opt-in
privacy setting for snapshots that cross untrusted networks. The web
UI stops re-redacting rows before persisting them to localStorage so
cached paints match what the server serves in either mode.
2026-08-07 17:13:16 -07:00
Peter Steinberger 276e5a50bc feat(cli): paint the serve dashboard instantly and stream data in (#2746)
Three layers, one goal: never make the browser wait on a snapshot build
(measured 46.5s cold vs 22ms warm on the portal host).

- Stale-while-revalidate: expired cache entries within staleTTL answer
  immediately from the last-good response while a coalesced background
  rebuild commits fresh data. Applies to /usage, /cost, and the
  dashboard snapshot; failure-fallback rules are unchanged.
- Snapshot query params (schema stays v1): ?provider=<id> builds and
  caches one provider row independently; ?detail=shell returns
  config-only rows with no provider fetches or cost scans.
- Web UI: renders the last snapshot from localStorage instantly on
  revisit, paints skeleton cards from the shell on cold start, fills
  each card as its provider resolves, then hands off to normal polling.
2026-08-07 16:37:33 -07:00
Peter Steinberger aee9e56818 feat(cli): add --output <path> to the dashboard snapshot command (#2719)
Static-webroot publishers currently shell-wrap the one-shot command
(codexbar dashboard > tmp && install tmp target) to avoid readers seeing
a partial document. --output writes the snapshot atomically instead:
staged temp file in the destination directory, fsync, rename(2) over the
target, 0644. Stdout stays untouched when the flag is absent and silent
on success when writing to a file. Empty paths are an args error and a
missing parent directory fails with a clear message; directories are
deliberately not created.
2026-08-06 13:56:27 -07:00
Peter Steinberger 81d5b2fdc8 fix(cli): deliver late serve results instead of discarding them (#2717)
When a serve operation outlived its request deadline, the coordinator
marked the slot timed out and threw away the eventually-produced value:
it never reached the accept commit (response cache) and the queued
same-config successor restarted the source from zero. On machines where
the dashboard snapshot build outlasts --request-timeout, GET
/dashboard/v1/snapshot 504ed forever while each retry burned another
full cost-history scan.

Timed-out sources now still commit through accept and hand the fresh
result to a same-fingerprint successor without rerunning the source;
changed-config successors promote as before. The web UI shows a
friendlier 504 message noting it retries automatically.
2026-08-06 12:32:05 -07:00
Peter Steinberger e795d349cb feat(cli): add built-in web dashboard to codexbar serve (#2715)
GET / now serves a self-contained HTML page that polls
/dashboard/v1/snapshot and renders provider cards with usage windows,
credits, and cost. The static UI stays unauthenticated (it carries no
account data); tokens are entered in-browser, kept in localStorage, and
sent as a bearer header. No visibility gating on polling so embedded
panes that report document.hidden permanently still refresh.
2026-08-06 11:37:24 -07:00
Peter Steinberger 8314a74e86 refactor: migrate provider payloads onto declarative details model (#2658)
* refactor: migrate provider details batch one

* refactor: migrate provider details batch two

* refactor: migrate provider details batch three

* fix: preserve provider detail rendering parity

* fix: migrate Copilot credits into provider details

* fix: pin Poe details to UTC

Poe timestamps are UTC and the daily buckets already used it, but the
recent-activity labels and Today bucket used the local zone in both the
Swift and JS paths, flaking the golden on non-Pacific runners. Golden
proven invariant under TZ=UTC, America/Los_Angeles, Asia/Tokyo.

* fix: normalize OpenRouter reset detail

* test: pin Poe menu fixture to UTC

* fix: preserve OpenRouter key details

---------

Co-authored-by: Peter Steinberger <steipete@mac-studio-sf2.local>
2026-08-04 22:19:31 -07:00
Nick Gu 8c37c20a43 Expose Codex scan completeness in cost JSON (#2520)
* Expose provider-native cost scans

* feat(cli): expose Codex cost scan completeness

Co-authored-by: NickGuAI <yu.gu.columbia@gmail.com>

---------

Co-authored-by: Peter Steinberger <steipete@mac-studio-sf2.local>
2026-08-04 17:18:21 -07:00
Umut Keltek e12a824fdb Add one-shot dashboard snapshot command (#2499)
* Add one-shot dashboard snapshot command

* Fix dashboard pricing refresh policy

* Honor Cursor source policy in dashboard

* test: dedupe cliExecutableURL helper after branch update

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <steipete@mac-studio-sf2.local>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 10:02:47 -07:00
Abhinav Singh f13ef61c49 Add codexbar hooks watch so hooks fire without the macOS app (#2536)
* feat(cli): add `hooks watch` so hooks fire without the macOS app

`HookRunner.dispatch` was only ever called from `Sources/CodexBar/UsageStore+Hooks.swift`,
so hook rules could be configured on Linux/headless but could never fire. `serve`'s
refresh interval is a cache TTL, not a poller, and `hooks test` only fires a synthetic
event on demand.

Add `HookTransitionDetector` to CodexBarCore: platform-neutral, side-effect free, and
built on the primitives Core already ships (`QuotaLowHookThreshold.crossedRules`,
`QuotaWarningWindow`, `HookRule`, `HookRateLimiter`). It preserves the app's semantics:
the first sample of a lane establishes a baseline without firing, `unknown`/`maintenance`
never flip provider status, a rule change clears baselines, and disappearing lanes are
pruned. All events are edge-triggered, which is what `HookRunner` already assumes when it
declines to rate-limit quota events.

Add `codexbar hooks watch` to drive it: `--interval` (default 300s, minimum 60s, rejected
rather than clamped), `--provider`, `--once`, and JSON output. Runs read-only like
`guard`, stops on SIGINT/SIGTERM/SIGHUP, and reports refresh failures with a coarse
category so raw provider errors are never forwarded.

The macOS app is intentionally untouched.

* fix: address review — filtered quota_low dispatch, session-only reached, interruptible sleep

Three bugs from automated PR review:

- quota_low dispatched against the full hooks config, so HookRunner re-evaluated
  every enabled rule's `matches()` against the current reading, re-firing any rule
  whose threshold sat below the one that actually crossed. `HookDispatch` now
  carries the pre-computed crossed subset for quota_low, mirroring the app's
  `HooksConfig(events: crossed)` pattern; other events still use the full config
  since `matches()` doesn't threshold-recheck them.
- quota_reached fired for every lane, including weekly. Documented and the app's
  own call site (`emitQuotaReachedHook(sessionWindow:)`) restrict it to session;
  gated accordingly.
- SIGINT/SIGTERM/SIGHUP during the poll sleep only flipped a flag; the running
  Task.sleep wasn't cancelled, so `hooks watch` could appear hung for up to the
  full interval. Replaced with `sleepInterruptibly`, a 200ms-tick loop that checks
  the stop flag between ticks.

Each fix has a regression test proving the bug and the fix.

* fix: validate watch arguments before loading configuration

`runHooksWatch` called `loadConfig` before decoding `--interval` and `--provider`.
`loadConfig` exits the process on a malformed config, so a broken config file
masked the documented argument errors: `hooks watch --interval 5` reported a
config decode failure instead of the interval floor error.

Reordering alone would leave the coupling in place, so the decoders no longer take
a config at all. `decodeHooksWatchProviderNames` validates explicit `--provider`
names and returns nil to mean "fall back to the enabled set"; the new
`hooksWatchProviders` resolves that fallback once the config is available. Both
command-only decoders now run before `loadConfig`, which makes the ordering defect
structurally impossible rather than merely corrected.

Verified against a malformed config: `--interval 5`, `--interval abc`, and an
unknown provider all report their own errors, while valid arguments still surface
the config decode error.

* fix(cli): require continuous hooks watch

---------

Co-authored-by: Peter Steinberger <steipete@mac-studio-sf2.local>
2026-08-02 17:08:33 -07:00
Zihaoqi 216d9973d2 Refine Claude credits display 2026-07-24 17:50:01 -05:00
Peter Steinberger 83f5a7e27d Merge pull request #2280 from possibilities/feature/claude-swap-single-account-option
Allow single-account claude-swap cards
2026-07-18 20:45:25 +01:00
Peter Steinberger b30c1457b9 docs: clarify single-account swap cards 2026-07-18 19:13:06 +01:00
Peter Steinberger b6366f3966 Merge remote-tracking branch 'origin/main' into feat/cli-cookie-refresh 2026-07-18 00:11:34 +01:00
Peter Steinberger eb26164e0c Merge pull request #2238 from billerickson/codex/deepinfra-provider
Add DeepInfra usage provider
2026-07-18 00:03:57 +01:00
Peter Steinberger fb44dd6720 fix: make cookie refresh non-destructive 2026-07-17 23:34:49 +01:00
Peter Steinberger b9089b9a98 fix: preserve scoped cookie caches during refresh 2026-07-17 23:16:53 +01:00
Peter Steinberger 991485ead0 Merge remote-tracking branch 'origin/main' into feat/cli-cookie-refresh
# Conflicts:
#	Sources/CodexBarCLI/CLIHelp.swift
#	docs/cli.md
2026-07-17 23:09:45 +01:00
Peter Steinberger 5ac0d7fb7f Merge remote-tracking branch 'origin/main' into codex/deepinfra-provider
# Conflicts:
#	Sources/CodexBar/MenuCardView.swift
#	Sources/CodexBar/MenuDescriptor.swift
#	Sources/CodexBar/SettingsStore+MenuPreferences.swift
#	Sources/CodexBar/UsageStore.swift
#	Sources/CodexBarCore/Config/ProviderConfigEnvironment.swift
#	Sources/CodexBarCore/Generated/CodexParserHash.generated.swift
#	Sources/CodexBarCore/Vendored/CostUsage/CostUsageScanner.swift
#	docs/cli.md
2026-07-17 20:11:47 +01:00
Peter Steinberger d8c282bbba fix: harden guard automation contract 2026-07-17 20:11:03 +01:00
Peter Steinberger aa7b3224c8 fix: gate CLI cookie refresh
Co-authored-by: PINKIIILQWQ <pink@pinkqaq.cn>
2026-07-17 20:06:47 +01:00
Peter Steinberger 3eac7e2fea Merge remote-tracking branch 'origin/main' into feat/cursor-token-cost
# Conflicts:
#	Sources/CodexBar/UsageStore+TokenCost.swift
#	Sources/CodexBar/UsageStore.swift
#	Sources/CodexBarCore/CostUsageFetcher.swift
#	Tests/CodexBarTests/CostUsageTokenSnapshotDaySelectionTests.swift
2026-07-17 08:58:25 +01:00
Peter Steinberger 0c67056db7 Merge pull request #2254 from steipete/codex/provider-roster-hygiene
Remove Kimi K2 and CrossModel provider relays
2026-07-16 23:48:58 -07:00
Peter Steinberger 54cfd1a3f5 chore: retire unverified provider relays 2026-07-17 06:19:00 +01:00
Peter Steinberger 14fc1f32e0 Merge remote-tracking branch 'origin/main' into feature/external-event-hooks
# Conflicts:
#	Sources/CodexBar/Resources/de.lproj/Localizable.strings
#	Sources/CodexBar/Resources/es.lproj/Localizable.strings
#	Sources/CodexBar/Resources/fr.lproj/Localizable.strings
#	Sources/CodexBar/Resources/ja.lproj/Localizable.strings
#	Sources/CodexBar/Resources/ko.lproj/Localizable.strings
#	Sources/CodexBar/Resources/nl.lproj/Localizable.strings
#	Sources/CodexBar/Resources/pt-BR.lproj/Localizable.strings
#	Sources/CodexBar/Resources/ru.lproj/Localizable.strings
#	Sources/CodexBar/Resources/sv.lproj/Localizable.strings
#	Sources/CodexBar/Resources/uk.lproj/Localizable.strings
#	Sources/CodexBar/Resources/vi.lproj/Localizable.strings
#	Sources/CodexBar/Resources/zh-Hans.lproj/Localizable.strings
#	Sources/CodexBar/Resources/zh-Hant.lproj/Localizable.strings
2026-07-17 04:47:47 +01:00
Peter Steinberger 2a421d6fe2 Merge remote-tracking branch 'origin/main' into feat/cursor-token-cost 2026-07-17 04:30:50 +01:00
Peter Steinberger 413e91fdc9 Merge remote-tracking branch 'origin/main' into feat/cursor-token-cost
# Conflicts:
#	Sources/CodexBar/MenuCardView+Costs.swift
#	Sources/CodexBar/MenuCardView.swift
#	Sources/CodexBar/UsageStore.swift
#	Sources/CodexBarCLI/CLICostCommand.swift
#	Sources/CodexBarCore/Providers/Cursor/CursorStatusProbe.swift
#	Tests/CodexBarTests/CursorStatusProbeTests.swift
2026-07-17 03:13:56 +01:00
Peter Steinberger ef5145e4d4 Merge remote-tracking branch 'origin/main' into feat/dashboard-snapshot-token 2026-07-17 02:19:34 +01:00
Peter Steinberger 766c8ad77c fix: harden dashboard snapshot serving 2026-07-17 02:01:36 +01:00
Peter Steinberger 875fe8f0d7 fix: bound and stabilize hook execution 2026-07-17 01:53:04 +01:00
Peter Steinberger 036823a094 docs: use dashboard token placeholders 2026-07-17 01:33:14 +01:00
Peter Steinberger 43cbcbc012 fix: harden external event hooks 2026-07-17 01:32:34 +01:00
Bill Erickson c83073139e Add DeepInfra usage provider 2026-07-16 16:33:14 -05:00
Jetha Chan 2bcbf65ef8 docs: document dashboard snapshot endpoint and threat model
docs/cli.md gains the new serve flags and endpoint; docs/dashboard-api.md
describes the bearer-token auth, the plain-HTTP threat model (the token
crosses the network in cleartext on every request), the loopback default,
the --allow-plain-http acceptance, a Caddy reverse-proxy recipe for TLS,
token hygiene (openssl rand -hex 32, prefer CODEXBAR_DASHBOARD_TOKEN,
rotate by restart), and the snapshot payload contract.

Both files state plainly that on a non-loopback bind the token gates ALL
data routes (/usage, /cost, /dashboard/v1/snapshot) and that /health is
always open.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 00:01:18 +09:00
Mike Bannister fa2e211001 feat(cli): render claude-swap account cards 2026-07-16 10:08:27 -04:00
Ethan Clinick fb5c0b47e0 Merge remote-tracking branch 'origin/main' into feat/cursor-token-cost
# Conflicts:
#	Sources/CodexBarCLI/CLIServeCommand.swift
#	Sources/CodexBarCore/CostUsageFetcher.swift
2026-07-10 16:53:38 -07:00
Donnie Fiander 8155f18732 Add CLI cards view (#1925)
Adds responsive codexbar cards and brief views with bounded terminal rendering, correct reset semantics, partial-success handling, and focused regression coverage.

Co-authored-by: Donnie Fiander <44792682+DonnieFi@users.noreply.github.com>
2026-07-06 23:27:23 +01:00
Ethan Clinick 613342a2f7 docs: describe Cursor dashboard cost source and CLI output 2026-07-06 11:21:25 -07:00
Peter Steinberger 1e49619e73 feat: add Codex project cost rollups (#1884)
Group local Codex usage and costs by canonical project and worktree source across menus, CLI text, and JSON output. Preserve the existing cache artifact while migrating project metadata safely, and avoid rendering legacy cache rows before migration.

Co-authored-by: Clemens Peters <c.peters@conventic.com>
2026-07-04 07:33:41 -04:00
Kentoku Matsunami 5bfd1d1474 feat(cli): show pace in text and JSON output (#1722)
Add session pace to text output, expose derived pace data in JSON, and respect the configured weekly work-day baseline.

Co-authored-by: Kentoku Matsunami <kentoku.matsunami@bizreach.co.jp>
2026-06-23 20:28:36 +01:00
Ellis Nieuwpoort 8c83f054ff serve: report build version on /health (#1703)
* serve: report build version on /health for stale-binary detection

Expose the running build version in the `codexbar serve` /health
response so polling clients (e.g. showy-quota, glean) can compare it
against `codexbar --version` and recycle a serve process still running
an older binary after an app update. Omitted when unresolvable.

Add CLIServeRouterTests coverage and document the field in docs/cli.md.

* serve: capture /health version at startup, not lazily

Resolve the running build version once when `serve` starts (via a
ServeRuntime context) instead of a lazily-initialized static let. A
static let resolves on the first /health request, which can land after
an in-place update replaced the on-disk binary — making a stale serve
report the newly installed version and defeating the client
stale-process detection this field exists for.

Addresses Codex review feedback on PR #1703.

* chore: polish health version reporting

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-06-21 22:19:50 -07:00
Peter Steinberger 7ad7bdadd3 Fix Linux OpenCode Go and Command Code usage (#1660)
* fix: support Linux provider usage

* fix: stage SQLite header for musl builds

* fix: isolate musl SQLite discovery
2026-06-19 22:23:36 +01:00