Commit Graph
819 Commits
Author SHA1 Message Date
Kai (Tam Nhu) TranandGitHub c12174db12 fix: gate auth monitor stats polling (#1421) 2026-05-30 14:08:53 -04:00
Kai (Tam Nhu) TranandGitHub aee322ea88 fix: compare cliproxy fork release suffixes (#1419) 2026-05-30 13:42:31 -04:00
Kai (Tam Nhu) TranandGitHub 5f1976f69c fix: add CLIProxy account reauthentication 2026-05-27 10:13:03 -04:00
Tam Nhu Tran bfa4c704eb fix(analytics): tighten top-bar layout (single-line trigger, grouped cluster, compact timestamp)
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.
2026-05-24 11:34:57 -04:00
Tam Nhu Tran 9130c7d869 fix(analytics): collapse profile-scope disclaimer into tooltip icon
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
2026-05-23 23:40:02 -04:00
Kai (Tam Nhu) TranandGitHub 6c0f7ac39c fix(dashboard): clear local control-panel management key (#1372) 2026-05-23 21:44:53 -04:00
Kai (Tam Nhu) TranandGitHub 58df9999db fix(ui-docs): remove third-party runtime assets from health report (#1349)
* fix(ui-docs): remove third-party runtime assets from health report

* style: apply prettier formatting
2026-05-23 16:57:08 -04:00
Kai (Tam Nhu) TranandGitHub b71fe5dd6e fix(codex-quota): guard feature label type in quota windows (#1346) 2026-05-23 16:55:55 -04:00
Tam Nhu Tran f1d655e425 feat: filter analytics by profile 2026-05-22 11:24:21 -04:00
Tam Nhu Tran 6569eed15b feat: support minimal codex effort aliases 2026-05-20 11:11:46 -04:00
Tam Nhu Tran 5c79df4311 fix(codex-auth): close remaining review gaps 2026-05-17 16:51:22 -04:00
Tam Nhu Tran 08fe63c626 fix(codex-auth): fail fast on missing active profile 2026-05-17 16:06:32 -04:00
Tam Nhu Tran 4e7d648967 fix(codex-auth): remove unused React import causing UI build failure 2026-05-17 14:57:45 -04:00
Tam Nhu Tran e99c4612a8 feat(codex-auth): add dashboard Auth Profiles tab + GET /api/codex/profiles
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
2026-05-17 14:45:35 -04:00
Tam Nhu Tran 8ad7653a2e feat(dashboard): add Korean language support
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
2026-05-14 19:14:13 -04:00
Tam Nhu Tran 15a1faf3ab fix(ui): handle TOML triple-quotes in arrays and AST-aware JSON keys
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.
2026-05-14 18:10:26 -04:00
Tam Nhu Tran a633ee0af4 fix(ui): skip TOML comments when scanning sensitive array values
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.
2026-05-14 17:57:06 -04:00
Tam Nhu Tran f404e52439 perf(ui): tighten sensitive-mask decoration scope and reveal selector
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.
2026-05-14 17:50:50 -04:00
Tam Nhu Tran bac51ce1ff fix(ui): honor TOML quoted keys and escaped quotes in sensitive masking
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.
2026-05-14 17:44:52 -04:00
Tam Nhu Tran eefb76214e fix(ui): mask multi-line sensitive values in CodeEditor
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.
2026-05-14 17:38:06 -04:00
Tam Nhu Tran 420494e0e0 fix(ui): make codex config.toml viewer selectable
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
2026-05-14 17:22:26 -04:00
Kai (Tam Nhu) TranandGitHub 4748c452bd fix(codex): self-heal ccsxp cliproxy provider (#1243) 2026-05-14 12:35:31 -04:00
Kai (Tam Nhu) TranandGitHub ac333dd1d5 fix: clarify CLIProxy setup actions
Make account setup the primary CLIProxy CTA, keep advanced variant creation secondary, and contain setup dialogs across narrow viewports.
2026-05-12 19:23:59 -04:00
Kai (Tam Nhu) TranandGitHub 5138741b5c fix(ui): keep codex toml tokens inline (#1219) 2026-05-12 07:51:59 -04:00
Kai (Tam Nhu) TranandGitHub ba761a0d1e fix(ui): wrap codex config highlight editor (#1217) 2026-05-11 21:58:55 -04:00
Kai (Tam Nhu) TranandGitHub e1777247b3 fix(ui): restore codex config highlighting (#1216) 2026-05-11 21:33:33 -04:00
Kai (Tam Nhu) TranandGitHub 225401ceca fix(ui): render codex config as exact text (#1215) 2026-05-11 20:43:26 -04:00
Kai (Tam Nhu) TranandGitHub 29da75c0d4 fix(cliproxy): explain headless Codex OAuth recovery
Closes #1213
2026-05-11 14:25:34 -04:00
Kai (Tam Nhu) TranandGitHub 248b6b735d Merge pull request #1200 from kaitranntt/kai/feat/1199-shared-resource-controls
feat(auth): add shared resource controls
2026-05-10 22:01:57 -04:00
Tam Nhu Tran 497bca8684 fix(ui): surface Plus OAuth credential diagnostics in Add Account dialog
When POST /api/cliproxy/auth/:provider/start-url returns 400
plus_oauth_credentials_missing or 502 plus_oauth_url_missing_client_id,
surface the server-provided human-readable message (env var names and
backend=original switch hint) instead of the raw error code. Error
propagates through the existing toast/inline-alert path in
add-account-dialog.tsx — no new component primitives.

Refs #1208
2026-05-10 21:55:08 -04:00
Kai (Tam Nhu) TranandGitHub 35346a981f fix(ui): keep profile dialog actions visible on small screens (#1204) 2026-05-09 14:20:06 -04:00
Tam Nhu Tran 8b34060294 fix(dashboard): show real shared plugin registry state 2026-05-09 03:18:20 -04:00
Tam Nhu Tran 2a422b3bd3 feat(dashboard): add shared resource controls 2026-05-09 02:29:08 -04:00
Kai (Tam Nhu) TranandGitHub 74d73748ee feat: support Codex fast service-tier aliases
* feat: support Codex fast service-tier aliases

* fix: send Codex fast tier as priority
2026-05-07 15:34:05 -04:00
Kai (Tam Nhu) TranandGitHub 19a50a8dd8 feat: deprecate GitHub Copilot compatibility surfaces (#1196) 2026-05-07 13:06:03 -04:00
Kai (Tam Nhu) TranandGitHub 8b681df455 fix: route Cursor auth through browser polling
Closes #1194
2026-05-07 11:25:17 -04:00
Kai (Tam Nhu) TranandGitHub be9effcce3 feat: clarify account history sync route (#1187)
* feat: clarify account history sync route

* fix: clarify shared context command examples

* fix: report missing bare profile settings
2026-05-05 13:33:04 -04:00
Tam Nhu Tran 58af9cd501 fix(ui): surface Claude Opus 4.7 in Claude picker 2026-05-05 11:38:00 -04:00
Kai (Tam Nhu) TranandGitHub 923683bf30 feat(cliproxy): route plus dashboard to maintained fork (#1173) 2026-05-03 13:01:04 -04:00
Kai (Tam Nhu) TranandGitHub 50b0ffba75 fix(cliproxy): refresh upstream model and quota surfaces (#1158)
* fix(cliproxy): refresh upstream model and quota surfaces

* test(cliproxy): cover codex legacy model fallback
2026-05-01 02:19:31 -04:00
Tam Nhu Tran 7f086c8685 fix(ui): drop dedicated stage column; render stage chip inline in message
Adding a separate STAGE column squeezed MESSAGE to 0px at the
default 22/52/26 panel split — fixed columns + gaps totalled more
than the list panel's available width.

Render the stage chip inline at the start of the MESSAGE column when
present, restoring the original 7-column grid. The bot's earlier
"extra cell mismatch" complaint is still satisfied because there's
no longer a row-only cell missing from the header.

Also tighten three fixed columns to give MESSAGE more breathing room
even on narrower saved panel layouts:
- Module 140 -> 120
- Latency 72 -> 64
- Request 112 -> 100
2026-04-30 16:59:02 -04:00
Tam Nhu Tran e7058b6b6d fix(ui): include stage in leaf coalesce key
PR-Agent flagged that the leaf coalesceKey omitted `stage`, so two
adjacent no-requestId logs differing only by stage (e.g. one logging
`route` and the next `dispatch`) would merge into a single `×2`
row, hiding a distinct entry.

Add `stage` to the coalesce tuple. New unit test asserts that two
leaves identical except for stage stay as separate rows.

Refs #1138, #1151
2026-04-30 16:31:31 -04:00
Tam Nhu Tran 2ddc5d5afd fix(ui): remove intra-trace coalescing — preserve every stage for inspection
PR-Agent flagged that the trace-child coalesce was hiding legitimate
repeated stage emissions: a request that retries an upstream call or
emits the same stage twice for any reason would show only the first
occurrence behind a `×N` badge, with subsequent attempts no longer
selectable or inspectable.

The original noise problem motivating intra-trace coalesce was the
149-stage `web-server:http` self-polling trace, but that's already
hidden by default via the `hideDashboardInternals` filter. Users who
opt in to see internals are deliberately debugging the dashboard and
SHOULD see all 149 stages — collapsing them defeats the opt-in.

Drop `coalesceChildren` entirely. Trace children render uncoalesced
so retries, duplicated stages, and multi-attempt traces stay
individually inspectable. Standalone-leaf coalesce stays — that's
the actual user-facing dedup the PR was about.

Tests: drop the 7 `coalesceChildren` cases; keep 16 covering
`deriveStageHint` and `deriveTraceGroups`.

Refs #1138, #1151
2026-04-30 16:28:42 -04:00
Tam Nhu Tran 6ada2b243e test(ui): cover trace-coalesce, leaf-coalesce, and stage-hint helpers
PR-Agent flagged "No relevant tests" each round. Add 23 unit tests
covering the pure-function surface introduced by this PR:

- deriveStageHint — explicit stage wins, fallback to last .-segment
  of event, 12-char cap, undefined when nothing meaningful.
- coalesceChildren — empty input, single child, adjacent identical
  collapse, distinct messages stay separate (round-1 fix), distinct
  sources stay separate (round-2 fix), distinct stages stay separate,
  interleaving breaks the run.
- deriveTraceGroups — empty input, lone leaf, requestId grouping,
  ts-asc child sort, group ts pinned to oldest child, adjacent leaf
  coalesce with collapsedRange, leaves split by trace stay distinct
  (round-3 fix), distinct messages stay distinct, reverse-chronological
  display sort, max-level + total-latency aggregates, original-input
  adjacency preserved despite display sort.

Refactor: coalesceChildren extracted from logs-trace-row.tsx into
derive-trace-groups.ts so it's testable as a pure function without
React rendering.

Refs #1138, #1151
2026-04-30 16:24:19 -04:00
Tam Nhu Tran 40cc62a67f fix(ui): reserve stage column on every row for consistent alignment
PR-Agent flagged that trace child rows rendered an extra stage-hint
cell while the header grid template only had 7 columns. Result: every
expanded child shifted module/message/latency/request rightward, and
the stage chip overlapped its neighbour in the trace timeline.

Add a dedicated 72px "Stage" column to the header grid template and
to every row variant. Standalone leaves and trace heads render an
empty span at the same width; trace children with stage hints render
the chip in that slot. Column edges now match across all row types.

Refs #1138, #1151
2026-04-30 16:09:50 -04:00
Tam Nhu Tran 04ddc33518 fix(ui): make trace chevron actually collapse auto-expanded traces
The first click on a trace's chevron did nothing visible when the
trace's child was the currently-selected entry. Root cause: `toggle`
only checked the `expanded` set; auto-expand kept re-injecting the
requestId so the row stayed open even after the user added it to
`expanded` (and oscillating subsequent clicks).

Replace the single `expanded` set with a tristate driven by two
sets — `userExpanded` (explicitly opened) and `userCollapsed`
(explicitly closed). Auto-expand only fires when the id is in
neither, so a click on an auto-expanded chevron now writes the
collapse intent to `userCollapsed` and the row collapses on the
first click.

Refs #1138, #1151
2026-04-30 15:58:48 -04:00
Tam Nhu Tran 871b6826f7 fix(ui): coalesce leaves only when truly adjacent in original stream
PR-Agent flagged that the previous derive-trace-groups split entries
into trace and leaf buckets *before* coalescing leaves. That meant two
identical no-requestId entries separated by other rows in the real
stream would still merge into a single `×N` row, hiding signal.

Walk `entries` in input order with single-pass coalescing: a leaf
only extends the previous leaf when no other entry (trace child or
otherwise) appeared between them. Trace children still gather across
interleaving since they're identified by `requestId`. Group children
get sorted ts-ascending for trace-timeline display, with the group's
positional ts pinned to the oldest child for the reverse-chrono
display sort.

Refs #1138, #1151
2026-04-30 15:45:02 -04:00
Tam Nhu Tran 6f1396cf1e fix(ui): import MouseEvent type explicitly in logs-row
PR-Agent flagged that `React.MouseEvent` referenced an unimported
`React` namespace; in stricter TypeScript builds this would fail
typecheck. Import the type alias from `react` directly.

Refs #1138, #1151
2026-04-30 15:44:36 -04:00
Tam Nhu Tran 39ec84a8a9 fix(ui): only show "Copied" feedback when clipboard write succeeds
PR-Agent re-review flagged that `copyText()` swallowed clipboard
errors but the row's `setJustCopied(true)` always fired regardless,
so users in insecure contexts (or with denied clipboard permission)
saw a fake success indicator while nothing was actually copied.

Make `copyText()` return a boolean and gate the "Copied" UI state
on it. When the clipboard write fails, the button stays in its idle
state and the user can retry rather than being misled.

Refs #1138, #1151
2026-04-30 15:37:50 -04:00
Tam Nhu Tran 75cdc02c1f fix(ui): include source in trace child coalesce key
PR-Agent re-review flagged that adjacent trace rows from different
services with the same event/message/stage/level/module would still
merge because `source` was missing from the coalesce key. A request
that fans out across multiple services would lose the second service's
row behind a `× 2` badge.

Add `source` to the trace child coalesce key so each participating
service stays visible in the trace timeline.

Refs #1138, #1151
2026-04-30 15:37:21 -04:00