Commit Graph
1196 Commits
Author SHA1 Message Date
Tam Nhu Tran d700030018 test(cliproxy): cover concurrent state writers 2026-07-29 12:52:03 -04:00
Kenneth Wong ee90dd2640 feat: support claude opus 5 2026-07-27 15:07:26 +08:00
Kai (Tam Nhu) Tran b09f8191f3 Merge pull request #1669 from kaitranntt/kai/docs/1666-pruning-freshness
docs: prune stale guides and enforce freshness
2026-07-26 22:09:35 -04:00
Tam Nhu Tran 8dc6b817b2 test(docs): enforce documentation freshness 2026-07-26 09:36:01 -04:00
Tam Nhu Tran 306a8276b3 fix(metrics): enforce exact runtime inventory 2026-07-26 09:36:00 -04:00
Tam Nhu Tran 1e11335348 docs(contributing): align test and UI guidance 2026-07-26 09:34:18 -04:00
Tam Nhu Tran 2d909a162f Merge remote-tracking branch 'origin/dev' into kai/review/pr-1655-retry-followup 2026-07-22 15:08:11 -04:00
Tam Nhu Tran 480b79551b fix: apply cliproxy retry settings safely 2026-07-22 15:08:06 -04:00
Kai (Tam Nhu) Tran 9cbf02b1be Merge pull request #1652 from minhbi245/feat/fable-tier-mapping
feat(ui): add fable tier row in model mapping
2026-07-22 14:59:24 -04:00
Tam Nhu Tran f7241d0874 fix: propagate fable model mapping across runtime paths 2026-07-22 14:58:57 -04:00
Kai (Tam Nhu) Tran 3608bf71a1 feat: rebrand CCS as Claude Codex Switch (#1658)
Closes #1657
2026-07-22 14:23:42 -04:00
milesnguyen2405 b27a007229 feat(ui): add fable tier row in model mapping 2026-07-22 14:51:40 +07:00
Tam Nhu Tran 003342f604 hotfix(docker): select Alpine-compatible CLIProxy asset 2026-07-18 19:55:07 -04:00
Tam Nhu Tran 44718e98ef fix(auth): preserve xAI profile compatibility 2026-07-18 19:04:37 -04:00
Tam Nhu Tran 90c0409aac Merge remote-tracking branch 'origin/dev' into kai/review/1641-xai-grok 2026-07-18 18:14:56 -04:00
Tam Nhu Tran 6dc199a038 fix(ci): isolate Bar command fast tests 2026-07-18 17:46:53 -04:00
Tam Nhu Tran 8996c92fda fix(bar): preserve quota cache and reset semantics 2026-07-18 17:28:36 -04:00
Tam Nhu Tran f77ed33cc7 fix(bar): show Claude and Codex pool quota 2026-07-18 17:13:40 -04:00
minhbi245 54a2b4759b feat(cliproxy): add xAI Grok provider 2026-07-17 00:02:12 +07:00
Tam Nhu Tran 234dce3150 fix(codex-auth): reject aliased plugin cache paths 2026-07-15 11:36:15 -04:00
Tam Nhu Tran 960d6e23a0 test(codex-auth): cover profile cache repair entry points 2026-07-15 10:24:13 -04:00
Tam Nhu Tran e5d4d860b3 fix(codex-auth): share plugin cache across profiles 2026-07-15 10:24:13 -04:00
Tom Price a7f3e4bc0e fix: guard against missing modelBreakdowns in usage aggregation
The CCS Bar server was crash-looping with:

    [X] Cannot read properties of undefined (reading 'length')

Usage records from partially-written or legacy persisted files (e.g. a
Codex rollout scanned mid-write) can be missing modelBreakdowns despite
the type. getHourlyRequestCount() and the daily/monthly/hourly merges
read it unguarded, and the Bar re-runs aggregation every ~5 min and
restarts on crash - hence the loop.

Default modelBreakdowns to [] at every use site and fall back to 0 for
request count. Regression test added for all three merges.

I don't normally work in TS and this was heavily tool-assisted, but it
has fixed the crash loop on my machine.
2026-07-12 21:23:31 -04:00
Tam Nhu Tran 77e73dd091 fix(codex): preview joined migration TOML repair
Closes #1635
2026-07-10 08:54:18 -04:00
Sergey Galuza 1e63c37baf feat(pricing): register Claude Sonnet 5 in the pricing registry
Add explicit `claude-sonnet-5` and `claude-sonnet-5-thinking` entries to the
web-server PRICING_REGISTRY at the standard Sonnet rates ($3/$15 in/out,
$3.75/$0.30 cache).

The model catalog and dashboard already ship Sonnet 5 (it is the Claude
default), but pricing was missing: getModelPricing() fell through to
UNKNOWN_MODEL_PRICING, which only coincidentally matches Sonnet rates. As a
result hasCustomPricing('claude-sonnet-5') returned false and getKnownModels()
omitted it, so Sonnet 5 was treated as an unknown model in cost accounting and
known-model listings.

Registering it explicitly makes the pricing intentional and consistent with
every other Claude model, without changing any resolved values.

Built [OnSteroids](https://onsteroids.ai)
2026-07-07 14:51:43 +02:00
Kai (Tam Nhu) Tran 1ee7cac555 fix: reject case-variant symlinked file paths (#1629)
* fix: reject case-variant symlinked file paths

* fix: validate requested case-variant symlink paths
2026-07-01 01:26:48 -04:00
Kai (Tam Nhu) Tran 343899f6c1 fix: prevent default profile credential collision (#1628)
* fix: prevent default profile credential collision

* fix: isolate default profile credential fallback
2026-07-01 01:15:45 -04:00
Kai (Tam Nhu) Tran 0f9a87619c fix: cap native quota profile refresh fan-out (#1627)
* fix: cap native quota profile refresh fan-out

* fix: preserve native quota live cache state
2026-07-01 01:09:01 -04:00
Kai (Tam Nhu) Tran 3621f8dcb1 fix: validate CCS Bar launch shim target integrity (#1626)
* fix: validate CCS Bar launch shim target integrity

* fix: execute verified bar shim bytes
2026-07-01 00:49:56 -04:00
Kai (Tam Nhu) Tran 05685d1c21 fix: keep agy websearch permissions enabled (#1625) 2026-07-01 00:45:09 -04:00
Kai (Tam Nhu) Tran 0180b62453 fix(bar): use nonce-bound probe auth (#1623) 2026-06-30 13:10:56 -04:00
Kai (Tam Nhu) Tran 138ead0e1e fix(logging): redact browser debug endpoint (#1622)
* fix(logging): redact browser debug endpoint

* fix(logging): redact prompt argv values
2026-06-30 13:07:46 -04:00
Kai (Tam Nhu) Tran f2843ad2ce fix: fail closed on websearch launch provisioning (#1621) 2026-06-30 13:00:41 -04:00
Kai (Tam Nhu) Tran 0527e276b1 fix: skip paused codex accounts in bar refresh (#1620) 2026-06-30 12:59:54 -04:00
Kai (Tam Nhu) Tran 396e01ab6f fix: bound bar raw socket probes (#1618) 2026-06-30 12:53:35 -04:00
Kai (Tam Nhu) Tran 2f1453e397 fix(auth): honor legacy unified default profiles (#1619) 2026-06-30 12:53:03 -04:00
Kai (Tam Nhu) Tran 4283c4665c fix(cursor): propagate daemon auth token (#1616)
* fix(cursor): propagate daemon auth token

* fix(cursor): align daemon auth token propagation
2026-06-30 12:37:41 -04:00
Kai (Tam Nhu) Tran 3f1dce30bc fix: close bar launch case bypass (#1613) 2026-06-30 12:33:46 -04:00
Tam Nhu Tran 045fc93285 test(glmt): align thinking signature coverage 2026-06-29 12:58:38 -04:00
Sergey Galuza cbcdb6ba62 fix(glmt): emit thinking signature as opaque string
generateThinkingSignature() returned an object
({type, hash, length, timestamp}) but Anthropic requires a thinking
block's `signature` to be a non-empty opaque STRING. The object made
the thinking block invalid, breaking the stream against reasoning
backends and surfacing as a false 502 "did not respond within 600s".

Return a deterministic base64 token instead (no Date.now()), and
narrow ThinkingSignature to a string alias so existing imports stay
intact. The signature is only ever assigned, never read as an object,
so consumers are unaffected. Update the existing unit test to the
corrected string contract.

Built [OnSteroids](https://onsteroids.ai)
2026-06-29 13:27:09 +02:00
Sergey Galuza 37d2bae001 test(glmt): assert thinking signature is a non-empty opaque string
Add two contract tests on the public proxy path
createAnthropicProxyResponse: JSON and SSE. Anthropic requires a
thinking block's signature to be a non-empty opaque string, but ccs
currently fabricates the signature as an object via
generateThinkingSignature(), which breaks the stream against reasoning
backends.

Built [OnSteroids](https://onsteroids.ai)
2026-06-29 13:26:16 +02:00
Kai (Tam Nhu) Tran 9dd9bf2978 feat(websearch): add agy provider and deprecate gemini cli fallback (#1607)
Google retired the gemini CLI on 2026-06-18, so the gemini websearch fallback no longer
works. Add agy (Antigravity) as the primary CLI websearch provider end to end: runtime spawn
in websearch-transformer.cjs (agy --dangerously-skip-permissions --print-timeout Ns -p),
detection (agy.ts), config schema and defaults, hook env, status, dashboard persistence, and docs.

The legacy gemini provider stays present but is marked deprecated for enterprise users who
retain access. Image analysis already supported the agy provider (no change). The CLIProxy
gemini quota fetcher (Gemini API OAuth, not the cli binary) is untouched.

Validation: typecheck, lint, and the websearch + config + web-server unit suites pass.
2026-06-27 10:01:25 -04:00
Thibault Jaigu a167f94e1b feat: add Requesty as an OpenAI-compatible provider (#1604)
Add a Requesty provider preset to the provider preset catalog, mirroring the existing OpenRouter preset (base https://router.requesty.ai/v1, default model openai/gpt-4o-mini, OpenAI-compatible).
2026-06-26 15:41:24 -04:00
Thieu Nguyen ba0e768fbf fix(codex): normalize CLIProxy responses routes (#1605)
Normalize Codex Responses base URLs so CCS-backed Codex launches use /backend-api/codex on the original CLIProxy backend. Share the Codex Responses route builder with ccsxp provider repair, and repair stale native Codex provider auth blocks when env_key token injection is used.
2026-06-26 15:41:15 -04:00
Kai (Tam Nhu) Tran 482868ad97 Merge pull request #1596 from kaitranntt/kai/feat/1595-bar-multi-profile-quota
feat(bar): per-profile subscription quota for ccs auth + ccsx auth accounts
2026-06-24 17:01:40 -04:00
Tam Nhu Tran b514986ddd fix(bar): short-TTL parked rows + keep valid codex subs active
Addresses two review focus areas:

- Stale Parked Rows: profiles with no on-disk credentials cached their parked
  row for the full quota TTL, so a fresh login stayed dimmed for up to 10 min.
  Parked rows (quotaStatus 'unsupported') now use a 30s TTL so a new login is
  picked up within seconds.
- Codex Fallback: a named codex profile whose token authenticated but whose
  response lacked core windows was downgraded to a parked/needsAuth row, hiding
  a real subscription. It now emits an active (quota-less) row; only the bare
  default still falls back to global local session data.

Also fixes a latent coalescing bug the short TTL exposed: a synchronous return
inside the pending IIFE cleared state.pending during its own assignment, leaving
a stale resolved promise that the next call reused. The IIFE now yields once so
the assignment lands before the finally clears it.
2026-06-24 00:52:55 -04:00
Tam Nhu Tran a1a565177e fix(codex): route codex CLI to /backend-api/codex on original CLIProxy backend
The Codex CLI provider config uses wire_api = "responses", so the Codex CLI
appends "/responses" to its base_url. buildCodexCliproxyProviderBaseUrl derived
the base URL from the backend-aware route helper, which returns the bare root for
the original backend. Codex then called http://127.0.0.1:<port>/responses, which
the original CLIProxy binary does not serve, producing a 404 on every request.

The original backend serves the Codex Responses API only at /v1/responses and the
chatgpt_base_url-compatible alias /backend-api/codex/responses. Use that alias for
the original backend; keep the provider-scoped alias for the Plus backend.

Closes #1597
2026-06-24 00:08:02 -04:00
Tam Nhu Tran 7b610f0e82 fix(bar): keep is_default on cache-fallback rows
The collector cached each row before the default profile was resolved, so the
cache-fallback path (getCachedNativeAccountRows) served the default account with
is_default:false -- the UI then lost default ordering/tagging when /summary
served from cache. Write the resolved default flag back onto the cached copy so
the fallback stays consistent with a fresh collection.
2026-06-24 00:03:20 -04:00
Tam Nhu Tran a0a2dd00fa fix(bar): cache expired profiles and gate codex local fallback to the default
Addresses two review focus areas:

- Reauth polling: a 401/expired profile now caches its dimmed reauth row and
  opens a cooldown, so it is shown parked and re-checked at most every 10 min
  instead of being re-polled (and re-401'd) on every /summary refresh.
- Wrong fallback: the global ~/.codex session-log fallback now applies ONLY to
  the bare default account. A named codex profile with no on-disk auth parks
  instead of borrowing the default's local usage (no misattribution).
2026-06-23 23:47:06 -04:00
Tam Nhu Tran ed86a089ba feat(bar): enumerate ccs/ccsx subscription profiles with per-profile quota
Replace single-account native quota collection with per-profile enumeration:
read ccs auth (Claude) and ccsx auth (Codex) profile registries plus the bare
~/.codex login, fetch each profile's quota under the existing TTL cache,
per-profile circuit breaker and 2.5s summary deadline. Emit surface, profile
and is_subscription wire fields; account_id becomes "<surface>:<profile>".

Active profiles (valid token) are live-polled and shown undimmed regardless of
default status; profiles without resolvable on-disk credentials are parked
(cache-only, dimmed). Claude per-profile credentials are read from disk only --
no macOS Keychain access -- so a profile without a credentials file renders as
needs-reauth instead of triggering a keychain prompt.
2026-06-23 22:56:38 -04:00