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)
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)
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.
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).
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.
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.
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
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.
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).
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.
Use a private safe ccs.js shim for native CCS Bar launch descriptors so symlinked Bun installs do not fall back to an app environment without node on PATH.
Codex quota in the menu bar came only from frozen local session logs, so it
showed stale data ("older session") that no refresh could update. Fetch it live
from the same source the dashboard uses, under the existing Claude-style safety
controls (10-min TTL, in-flight coalescing, 429 backoff, circuit breaker,
serve-stale), falling back to local logs when offline or rate-limited. A success
with no usable 5h/weekly window keeps the local reading rather than caching a
contentless row. The footer refresh and a new inline button on the Codex card
force a live pull past the open debounce, and a forced /summary re-pulls native
rows while serving the last-known cached rows if the live pull overruns its
budget, so the Claude/Codex cards never blank mid-refresh.
The spend strip gains a Today / 7d / 30d selector (default 7d), a taller chart,
and bottom time-axis labels (local hours for today, weekday for 7d, dates for
30d). The analytics endpoint now exposes a 24-bucket hourly series for today,
converted from the pipeline's UTC hour keys to the user's local clock so the
intra-day chart matches the dashboard.
Claude Code's status line and the session log showed 0 tokens for every
streaming response routed through the OpenAI-compatible proxy. The root
cause was that the upstream request did not include
`stream_options: { include_usage: true }`, so the provider (LiteLLM and
other OpenAI-compatible endpoints) never emitted the final SSE chunk
that carries `usage`. The proxy's stream parser was already wired to
forward that chunk into an Anthropic-shaped `message_delta` event but
had nothing to forward.
Set `stream_options.include_usage` whenever the incoming Anthropic
request is streamed. Non-streamed requests are unaffected.
Ref: https://platform.openai.com/docs/api-reference/chat-streaming
(search 'include_usage')
Redact StageOptions error payloads and summarize debug launch args.
Propagate request IDs through Cursor daemon and dashboard completion logs.
Mark remaining P2/P3 maintainability targets as partial instead of overclaiming.
Epic P7. Locks in the epic's gains with ESLint gates so the adoption work
does not regress.
- ccs/no-new-throw-error (error): custom flat-config rule that flags NEW
throw new Error(...) outside a generated baseline allowlist. Forces the
typed-error taxonomy (src/errors/error-types.ts). Existing 338 sites are
grandfathered in eslint-rules/throw-error-baseline.json; only NEW violations
error. Rule normalizes the filename to repo-root-relative to match baseline
keys regardless of how ESLint reports paths.
- max-lines (warn, 400, skipBlankLines/skipComments): warns on files over
400 LOC (goal of P5/P6 god-file splits). Currently 51 warnings on the
not-yet-split god-files (P6 territory).
- scripts/generate-throw-error-baseline.js: emits the allowlist from raw
source (superset of real throws; never undercounts). Run after intentionally
grandfathering a site, or quarterly to prune.
- tests/unit/eslint-rules/no-throw-new-error.test.ts: rule logic (flags
off-allowlist, passes on-allowlist/typed/rethrow, line-sensitivity).
- docs/code-standards.md: Lint Enforcement Gates section.
- docs/logging-contract.md: error.code -> ExitCode table (from P4).
validate + validate:ci-parity green.
Epic P2. Closes the three real traceability gaps so every diagnostic log can
carry a requestId from origin (ccs.ts main) through HTTP edges and spawned
daemons.
- log-context: add REQUEST_ID_HEADER/ENV/PATTERN, resolveRequestIdFromEnv,
forwardRequestIdEnv. runWithRequestId now reuses a forwarded CCS_REQUEST_ID
when well-formed (child re-anchor), else mints fresh.
- request-logging-middleware: wrap the Express dashboard handler chain in
withRequestContext so downstream route-handler logs carry requestId (mirrors
src/proxy/server/proxy-server.ts, which is untouched prior art).
- forward CCS_REQUEST_ID at the 4 child-daemon spawn sites: delegation
headless-executor, cursor-daemon, cursor-profile-executor, copilot-executor.
- cursor-daemon-entry: re-anchor via runWithRequestId so daemon startup logs
correlate with the spawning CLI invocation (ALS does not cross spawn).
- logger adoption toe-hold: delegation/session-manager (load/save failures) and
docker/supervisord-lifecycle (restart failure) now use createLogger.
api/channels/shared have no touchable diagnostic console.error (CLI-UX only or
pure data); dispatcher's only diagnostic is in pre-dispatch.ts, owned by plan
#1165. Those defer to P3's full per-site sweep.
Tests: request-context-middleware (handler log requestId === header),
request-id-forwarding (env resolve/reject, re-anchor, forwardRequestIdEnv).
validate + validate:ci-parity green.
Built-in Claude provider now uses the CLIProxy root URL instead of /api/provider/claude (which 404'd since base CLIProxy registers /v1/messages at root). Repairs stale local Claude settings, keeps non-Claude providers on their scoped routes, and applies the same root-URL rule to the ccs api create --cliproxy-provider claude bridge path via a shared buildCliproxyProviderPath helper. Closes#1545.
* test(bar): cover socket-level 401/403 auth detection and liveness-poll rogue rejection
Add two new describe blocks to bar-command.test.ts:
1. `defaultFindRunningServer: socket-level 401/403 classifies authRequired=true`
Drives `net.connect` via mock.module('net') to verify that status lines
401 and 403 off the wire set authRequired=true. A correct-token 200 must
not set authRequired. Prior tests bypassed the real status-line parser by
injecting authRequired via deps; these tests couple to the actual branch.
2. `defaultWaitForServerLive: rogue 200 without matching token is rejected`
Uses the same net mock pattern to verify that a 200 carrying a wrong
x-ccs-bar-token never causes the liveness poll to resolve (rogue reflector
cannot pass). Correct token resolves immediately.
Export `defaultWaitForServerLive` from launch-subcommand.ts so the direct
unit test can import it without forcing a full handleBarLaunch invocation.
Both test groups are behavior-coupled: removing the relevant branch in
production causes the tests to fail (verified under mutation).
* refactor(bar): drop dead ensureLoopbackNoProxy proxy shim
The probe now uses raw net.connect() which never consults proxy env vars
(undici was fully removed in an earlier PR). ensureLoopbackNoProxy()
permanently mutated process-wide NO_PROXY/no_proxy on every discovery call
with no effect on the actual network path.
Verified zero remaining references to ensureLoopbackNoProxy outside the
declaration and call site that are now removed.
Closes a spoofed-loopback-200 bar.json poisoning vector with a per-user 0600 capability token. The real bar server echoes its file-derived token on /bar/* responses; the launch probe verifies the echoed token against the locally-read file (fail-closed) before reusing a server, so a rogue loopback process that cannot read the token file is rejected.
Raw-socket probe detects auth-protected (401/403) bar servers, reuses them, and kills the orphaned detached server on auth timeout. Integrated with the non-blocking priority probe.