Commit Graph
1663 Commits
Author SHA1 Message Date
Tam Nhu Tran c572d9f860 fix(bar): read app version from Info.plist and verify bar API instead of version majors
The floating ccs-bar-latest release tag carries no version, so deriving the
app version from tag_name printed 'vccs-bar-latest' and pinned that literal
string. The version now comes from CFBundleShortVersionString in the
extracted bundle's Info.plist; an unreadable plist skips pinning and clears
any stale pin.

The post-install check compared app semver major against the CCS server
major, but the app is versioned independently of the CLI, so the mismatch
warning fired on every install. It is now a capability handshake against
GET /api/bar/summary: 200 confirms the server serves the bar API, 404 warns
the server predates CCS Bar, and anything else keeps the soft warning.
Install never hard-fails on the handshake.

Closes #1497
2026-06-10 00:11:29 -04:00
Tam Nhu Tran 9ae6f85fa7 feat(bar): add ccs bar --help with docker-style help screen
--help and -h are honored anywhere in the args so 'ccs bar install --help'
shows help instead of running the installer. Also wires the 'ccs help bar'
topic, shell-completion flag suggestions, and a more-help table entry.
2026-06-10 00:11:19 -04:00
Tam Nhu Tran 2e99b58d09 fix(bar): read codex rollout tail via fs so quota surfaces under node
defaultTailLines used Bun.spawn(['tail',...]), but the ccs server (and
'ccs bar launch') runs under node where Bun is undefined — it threw, the
per-path catch swallowed it, and Codex quota silently never appeared in real
deployments (it only worked under the bun-run dev harness). Replace with a
pure fs read: runtime- and OS-agnostic, no subprocess. Verified under node:
surfaces a live rollout's rate_limits (primary/secondary).
2026-06-09 21:11:01 -04:00
Tam Nhu Tran 2f8745bc1f fix(bar): bind 'ccs bar launch' server to IPv4 loopback
startServer was called without a host, defaulting to 'localhost' which
resolves to ::1 (IPv6) on macOS, while bar.json's baseUrl and the menu-bar
app use 127.0.0.1 — so the app could not reach its own server (connection
refused) and showed offline. Pass host 127.0.0.1 explicitly to match.
2026-06-09 20:08:07 -04:00
Tam Nhu Tran 7d3a11a452 fix(bar): resolve pre-dev review findings (security gate, honesty, correctness)
Gate /api/bar/* behind the localhost-when-auth-disabled guard (single DRY
choke point) so native quota/tier/cost can't leak on a non-loopback bind with
auth disabled; add a guard test. Delete the dishonest maxRedirections test that
asserted the opposite of the production redirect hardening. Key per-account
today-cost on the local day (matching analytics) instead of UTC. Stop the
inner 429 retry in the Claude usage fetch so the outer cache + circuit breaker
honor Retry-After. Narrow the usage-transformer map type and fix stale
doc-comments; clarify the one-alert-per-reset-window quota rule; gitignore the
local demo scaffolding.
2026-06-09 18:04:31 -04:00
Tam Nhu Tran e96967c224 feat(bar): per-window subscription quota detail + codex multi-session scan
Expose per-window detail (5h / weekly / Opus / Sonnet) on native subscription
rows instead of collapsing to a single percentage, so the bar can show the
binding window, resets, and a burn-rate pace line. Fix the Codex collector to
scan recent session rollouts newest-first for the latest non-null rate_limits
(today's exec-mode session is null) and mark the result stale with its source
time, so Codex quota appears instead of silently vanishing.
2026-06-09 14:39:41 -04:00
Tam Nhu Tran dbeb0c543a feat(bar): native Claude Code + Codex subscription quota (safe, server-side)
Surface the logged-in Claude Code and Codex subscription quota as first-class
summary rows so the existing gauge and alert engine render them with no new UI.

Claude Code: read the native token (~/.claude/.credentials.json, macOS Keychain
fallback) and reuse the existing Anthropic usage fetch+normalize via a new
token-fed entry point. The /oauth/usage endpoint is hostile to polling, so the
fetch is server-side only behind a 10-minute on-demand cache, in-flight
coalescing, Retry-After + exponential backoff with jitter, a 3-strike circuit
breaker with a 15-minute cooldown, and serve-stale-on-failure; logged-out or
unsupported subscriptions never spend a token call. Codex: zero-network read of
the latest rate_limits from local session rollouts, omitted when absent.
Native rows side-load bounded so a slow or failed fetch degrades to CLIProxy
rows, never an error.
2026-06-09 13:37:38 -04:00
Tam Nhu Tran 68f0231f48 feat(bar): add calendar month-to-date spend to analytics
monthToDate (calendar 1st-of-month to now, local) on BarAnalytics in both
compute paths, kept distinct from the rolling last30d so a fresh month resets
toward zero. Feeds the monthly-spend alert and the month-spend glance without
a rolling-window false breach.
2026-06-09 13:03:25 -04:00
Tam Nhu Tran 5f850c4899 feat(bar): honest quota state and merged multi-source analytics
Derive a tri-state quotaStatus (ok|unsupported|error) per account so a
provider with no quota API renders as 'no quota' with a healthy dot instead
of an alarming bare dash, and treat unsupported as healthy in deriveHealth.

Switch the analytics endpoint off the CLIProxy snapshot, which freezes
whenever the proxy restarts (usage is in-memory only), and onto the merged
daily/hourly usage the dashboard uses. Recent activity from Claude Code,
Codex, and Droid now shows, and a per-surface breakdown answers where usage
goes. Add lastActivityAt, daysSinceLastActivity, hasRecentData and a 30-day
series; per-account today_cost reads null (unknown) rather than a misleading 0.
2026-06-09 11:49:36 -04:00
Tam Nhu Tran 78f9fc7c0b feat(bar): harden summary against provider hangs and add analytics endpoint
Summary aggregator could block indefinitely: it ran the full system health
audit (a synchronous execSync) on every request and had no per-account or
request-level timeout. Now:
- per-account fetch is bounded; whole response is raced against a deadline
- health is derived per-account from each quota result (no blocking audit)
- stale-while-revalidate keeps the last value when a refresh is slow/fails

Adds GET /api/bar/analytics plus a pure, tested aggregator rolling up
today/7d/30d/all-time spend, a 7-day sparkline, and top models.
2026-06-08 09:31:18 -04:00
Tam Nhu Tran f0734348d0 fix(usage): compute cost fallback lazily to stop event-loop stall
normalizeCliproxyUsageHistoryDetail passed calculateHistoryDetailCost (a
~6ms model-pricing lookup) as an eager default argument to
normalizePersistedNumber, so it ran for every record even when a persisted
cost was already present. A few thousand records turned into a multi-second
synchronous stall that wedged the bar summary aggregator and the dashboard
startup prewarm. Compute the fallback only when cost is actually missing.
2026-06-08 09:30:55 -04:00
Tam Nhu Tran b9a1084bd4 fix(quota): reject tier-lock for non-managed providers
Only managed-quota providers (agy/claude/codex/gemini/ghcp) enforce tier_lock;
validate the provider against that set so locking a non-managed provider returns
400 instead of persisting a silently-unenforced config entry.
2026-06-07 16:38:18 -04:00
Tam Nhu Tran 63d10cb2d0 fix(cli): harden ccs bar install + align launch path
Resolve the app path via os.homedir() in launch to match install/uninstall;
validate the host on every redirect hop (manual follow, not blind
maxRedirections); reject zip-slip entries before extracting into ~/Applications.
2026-06-07 16:38:08 -04:00
Tam Nhu Tran cc7ac553e3 fix(usage): correct per-account cost attribution
Drop the detail.source fallback and dead numeric-key lookup in the usage
transformer so unmapped auth_index rows go to the 'unknown' bucket instead of
mis-keying cost; null out today_cost when an email cost-key is shared by more
than one account (duplicate-email providers) instead of double-displaying the
combined spend.
2026-06-07 16:37:59 -04:00
Tam Nhu Tran 205c2f3cd6 feat(cli): add ccs bar command for the macOS menu bar app
Add ccs bar (install/launch/uninstall/version) and the ~/.ccs/bar.json
discovery handshake the app reads. install resolves a floating release asset,
follows redirects, validates the download host over HTTPS, checks status,
verifies the extracted app, and runs a real version-compat handshake against
/api/overview.
2026-06-07 15:32:51 -04:00
Tam Nhu Tran 40f32ebbf0 feat(quota): add per-provider tier-lock account selection
Make tier_lock a per-provider map and honor it in findHealthyAccount and
preflightCheck for the selected provider only, so locking one provider never
disables failover for others. Add POST /api/accounts/tier-lock with tier
validation against known tiers, and serialize quota_management on config write
so the lock persists.
2026-06-07 15:32:40 -04:00
Tam Nhu Tran 6d3fde9ed3 feat(web-server): add /api/bar/summary aggregator with force-fresh
Single endpoint merging per-account quota, tier, paused, health and today cost
for the menu bar. Cached by default; ?refresh=true invalidates the quota cache
and pulls live server-side, debounced ~15s. Per-account errors degrade one row
without failing the payload; force-fresh skips paused accounts and caps fetch
concurrency.
2026-06-07 15:32:29 -04:00
Tam Nhu Tran 1867116472 feat(usage): attribute CLIProxy usage to accounts for per-account cost
Carry the CLIProxy auth_index through the usage transformer and aggregator,
build an auth_index->account map from the auth files, and wire it into the
usage syncer so persisted snapshots stamp accountId. Adds getTodayCostByAccount
and a snapshot detail reader. Backward-compatible: accountId is optional and
profile-based aggregation is unchanged.
2026-06-07 15:32:19 -04:00
Tam Nhu Tran 8282ff68a1 fix(proxy): support opt-in OpenAI reasoning shaping 2026-06-03 11:08:41 -04:00
Sergey Galuza 1fc595f10c docs(pricing): document legacy 4-7-thinking entry; cover tier metadata
Final review polish:

- Add an inline comment on the claude-opus-4-7-thinking registry entry
  explaining it is a pricing-only id kept for historical analytics data
  (no catalog model after Opus 4.7 moved to adaptive thinking levels),
  and why it carries no fast tier.
- Add a test asserting applyServiceTier preserves the serviceTiers map on
  its result, guarding against a future simplification dropping it.

Built [OnSteroids](https://onsteroids.ai)
2026-05-31 20:23:14 +02:00
Sergey Galuza 5a79b47506 fix(pricing): restore opus version order; cover 4.6/4.7 fast-tier rates
Address presto review on the fast-tier work:

- Move the claude-opus-4-8 entry after claude-opus-4-7-thinking so the
  registry keeps chronological 4.6 -> 4.7 -> 4.8 ordering (the 4.8 insert
  had split the 4-7 / 4-7-thinking pair).
- Drop the fast serviceTier from claude-opus-4-7-thinking: that id is a
  legacy pricing-only entry with no catalog model, so a fast premium on it
  is meaningless. The active 4.6-thinking variant (agy provider) keeps its
  fast tier.
- Extend the 4.7 fast-tier test with cache-rate assertions and add an
  equivalent 4.6 fast-tier test so the derived buildRates math is covered
  for every premium-tier model.

Built [OnSteroids](https://onsteroids.ai)
2026-05-31 18:52:54 +02:00
Sergey Galuza e8057a7073 refactor(pricing): share Opus fast-tier rate constants
Hoist the fast-mode rate sets into OPUS_46_47_FAST_RATES and
OPUS_48_FAST_RATES module constants (built via buildRates) so the
registry entries reference shared values instead of repeating literal
buildRates(...) calls. Also wires the fast tier onto the -thinking
aliases (claude-opus-4-6-thinking / -4-7-thinking) so they bill at the
same premium as their base ids.

Built [OnSteroids](https://onsteroids.ai)
2026-05-31 18:16:23 +02:00
Sergey Galuza 254fc88f71 refactor(pricing): derive fast-tier cache rates via buildRates helper
Address review feedback on the per-service-tier pricing:

- Extract `buildRates(input, output)` plus named CACHE_5M_WRITE_MULTIPLIER
  / CACHE_READ_MULTIPLIER constants so fast-tier cache rates are derived
  from Anthropic's documented multipliers instead of hand-computed numbers.
  This removes the inconsistency where Opus 4.6 fast-tier lacked the
  explanatory inline comments that 4.7/4.8 carried (presto suggestion #3).
- Document in `applyServiceTier` that no production caller passes
  `serviceTier` yet (Anthropic's service_tier is not captured on
  CliproxyRequestDetail), so fast-mode usage is currently billed at the
  standard rate until the usage pipeline records the tier.
- Add a combined date-suffix + fast-tier lookup test to prove the two
  resolution stages compose.

Built [OnSteroids](https://onsteroids.ai)
2026-05-31 10:34:50 +02:00
Sergey Galuza c74ad22bd4 Merge remote-tracking branch 'upstream/dev' into feat/claude-opus-4-8 2026-05-30 22:31:55 +02:00
Sergey Galuza 878775f5b6 feat(pricing): support per-service-tier rates; wire Opus fast mode
Extend `ModelPricing` with an optional `serviceTiers` map keyed by
Anthropic's `service_tier` request parameter. `getModelPricing(model,
{ serviceTier })` returns the matching tier rates when present and
transparently falls through to base rates otherwise — existing call
sites keep current behavior.

Registry entries added (per Anthropic Fast mode pricing docs):
- claude-opus-4-8 fast: $10/$50 input/output (2x premium)
- claude-opus-4-7 fast: $30/$150 (6x premium)
- claude-opus-4-6 fast: $30/$150 (6x premium)

Cache rates derived from the documented Prompt caching multipliers
(1.25x for 5-min cache write, 0.1x for cache read).

Note: tier tracking through CliproxyRequestDetail is not wired yet —
that's a follow-up so usage transformers can pass `serviceTier` when
Anthropic returns it on the response. Schema is in place; integration
can land independently.

Also adds a defensive `claude-opus-4-8-20260530` pricing test to exercise
`stripDateSuffix` even though Anthropic no longer issues date-stamped IDs
for the 4.6+ generation (addresses presto-review suggestion #1).

Built [OnSteroids](https://onsteroids.ai)
2026-05-30 22:17:21 +02:00
Tam Nhu Tran ced9317565 Merge remote-tracking branch 'origin/dev' into codex/fix-cliproxy-v3-snapshot-migration-issue
# Conflicts:
#	src/web-server/usage/cliproxy-usage-transformer.ts
#	tests/unit/web-server/cliproxy-usage-transformer.test.ts
2026-05-30 16:13:49 -04:00
Kai (Tam Nhu) TranandGitHub dce968fdf7 Merge pull request #1425 from kaitranntt/codex/fix-unvalidated-codex-quota-labels
fix(cliproxy): sanitize Codex quota labels
2026-05-30 16:12:22 -04:00
Kai (Tam Nhu) TranandGitHub e7db1d65f5 Merge pull request #1452 from kaitranntt/codex/propose-fix-for-codex-target-rejection
Mark Codex as a persisted target and align UI/validation
2026-05-30 16:12:03 -04:00
Kai (Tam Nhu) TranandGitHub 429fcc0d51 Merge pull request #1454 from kaitranntt/codex/fix-email-fallback-parsing-issue
fix(cliproxy): infer emails from alternate token prefixes
2026-05-30 16:11:54 -04:00
Kai (Tam Nhu) TranandGitHub b1c8fbf701 Merge pull request #1417 from kaitranntt/codex/propose-fix-for-proxy-validation-issue
fix: validate browser flags before proxy side effects
2026-05-30 16:10:29 -04:00
Kai (Tam Nhu) TranandGitHub d028329d2c Merge pull request #1426 from kaitranntt/codex/fix-cliproxy-usage-cache-vulnerability
fix(cliproxy): avoid persisting account identifiers and harden usage cache permissions
2026-05-30 16:08:26 -04:00
Kai (Tam Nhu) TranandGitHub bbb717ff2f Merge pull request #1441 from kaitranntt/codex/propose-fix-for-provider-alias-crash
fix: harden provider alias normalization
2026-05-30 16:07:28 -04:00
Kai (Tam Nhu) TranandGitHub 1d1b9fbe6d Merge pull request #1443 from kaitranntt/codex/fix-ccsxp-codex-config-check
fix(codex): gate ccsxp config overrides
2026-05-30 16:07:21 -04:00
Kai (Tam Nhu) TranandGitHub 41e550e92f Merge pull request #1428 from kaitranntt/codex/propose-fix-for-symlinked-cleanup-issue
fix: reject symlinked cleanup directories
2026-05-30 16:05:05 -04:00
Kai (Tam Nhu) TranandGitHub 5ac0e808b4 Merge pull request #1432 from kaitranntt/codex/fix-ccsxp-argument-parsing-bug
fix: stop ccsxp model alias parsing at option terminator
2026-05-30 16:01:55 -04:00
Kai (Tam Nhu) TranandGitHub ee50c0c59a Merge pull request #1422 from kaitranntt/codex/fix-codex-usage-cache-permissions
fix: restrict Codex usage cache permissions
2026-05-30 16:01:00 -04:00
Kai (Tam Nhu) TranandGitHub a6ea3f2d19 Merge pull request #1450 from kaitranntt/codex/fix-hidden-stale-default-model-in-live-catalogs
fix: keep live catalog defaults visible
2026-05-30 15:59:59 -04:00
Kai (Tam Nhu) TranandGitHub b2ee234430 Merge pull request #1451 from kaitranntt/codex/propose-fix-for-codex-fallback-issue
fix(cliproxy): prefer explicit Codex free fallbacks
2026-05-30 15:56:02 -04:00
Kai (Tam Nhu) TranandGitHub 4ab920c489 Merge pull request #1438 from kaitranntt/codex/fix-invalid-default-claude-image-analysis-model
fix: correct claude image analysis default model
2026-05-30 15:55:41 -04:00
Kai (Tam Nhu) TranandGitHub 57867ff8f0 Merge pull request #1445 from kaitranntt/codex/propose-fix-for-opus-4.7-test-coverage
fix(analytics): price Claude Opus 4.7 thinking
2026-05-30 15:53:40 -04:00
Kai (Tam Nhu) TranandGitHub 484f0a0427 Merge pull request #1427 from kaitranntt/codex/propose-fix-for-local-runtime-probe-vulnerability
fix: restrict local runtime readiness probes
2026-05-30 15:51:43 -04:00
Kai (Tam Nhu) TranandGitHub a9f5f26807 Merge pull request #1446 from kaitranntt/codex/fix-quota-cooldown-auto-resume-logic
fix(cliproxy): preserve manual quota pauses
2026-05-30 15:51:42 -04:00
Tam Nhu Tran bcc68992fa fix(cliproxy): ignore stale executor exit code 2026-05-30 15:48:18 -04:00
Kai (Tam Nhu) TranandGitHub bdea434339 Merge pull request #1429 from kaitranntt/codex/fix-vulnerability-in-self-signed-routing
fix: guard self-signed routing request setup
2026-05-30 15:46:53 -04:00
Kai (Tam Nhu) TranandGitHub 5151d6d24e Merge pull request #1433 from kaitranntt/codex/fix-issue-with-profile-query-handling
fix: validate usage profile query type
2026-05-30 15:46:47 -04:00
Kai (Tam Nhu) TranandGitHub 93756489a5 Merge pull request #1434 from kaitranntt/codex/fix-unbounded-recursion-in-receipt-generation
fix(persist): bound Codex translator receipt scan
2026-05-30 15:46:29 -04:00
Kai (Tam Nhu) TranandGitHub 229d5456c2 Merge pull request #1436 from kaitranntt/codex/fix-null-retryablecheck-crash
fix: tolerate null retryable check
2026-05-30 15:46:21 -04:00
Kai (Tam Nhu) TranandGitHub 5619f32651 Merge pull request #1447 from kaitranntt/codex/fix-pid-only-proxy-cleanup-issue
fix(proxy): load pid-only profile daemon state
2026-05-30 15:45:50 -04:00
Kai (Tam Nhu) TranandGitHub 1333407f54 Merge pull request #1456 from kaitranntt/codex/fix-broken-symlink-handling-in-plugin-setup
fix(management): skip broken shared plugin entries
2026-05-30 15:45:37 -04:00
Tam Nhu Tran 79379a25fe style: format email fallback parsing changes 2026-05-30 15:44:45 -04:00