- pool --enable/--disable: refuse remote targets with manual config
guidance; resolve the lifecycle port instead of assuming 8317
- enablePoolRouting: roll back the pool flag when config regeneration
fails; already-enabled path re-runs regeneration (repairable state)
- pool opt-in prompt: gate on hasUnifiedConfig (legacy installs skip);
never auto-accept consent under --yes/CCS_YES
- order show (file mode): render selector pick order incl. residual
on-disk priorities and surface drift instead of alphabetical order
- order --reset: clear residual priority fields via management-API
PATCH when proxy runs, atomic direct write when stopped
- quota pool section: classify in-proxy 429 cooldowns as cooling with
reset times (graceful degradation when proxy or endpoint is absent);
honest paused label plus resume hint
- routing state: remote targets report pool as not manageable instead
of echoing the local flag; strategy/affinity apply warns when pool
routing overrides the change (CLI, API message, and dashboard)
- claude model-neutral: --config explicit pins survive the stale-pin
migration; remote env path filters historical default pins read from
claude.settings.json without mutating the file
- cross-lane guard: also checks account-profile CLAUDE_CONFIG_DIR lanes
for email overlap, not only the ambient ~/.claude login
- onboarding hint: opt-in copy naming ccs cliproxy pool --enable
- dashboard card: pool-ON shows drain-order pointer, pool-OFF shows the
enable command, local-only note for remote proxies (i18n x5)
- ccs cliproxy quota: per-provider Pool context section with routing
mode (pool on/off, strategy, affinity, effective retry cap), drain
order resolved exactly as the selector picks (incl. residual on-disk
priorities reordering display + drift warning), and per-account state
named distinctly: available / cooling-until-<time> / paused - these
produce different client errors so they read differently
- cooling visibility degrades honestly when pool cooling is disabled
(no cooldown data exists; renderer says so)
- dashboard routing card: pool badge + retry cap + drain-order hint in
compact and full variants via additive poolRouting state block
- no Bar summary fields, no per-session pin introspection (cut per
plan); policy_quota_unsupported semantics untouched
Part of #1464 account pools (phase 6).
Add a 'Get CCS Bar' promo banner + card to the dashboard (mirroring the
OpenRouter promo pattern + design system) so users discover the macOS menu-bar
app, with a macOS-aware install CTA. Add a user-facing docs/ccs-bar.md covering
what it is, install via 'ccs bar install', launch, what it shows, uninstall,
and the loopback requirement -- closing the docs-sync gap for the new ccs bar
command.
Commit 72ea1fc9 ("fix(accounts): simplify codex free tier badges") split
free codex accounts out of the `personal` audience into a distinct
`free` audience and dropped the `'Personal · '` prefix on inlineLabel,
but `account-visual-groups.test.ts` was not updated and has been
failing in CI ever since.
Update expectations to match the shipped behavior:
- `audience` for `-free` tokens is `'free'`, not `'personal'`
- `inlineLabel` for a bare free account is `'Free'`, not `'Personal · Free'`
- `compactDetailLabel` is `null` when no extra parts are present
- Sort order: business -> personal -> free -> unknown
Drive-by fix unrelated to the Opus 4.8 work in this PR but caught
because these tests started failing on every push to the branch.
Built [OnSteroids](https://onsteroids.ai)
Register `claude-opus-4-8` in the cliproxy model catalog, web-server
pricing table, and UI catalog as an additive entry next to 4.7. Defaults
are unchanged (claude provider stays on sonnet-4-6); users opt into 4.8
explicitly via ANTHROPIC_MODEL or the dashboard.
Configuration mirrors 4.7:
- adaptive thinking levels (low through max), max distinct from xhigh
- extendedContext (1M) available
- nativeImageInput
- pricing $5/$25 in/out, $6.25/$0.5 cache
Built [OnSteroids](https://onsteroids.ai)
Three design taste fixes that ride on top of the disclaimer collapse:
- Single-line profile trigger: render only `option.label` in the
Select trigger; keep label+description in the open menu where the
description earns its keep. Removes the two-line trigger that broke
the row baseline (taller pill, vertical-center cascade).
- Group Select + Info icon in an `inline-flex … shrink-0` cluster so
they wrap as a single unit and the icon never orphans onto a second
row under the refresh button.
- Compact timestamp: "Updated less than a minute ago" → "1m ago"
rendered in font-mono. Full phrase preserved via `title`
attribute. Drops the localized prefix into a tooltip-only context.
- Trigger width trimmed 190px → 170px since it no longer needs to fit
a description line.
The disclaimer paragraph rendered as a two-line block under the
controls row, eating vertical real-estate while the cards stayed
empty. Replace it with a small Info icon beside the profile
dropdown that surfaces the same copy in a tooltip on hover/focus.
- Same copy preserved verbatim; no informational loss
- Icon only renders when a non-All profile is selected
- Reclaims ~32px of vertical space on the analytics header
Closes#1390
Add Qoder provider models to both backend MODEL_CATALOG and UI
MODEL_CATALOGS with 11 models (5 auto-routing tiers + 6 frontier
models). Frontier models use unified preset mappings except
DeepSeek which routes haiku to Flash.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add Qoder provider to integration layers and dashboard UI:
- Channel-to-provider mapping in catalog-cache
- Model routing owner hints
- Provider editor owner map
- Setup wizard provider list
- Fallback visuals and brand color
Adds a read-only dashboard surface for the codex-auth profile registry.
Power users can see which profile is active and its decoded email/plan
without leaving the browser; mutations stay CLI-only.
- codex-auth-dashboard-service: builds the response shape (active +
default + profiles[]), reads each profile's auth.json, decodes id_token
via Phase 1 decoder (nested URI claims per C1), 5s in-memory single-key
cache plus exported invalidateCodexAuthProfilesCache() hook for
in-process Phase 2 callers (D7); strict field whitelist — id_token /
access_token / refresh_token NEVER appear in response body or logs
- GET /api/codex/profiles registered INSIDE the
requireLocalAccessWhenAuthDisabled middleware (H6) — emails are PII
and must not leak when dashboard is exposed remotely; integration
test asserts 403 from non-localhost origin
- NEW Auth Profiles tab (D5) in ui/src/pages/codex.tsx — distinct from
the existing codex-profiles-card (which edits config.toml [profiles],
a different concept); active profile + email + plan tier highlighted,
table of all profiles below, disabled Switch/Remove buttons redirect
to terminal commands
- accountId returned by API for power users (curl) but hidden from
the default UI (D6)
- 11 service unit tests + 4 endpoint integration tests, all green
Adds Korean (ko) as a supported dashboard locale alongside en, zh-CN, vi, ja.
Browser locales starting with `ko` (e.g. `ko-KR`) normalize to `ko` and the
Language switcher exposes "Korean" / "한국어" as a selectable option.
The full ~2670-key translation block was translated from the English source
with the formal-polite register (하십시오체) appropriate for an enterprise
dashboard. Technical names (CCS, Claude, CLIProxy, OAuth, provider names,
env vars, paths) are kept untranslated. All placeholders (e.g. {{name}},
{{count}}, {{provider}}) are preserved verbatim, matching the parity test.
Also backfills 23 keys missing from zh-CN, vi, and ja that were added to en
with the recent "Shared Resource Controls" feature (#1206 -> 2a422b3b):
accountsPage.resources*, accountsTable.{sharedResources,resourcesTitle,
resourcesShared,resourcesProfileLocal,badges.profileLocal},
commonToast.resourcesUpdated, and the full editAccountSharedResources
section. Without this backfill the existing i18n parity test was red for
all non-en locales on dev.
Closes#1241
PR-Agent on #1248 flagged two remaining sensitive-mask edge cases:
1. The TOML array walker stepped through triple-quoted strings one
single quote at a time. With a body containing both quotes and
structural characters, like """abc"]xyz""", a stray `]` inside the
string body could escape the string-skip pair and terminate the
array scan early. Add skipTomlString that recognizes triple-quoted
strings ("""…""", '''…''') and skips them as one unit.
2. The JSON regex matched any "...": pattern, so substrings inside
escaped value strings, like "description": "use \\"API_KEY\\": header",
could mask unrelated text. Replace the JSON branch with a state-aware
scanner that only registers a string as a key when it sits at an
object-key position (preceded by `{` or `,`, followed by `:`).
Adds regression tests for both cases.
PR-Agent on #1248 flagged that the TOML array walker did not skip
`#` line comments while balancing brackets. A sensitive array with a
comment containing `]` could terminate the scan early and leave the
real tail of the secret unmasked. Skip from `#` to the next newline at
the array's top level. Adds a regression test.
PR-Agent review on #1248 flagged two follow-ups:
1. The reveal CSS used `.cm-editor.cm-sensitive-revealed`, but
@uiw/react-codemirror puts the consumer className on its outer
wrapper, not on .cm-editor. The selector never matched, so the Eye
toggle could not un-blur masked values. Drop `.cm-editor` from the
selector so it matches the wrapper that actually carries the class.
2. The sensitive-decoration plugin rebuilt on every `viewportChanged`,
which means each scroll event re-stringified and rescanned the
entire document even though decorations are doc-only-dependent.
Rebuild only on `docChanged` to remove scroll-time work.
Two remaining gaps in the sensitive-value detector flagged by PR-Agent
on #1248:
1. The TOML/YAML key regex only matched bare keys, so values written
under quoted keys like `"API_KEY" = "secret"` were never masked.
Accept basic-string and literal-string quoted keys and normalize the
captured key (strip quotes, unescape) before isSensitiveKey.
2. The string-skip helper used indexOf for the next quote character, so
a value like `AUTH_TOKEN = ["a \"quoted\" value", "x"]` could
terminate scanning early and leak unrelated text or under-mask the
secret. Introduce skipString that honors backslash escapes for basic
strings and is used by both the TOML array walker and the JSON
balanced-brace walker.
Adds regression tests for both edge cases.
Extend the sensitive-key decoration to cover the full logical value, not
just the rest of the current line. Adds value-extent detection for:
- TOML triple-quoted strings (multi-line literal/basic strings)
- TOML arrays ([ ... ] across multiple lines, string-aware)
- YAML block scalars (| and > with indent-based termination)
- JSON arrays and objects (balanced braces, string-aware)
Without this, a secret value spanning multiple lines (multi-line API
key, certificate, private key) was only blurred on its opening line and
the rest stayed readable when the Eye toggle was masked.
Adds regression tests for the TOML triple-quote and array cases.
Flagged by PR-Agent review on #1248.
Replace the hand-rolled textarea+Prism overlay in CodeEditor with
CodeMirror 6. The overlay hid the textarea selection with
`selection:bg-transparent` and `WebkitTextFillColor: transparent` as a
workaround for wrap drift between the highlight layer and the textarea,
which left Ctrl+A / drag-select / Ctrl+C with no visible result.
CodeMirror handles selection, copy, undo, and wrap natively. Custom
themes match the previous prism-react-renderer github (light) and
nightOwl (dark) palettes; background is transparent so the surrounding
bg-muted/30 still shows; font, font-size, line-height, padding, and
gutter-less layout are preserved.
Public CodeEditor props are unchanged (value, onChange, language,
readonly, exactText, className, minHeight, heightMode) so all seven
call sites keep working. The sensitive-key blur is reimplemented as a
CodeMirror Decoration and stays gated behind the existing Eye toggle.
Test setup gets a Range.getClientRects polyfill so CM mounts cleanly in
JSDOM, and shared-page.test.tsx checks .cm-content text directly.
Closes#1247