Commit Graph
730 Commits
Author SHA1 Message Date
Kai (Tam Nhu) TranandGitHub 54e15c430e Merge pull request #1140 from kaitranntt/kai/feat/1139-claude-quota-bars
feat(ui): clarify Claude quota bars
2026-04-30 10:58:11 -04:00
Tam Nhu Tran 476c6d827f fix(ui): improve split quota bar readability 2026-04-30 10:32:43 -04:00
Tam Nhu Tran a8b686d643 feat(ui): show split Claude quota bars 2026-04-30 10:05:19 -04:00
Tam Nhu Tran 804b1e80b4 chore: remove build artifacts accidentally committed 2026-04-29 17:20:11 -04:00
Tam Nhu Tran c3c8cb7a82 fix(cliproxy): exclude colocated tests from tsconfig and eslint
- Add src/**/__tests__/** to tsconfig.json exclude list
- Add ignores pattern for __tests__ in eslint.config.mjs
- Fix ui/src/lib/api-client.ts import path for provider-entitlement-types
- Remove stale build artifacts from ui/src/lib/ and tests/mocks/
2026-04-29 17:18:23 -04:00
Tam Nhu Tran 5013d411a7 feat(cliproxy): self-pause exhausted quota accounts 2026-04-28 20:35:15 -04:00
Kai (Tam Nhu) TranandGitHub a8e0d95bc8 Merge pull request #1117 from kaitranntt/kai/feat/1115-session-affinity
feat: add local CLIProxy session affinity controls
2026-04-28 13:37:37 -04:00
Tam Nhu Tran 5267c421ca fix(cliproxy): harden session affinity behavior 2026-04-28 13:27:05 -04:00
Kai (Tam Nhu) TranandGitHub f328cff870 Merge pull request #1113 from yousiki/fix/codex-additional-rate-limits
fix(cliproxy): parse Codex additional_rate_limits for Spark quota
2026-04-28 13:04:16 -04:00
Tam Nhu Tran 148cf35560 fix(cliproxy): polish session affinity controls 2026-04-28 12:38:30 -04:00
Tam Nhu Tran c277955762 fix(cliproxy): tighten session affinity review issues 2026-04-28 12:33:12 -04:00
Tam Nhu Tran 20f3916d55 fix(cliproxy): tighten session affinity status handling 2026-04-28 12:26:42 -04:00
Tam Nhu Tran 4309db89c3 feat(cliproxy): add local session affinity controls 2026-04-28 12:17:26 -04:00
yousikiandClaude Opus 4.7 0e602932f2 fix(ui): widen getCodexWindowKind parameter to accept CodexWindowSummary
The new helpers added in this PR (inferCodeReviewCadence,
getCodexWindowDisplayLabel) operate on CodexWindowSummary - a Pick subset
of CodexQuotaWindow without usedPercent/remainingPercent/resetAt. They
pass that subset into getCodexWindowKind, which was still typed as
string | CodexQuotaWindow, so tsc -b fails with TS2345 in CI. The
function only reads label/category/cadence, all of which exist on
CodexWindowSummary, so widening the parameter is safe and lets a real
CodexQuotaWindow continue to flow through unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 10:59:58 +09:00
Tam Nhu Tran b2e4be310d fix(ui): tighten analytics session and query contracts 2026-04-27 12:30:56 -04:00
yousiki a90aadd202 fix(cliproxy): tighten Codex window classification on incomplete metadata
Apply Copilot review feedback on PR #1113:
- getCodexWindowKind: require cadence alongside category; fall through
  to label sniffing when missing instead of silently defaulting to 5h.
- getCodexWindowDisplayLabel (CLI): for category 'additional', fall back
  through featureLabel -> window.label -> 'Additional' so partial cached
  windows preserve user-visible context.
2026-04-27 16:57:28 +09:00
yousiki 725d95b0d2 fix(ui): surface Codex Spark windows in dashboard quota views
Mirror the server-side CodexQuotaWindow metadata extension on the UI
side: api-client.ts gains category/cadence/featureLabel; utils.ts
breakdown returns additionalWindows so Spark quota does not pollute
core 5h/weekly badges; quota-tooltip-content renders Spark inline with
prettified labels (GPT-5.3-Codex-Spark -> Codex Spark). Adds breakdown
unit tests and i18n strings for English/Chinese/Vietnamese/Japanese.
2026-04-27 15:50:31 +09:00
Tam Nhu Tran e2f1363708 fix(analytics): correct token accounting and usage aggregation
Align snapshot handling and UI contracts with the current analytics payloads.
2026-04-26 15:21:52 -04:00
Tam Nhu Tran aec5267651 fix(ui/design-system): address PR-Agent round 2 on PR #1109
Three more issues raised by upstream review after the v1.7 fix push.
Each is encoded both in code and in spec so future drift can't
reintroduce them:

1. Required `storageKey` was the wrong fix for cross-page state bleed.
   Forcing every callsite to pass `storageKey` made future
   production-page migrations a build-breaking event for no real
   safety benefit. Better engineering: keep the prop optional and
   default to a key derived from `window.location.pathname` so each
   route gets its own localStorage slot automatically. Pathname-
   derived defaults are unique by construction; the cross-page bleed
   risk only exists for hardcoded shared keys, which the doc warns
   against. SSR-safe (falls back to a stable string when window is
   unavailable). Pages can still pass an explicit `storageKey` to opt
   out of pathname coupling (e.g. when sub-routes should share state).

2. `MaskedInput` `type` was overridable by callers, which defeated
   the component's purpose for credentials. Two-layer fix:
   - Compile-time: `MaskedInputProps` now extends
     `Omit<InputHTMLAttributes, 'type'>` so callers literally cannot
     pass `type`. The TS surface enforces the contract.
   - Runtime: the `type` attribute on `<Input>` is now placed AFTER
     the spread so even an `as`-cast bypass can't override it.

3. The reveal toggle was keyboard-inaccessible. Both `MaskedInput`
   and `Field` had `tabIndex={-1}` on the eye-icon button, removing
   it from the tab order. Keyboard-only users couldn't show or hide
   the secret. Resolution:
   - Drop `tabIndex={-1}` so the button joins the natural tab order.
   - Add `aria-pressed={revealed}` so screen readers announce toggle
     state.
   - Add a focus-visible accent ring so the focused state is visible
     without a mouse.

Decisions log: v1.8 entry records the rationale for each correction
and explicitly calls out that v1.7's "required storageKey" fix was
worse than the problem it tried to solve.

Validation: typecheck + lint + format + build clean. Tests 519/521
pass (2 pre-existing account-visual-groups failures on dev,
unrelated). Styleguide demos still pass storageKey explicitly so
behavior is unchanged for the only existing callsites.
2026-04-26 14:04:39 -04:00
Tam Nhu Tran 839997d08e fix(ui/design-system): address PR-Agent feedback on PR #1109
Three substantive issues raised by upstream review, encoded in code +
spec so future drift can't reintroduce them:

1. Width floor was unenforceable. The previous spec wording said
   "form ≥ 360px / json ≥ 320px" but `react-resizable-panels` v3 only
   accepts percentage `minSize`. On a 1280px viewport this could let a
   user drag a pane down to ~250px — well below the documented floor.
   - `Panel minSize` bumped 25 → 30 (≥ 30% of body width after rail)
   - Spec rewritten percent-based with the actual 300–360px range
     across realistic viewports plus a note on the v3 API constraint
     and the `onResize`-clamp escape hatch if hard pixel floors become
     necessary later.

2. `storageKey` default caused cross-page state bleed. The previous
   default `storageKey="ccs.config-layout"` meant any `<ConfigLayout>`
   without an explicit key would share localStorage state with every
   other Config page — split ratios contaminating across unrelated
   pages.
   - `storageKey: string` is now REQUIRED (no default). TypeScript
     compile-fails any caller that omits it.
   - Spec restated to make the per-page-key contract explicit.

3. Sensitive-field heuristic was too narrow. The previous regex
   `AUTH_TOKEN|API_KEY|SECRET|PASSWORD|PRIVATE_KEY` missed common
   secret names (ACCESS_TOKEN, REFRESH_TOKEN, BEARER_TOKEN,
   CLIENT_SECRET, CLIENT_ID, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY,
   GCP/Azure/GitHub/OpenAI/Anthropic variants, JWT, OAUTH, CREDENTIAL,
   PAT, WEBHOOK_SECRET, HMAC_KEY, SIGNING_KEY, SSH_KEY).
   - New `src/lib/sensitive-label.ts` Single Source of Truth
     (`isSensitiveLabel(label)`) with broadened regex; case-insensitive
     and tolerant of `_`/`-` separators.
   - `Field` imports the shared helper; future consumers do too.
   - Spec §5g enumerates the new patterns and points at the SSoT.

Decisions log: v1.7 entry records the rationale and the connections
between spec wording and library API constraints, so the next reviewer
sees the trail rather than re-discovering it.

Validation: typecheck + lint + format clean; build clean; tests
519/521 pass (2 pre-existing account-visual-groups failures on dev,
unrelated). Styleguide demos already pass storageKey explicitly.
2026-04-26 13:50:47 -04:00
Tam Nhu Tran 53030891c6 feat(ui/design-system): codify rail-anchored layout invariants and palette
Adds a page-level design system spec for CCS dashboard Config pages,
without migrating any production page yet. Pure-spec PR: docs +
primitive treatments + DEV-only /_styleguide route. Production page
adoption is intentionally left for follow-up work, one page at a time.

Spec — `ui/docs/design-system.md`:

- §0 Layout invariants (NEVER VIOLATE): two-column shell, no second
  horizontal strip below the global topbar, sibling-pane top alignment,
  cliproxy as canonical reference, user-resizable form/json split, and
  content-fit unified rail (`w-fit min-w-[240px] max-w-[360px]`)
- §1 identity-strip patterns: HeroBar (home), rail-anchored (cliproxy),
  PageHeader (Monitor-only), Bespoke (health)
- §2 body archetypes: Config (rail + form + optional json) and Monitor
- §4 anti-patterns with rejected code samples (PageHeader-over-
  ConfigLayout, tab-bar offsetting json pane, redundant description
  band, blank vertical band)
- §5 color & accent rules using the existing Pampas/Crail palette only:
  1-accent-dot rule, sibling-pane differentiation, status pill spec,
  three-tier intensity ladder, sensitive-field treatment per §5g

Decisions log — `ui/docs/design-decisions.md`:

- v1.6: content-fit rail (replaces fixed 260px)
- v1.5: color & accent treatment for body panes
- v1.4: resizable form/json split
- v1.3: layout invariants and rail-anchored default for Config

Primitives — `ui/src/components/config-layout/`:

- ConfigLayout: rail rendered as content-fit `<aside>` within the
  unified envelope; form↔json split via react-resizable-panels (already
  in deps) with autoSaveId-driven per-page localStorage persistence
- FormPane: 1px Crail top strip on header + soft from-card gradient +
  inset bottom shadow for scroll-depth cue; body wash bg-muted/20 so
  FormSections read as elevated cards; footer bg-muted/40 anchors save
- FormSection: 2px Crail leading-edge stripe with three-tier intensity
  (default 30% / hover 70% / focus-within solid + ring + shadow) + 1.5px
  accent dot prefixing each title
- JsonPane: bg-muted/30 shell visually recesses the read-only pane vs
  the active form pane (bg-card); accent dot + status pill in header;
  inner <pre> sits inside an inset-shadow well; content stays plain
  (a dedicated JSON viewer with its own color coding will replace it
  later — pages MUST NOT add inline JSON tints in the meantime)
- ListPane: selected row uses three-tier intensity ladder (no stripe at
  rest, accent/30 stripe on hover, solid Crail stripe + bg-accent/10
  row tint + accent-tinted icon and count badge on selection)

Sensitive input primitive — `ui/src/components/ui/masked-input.tsx`:

Upgraded to match §5g: lock glyph prefixing label, "sensitive" accent
pill on the label row, accent focus ring (the only place the default
ring is overridden), accent-tinted reveal toggle on hover. Existing
consumers (settings-dialog, websearch, friendly-ui-section, env-editor-
section) inherit the treatment without code changes.

Shared Field — `ui/src/components/forms/field.tsx`:

Tiny self-documenting Field component referenced by /_styleguide demos.
Auto-detects sensitive labels (AUTH_TOKEN | API_KEY | SECRET | PASSWORD
| PRIVATE_KEY) and applies §5g treatment. Production pages can adopt
this as a follow-up; no production code currently consumes it.

Live styleguide — `ui/src/pages/_styleguide.tsx`:

DEV-only route (gated by import.meta.env.DEV in App.tsx) showcasing
every primitive in isolation plus composed Config + Monitor archetype
demos. Intro callout surfaces the §0 invariants. §1b/§2a/§2b demos are
canonical rail-anchored examples authors can copy. Demo content uses
realistic Anthropic-style env field sets so the visual density mirrors
the cliproxy reference.

What this PR does NOT do:

- No production page rewrites — `pages/{api,accounts,codex,copilot,
  cursor,droid,shared,updates,analytics,claude-extension,cliproxy-ai-
  providers}` are unchanged
- No test selector updates — the existing test suite passes (excepting
  the 2 pre-existing account-visual-groups failures already on dev)
- No HTML preview reports — the canonical visual reference is the live
  /_styleguide page
- No new dependencies — `react-resizable-panels` was already declared

Validation: typecheck + lint + format + build clean. Test suite green
(519/521 — 2 pre-existing dev failures unrelated to this PR).
2026-04-26 13:30:03 -04:00
Tam Nhu Tran 8911906e9f fix(codex): resolve PR review contract and i18n drift 2026-04-26 11:24:08 -04:00
Tam Nhu Tran 82c92aa940 feat(codex): align ccsxp with native cliproxy shortcut 2026-04-26 11:09:54 -04:00
Tam Nhu Tran e64060fe0d fix(ui): address PR-Agent round 2 on health redesign
PR-Agent flagged two more real regressions vs the original health page:

1. Stale timestamp (HealthStatusRibbon): formatRelativeTime reads
   Date.now() during render, but nothing forces a re-render after mount
   so the 'last scan' label froze and never advanced to '1 minute ago',
   '2 hours ago', etc. Restore the per-second tick (matching the
   original health.tsx behavior) so the label behaves like a real
   relative timestamp.

2. Hidden copy action (HealthPriorityCard): the fix-copy button was
   gated by group-hover, making it invisible to keyboard users and
   unreachable on mobile (no hover state). Make it always visible with
   an aria-label so screen-reader and touch users can copy the fix
   command.
2026-04-25 19:14:42 -04:00
Tam Nhu Tran 525c4f9812 fix(ui): address PR-Agent feedback on health redesign
PR-Agent flagged two real bugs at score 84:

1. Accessibility (HealthPriorityCard): the priority card header was a
   clickable <div> with onClick, making expand/collapse mouse-only.
   Promote it to a <button type="button"> with aria-expanded reflecting
   state and a contextual aria-label, and a focus-visible ring. The
   inner content is extracted into a shared fragment so the button and
   the no-content fallback <div> render the same markup.

2. Time display (HealthStatusRibbon): formatRelativeTime lost the hours
   branch from the original health.tsx, so a 2-hour-old scan showed as
   '120 minutes ago' instead of '2 hours ago'. Restore the hours
   rollover with health.hoursAgo i18n key.
2026-04-25 19:10:00 -04:00
Tam Nhu Tran 90a3d330df fix(ui): polish health page background and priority card layout
Iteration on top of the health redesign:
- layout.tsx: drop backdrop-blur transparency on the global header
  (interfered with the new health page colored backdrop)
- health.tsx: switch from fixed full-viewport background to scoped
  absolute positioning; replace unreliable external grain SVG (vercel
  app) with an inline data URI that always loads
- health-priority-card.tsx: refine spacing, expansion behavior, and
  visual hierarchy
2026-04-25 16:29:16 -04:00
Tam Nhu Tran 4d314ef2b7 chore: resolve merge conflicts and integrate health page redesign 2026-04-25 14:48:40 -04:00
Tam Nhu Tran 36ed091e4d feat(ui): redesign health page with prioritized layout and premium aesthetics 2026-04-25 14:45:58 -04:00
Tam Nhu Tran ba4fbcf75f docs(ui): add HeroBar and rail-anchored demos to styleguide
The v1.1 design contract names three identity-strip patterns but the
styleguide previously only demoed PageHeader. Future contributors
visiting /_styleguide had no live preview of HeroBar or rail-anchored
identity, leaving the contract under-documented.

Add:
- 1a. HeroBar demo (canonical: home pattern) -- single-row dense hero
  with logo + title + version badge + 4 inline stat tiles, dotted
  background pattern, anonymized data
- 1b. Rail-anchored identity demo (canonical: cliproxy pattern) -- a
  Config 3-pane layout where the left rail carries brand + Quick Setup
  CTA + provider list + footer status, with NO top chrome
- 1c. PageHeader demo (existing, retitled with health pattern reference)

All demos use anonymized data (Provider A/B/C, Demo Dashboard, fake
metrics) so screenshots are safe to publish without Privacy mode.
2026-04-25 14:08:42 -04:00
Tam Nhu Tran 1a2fd848f0 refactor(ui): revert home/cliproxy migrations and restructure design system
User feedback caught a Phase 2 mistake: forcing home and cliproxy into
a one-size-fits-all PageShell + PageHeader chrome regressed density on
both pages.

- home: original 1-row hero (logo + title + version + 4 inline stats)
  was split into PageHeader + KpiRow, doubling vertical footprint
- cliproxy: original rail-anchored brand was duplicated by a top
  PageHeader, stealing ~80px from the 3-pane body

Resolution: revert both pages to dev-branch state, then restructure
ui/docs/design-system.md to extract THREE identity-strip patterns from
the canonical references rather than imposing one:

  1. HeroBar       (1-row dense)             -> home pattern
  2. Rail-anchored (no top chrome)           -> cliproxy pattern
  3. PageHeader    (title + description)     -> health pattern

Health stays migrated -- the Monitor archetype + PageHeader is a real
improvement there because the gauge + KPI row + group cards don't fit
the HeroBar pattern.

Future page migrations adapt to whichever identity-strip pattern fits
the page's content shape, not the other way around. design-decisions.md
gets a v1.1 revision row capturing the rationale.
2026-04-25 13:34:43 -04:00
Tam Nhu Tran c59622fabd fix(ui): restore click-through navigation on home KPI cards
PR-Agent caught a regression: pre-migration the four home stats had
onClick handlers navigating to /providers, /cliproxy, /accounts, and
/health. The Phase 2 migration dropped those handlers, removing the
shortcuts for all users.

Add an optional onClick prop to KpiCard. When supplied, the tile
promotes from a static <div> to a <button> with hover lift, keyboard
focus ring, and an accessible aria-label derived from the label.
Wire all four home KPIs back to their original navigation targets.
2026-04-25 13:18:44 -04:00
Tam Nhu Tran 9a2c09357a feat(ui): migrate cliproxy page to design system Config archetype
Wrap master-detail layout in PageShell + PageHeader + ConfigLayout.
PageHeader carries the brand strip (Zap icon + CLIProxy title +
account-management description) and refresh button. The existing
sidebar (Quick Setup CTA, sectioned providers list, variants list,
ProxyStatusWidget, footer connection summary) becomes ConfigLayout's
left rail; ProviderEditor and EmptyProviderState become the form pane.

Pure layout migration: every sub-flow still mounts correctly --
QuickSetupWizard dialog, AddAccountDialog (URL action=auth deep-link),
AccountSafetyWarningCard for gemini/agy, provider selection persisted
to localStorage and URL deep-link, all bulk pause/resume/solo/delete
mutations untouched. ProviderEditor (which contains the form + raw JSON
internally) remains as a single 'form' slot.
2026-04-25 13:13:14 -04:00
Tam Nhu Tran 5e3e554693 feat(ui): migrate health page to design system Monitor archetype
Hero gauge + status copy moved into a MonitorCard variant=terminal,
preserving the ccs doctor / live-ops aesthetic per locked decision #4.

HealthStatsBar replaced by a 4-column KpiRow with severity tones
(Checks / Passed / Warnings / Errors). Each HealthGroupSection becomes
its own MonitorCard while keeping the existing accordion behavior
intact -- so check expansion, sort-by-severity, and live monitoring
continue to work unchanged.

PageHeader carries the version badge, last-scan relative time,
auto-refresh hint, ccs doctor copy action, and refresh button.

Pure layout + visual hierarchy migration -- no new metrics, no new
features. LOC: 263 -> ~245.
2026-04-25 13:12:41 -04:00
Tam Nhu Tran 3ae5f20dc8 feat(ui): migrate home page to design system Monitor archetype
Wrap in PageShell + PageHeader + MonitorLayout. Replace bespoke hero
stat row with KpiRow + 4 KpiCards (profiles, cliproxy, accounts, health
with status-derived tone). AuthMonitor and ErrorLogsMonitor become
MonitorCard children; the 'logs moved' callout becomes a MonitorCard.

Pure layout migration -- behavior preserved (navigation, configuration
warning Alert, hooks unchanged). Hero punch retained via tone-coded KPI
cards. LOC: 208 -> 173.
2026-04-25 13:12:08 -04:00
Kai (Tam Nhu) TranandGitHub 283f866897 Merge pull request #1088 from kaitranntt/kai/feat/design-system-foundations
feat(ui): add design system foundations (PageShell + ConfigLayout + MonitorLayout)
2026-04-25 12:54:57 -04:00
Tam Nhu Tran 6261e150e3 fix(ui): address PR-Agent round 3 review on ConfigLayout duplicate DOM
Render exactly one layout at a time -- desktop 3-pane grid OR mobile
tabs -- via a useIsDesktop matchMedia hook gated at the lg breakpoint.

Previously the component rendered BOTH and toggled visibility via
Tailwind 'hidden lg:grid' / 'lg:hidden'. This duplicated FormSection
elements in the DOM, so document.getElementById() in SectionRail's
scroll-spy and click-to-jump would resolve to the (hidden) desktop copy
first on mobile -- making the rail attach to the wrong scroller and
never update the active section.
2026-04-25 12:48:06 -04:00
Tam Nhu Tran caef89a7aa fix(ui): address PR-Agent round 2 review feedback
MonitorLayout:
- Wrap ScrollArea in an explicit flex-col container with min-h-0. The
  previous version relied on the parent (PageShell) being flex-col for
  flex-1 to compute a definite height; that's fragile. The wrapper now
  establishes its own flex column so the ScrollArea reliably scrolls
  whether or not the caller's wrapper is flex.

ConfigLayout (MobileTabs):
- Derive active tab during render with fallback to first available, same
  pattern applied to JsonPane in the previous round. Parent toggling
  `left` or `json` props could change the available tabs and leave
  the controlled Tabs value pointing at a tab id that no longer existed,
  rendering an empty pane on mobile until the user manually switched.
2026-04-25 12:43:41 -04:00
Tam Nhu Tran 37de42d463 fix(ui): address PR-Agent review feedback on JsonPane and SectionRail
JsonPane:
- Reset active tab when the tabs prop changes. Previously activeTab was
  initialized once and never re-synced; a parent swapping the tab set
  (e.g. selecting a different entity) could leave us pointing at a stale
  id, leaving the pane empty and Copy returning '{}'.
- Force textarea remount on data change in editable mode via key={text}.
  Uncontrolled defaultValue retained the prior value when the underlying
  config changed, so onBlur could save stale text.

SectionRail:
- Default scroll-spy root to the nearest scrollable ancestor instead of
  the page viewport. FormPane wraps its body in a shadcn ScrollArea, so
  IntersectionObserver with root:null was watching the wrong scroller and
  the active section never updated as the form scrolled.
- observeRoot prop still wins when supplied for explicit overrides.
2026-04-25 12:36:58 -04:00
Tam Nhu Tran 64e78f6e69 feat(ui): add design system foundations
Introduce two locked page archetypes -- Config (3-pane) and Monitor
(KPI row + 12-col grid) -- wrapped by shared PageShell + PageHeader.

Primitives:
- page-shell/: PageShell, PageHeader, EmptyState, ErrorState
- config-layout/: ConfigLayout, ListPane, SectionRail, FormPane,
  FormSection, JsonPane (read-only by default, opt-in editable)
- monitor-layout/: MonitorLayout, KpiRow, KpiCard, MonitorGrid,
  MonitorCard (incl. variant="terminal")

Single ConfigLayout component, prop-controlled left rail:
- ListPane for multi-entity (cliproxy, accounts, providers)
- SectionRail for single-entity (codex, copilot, cursor, droid)
  with IntersectionObserver scroll-spy
- omit for none

DEV-ONLY /_styleguide route gated by import.meta.env.DEV. Shows every
primitive plus composed Config (multi + single) and Monitor demos using
fully anonymized data (Provider A/B/C, fake metrics).

Phase 1 of dashboard design system unification. Existing pages untouched
this phase -- migrations land in Phase 2+.

Locked decisions in ui/docs/design-decisions.md:
1. In-app /_styleguide over Storybook
2. Archetype name: Monitor (not Dashboard)
3. JsonPane read-only by default
4. Health terminal aesthetic kept as variant
5. i18n per-page namespaces
6. SectionRail uses scroll-spy
2026-04-25 12:16:27 -04:00
Kai (Tam Nhu) TranandGitHub 5dd5878bb4 Merge pull request #1086 from BlackJulySnow/main
feat: add extra models support for API profiles
2026-04-25 12:07:01 -04:00
Tam Nhu Tran bc16c5168c fix(ui/profiles): latch extraModels touch state for explicit-clear
The previous fix used react-hook-form's `dirtyFields.extraModels` to
gate forwarding of the empty value. RHF compares each value to its
`defaultValues` entry, so typing "x" and erasing back to "" reverts
the dirty flag to false — making it impossible to clear a saved
ANTHROPIC_EXTRA_MODELS through the dashboard.

Track a local boolean that latches true on the first onChange and
resets when the dialog closes. The latch survives a "type then
delete" round-trip, so the empty-string delete signal still reaches
the server, while a never-touched field still gets skipped to
preserve the existing saved value.
2026-04-25 12:00:50 -04:00
Tam Nhu Tran 9122f68dd4 fix(ui/profiles): preserve ANTHROPIC_EXTRA_MODELS on untouched edit-dialog save
The edit dialog cannot pre-populate `extraModels` from the existing
profile (the Profile type carries no env data), so the field always
opens blank in edit mode. Forwarding that blank value unconditionally
clobbered any saved ANTHROPIC_EXTRA_MODELS, since the PUT route treats
an empty string as a delete signal.

Track react-hook-form's `dirtyFields.extraModels` and only include the
field in the update payload when the user actually touched it. Typing
then clearing still marks the field dirty, so the explicit-clear UX
keeps working.
2026-04-25 11:45:51 -04:00
B1GGersnow 2915ab0c40 feat: add extra models support for API profiles
Add ANTHROPIC_EXTRA_MODELS env var to allow each API profile to
configure additional models alongside the primary ANTHROPIC_MODEL.
These are synced to CLIProxy config.yaml during ccs cliproxy sync.

- profile-mapper.ts: parse ANTHROPIC_EXTRA_MODELS on sync
- profile-writer.ts: write extra models to settings.json
- shared.ts + create-command.ts: --extra-models CLI flag
- profile-routes.ts + route-helpers.ts: REST API support
- profile-dialog.tsx + api-client.ts: frontend input
2026-04-25 03:20:29 +08:00
Tam Nhu Tran 4efd61ee34 feat: add gpt-5.5 to codex model catalogs 2026-04-24 10:30:59 -04:00
Tam Nhu Tran 5ff0370c1c chore: merge origin/dev into pr-1061 fix branch 2026-04-22 22:38:20 -04:00
Tam Nhu Tran c24033dc6b fix(browser): preserve opt-in browser settings and env isolation 2026-04-22 22:35:02 -04:00
Kai (Tam Nhu) TranandGitHub 142381078e Merge pull request #1069 from sgaluza/feat/opus-4-7-adaptive-thinking
fix(cliproxy): use adaptive thinking for Opus 4.7 + add 'max' level
2026-04-22 22:03:21 -04:00
Tam Nhu Tran b3bc17639c fix(ui): surface the max thinking level in settings and help 2026-04-22 21:43:32 -04:00
Tam Nhu Tran 254abd504f fix(cliproxy): keep provider sections consistent for variants 2026-04-22 20:02:54 -04:00
Tam Nhu Tran f6c86b79fc feat(cliproxy): separate core and plus provider sections 2026-04-22 19:51:20 -04:00