Commit Graph
3789 Commits
Author SHA1 Message Date
Tam Nhu Tran 0cf4ad7b48 refactor(dispatcher): extract bootstrap and pre-dispatch handlers from ccs.ts
Phases 2+3 of #1165. Extracts main() bootstrap + pre-dispatch handler
chain into focused dispatcher modules:

- src/dispatcher/cli-argument-parser.ts (+138 LOC):
  bootstrapAndParseEarlyCli + DispatcherBootstrap. Encapsulates UI init,
  --config-dir parse/validate, cloud-sync warnings, completion command
  short-circuit, legacy cursor arg normalization, browser launch flag
  resolution, and native codex passthrough escape.
- src/dispatcher/pre-dispatch.ts (155 LOC):
  runPreDispatchHandlers. Wraps update check, root command router,
  provider help shortcut, copilot/cursor subcommand routing, first-time
  install hint. Returns boolean consumed signal.
- New tests: 12 + 7 covering both modules.

Adapter registration intentionally stays in main() — singleton wiring
with no arg dependency; folding it into bootstrap would conflate
concerns. ccs.ts: 1475 -> 1262 LOC (-213). Behavior unchanged; full
suite passes 1824/1824.

Refs #1165
2026-05-02 23:27:05 -04:00
Tam Nhu Tran f759cfeaaa refactor(dispatcher): scaffold src/dispatcher/ and extract pure helpers from ccs.ts
Phase 1 of #1165. Pure code-motion: moves top-level helpers out of the
1775-LOC CLI entry point into focused dispatcher modules. Zero
behavior change, zero main() changes.

- src/dispatcher/cli-argument-parser.ts (199 LOC):
  DetectedProfile, RuntimeReasoningResolution, NATIVE_CLAUDE_EFFORT
  constants, detectProfile, normalizeLegacyCursorArgs,
  printCursorLegacySubcommandDeprecation, resolveRuntimeReasoningFlags,
  normalizeCodexRuntimeReasoningOverride,
  exitWithRuntimeReasoningFlagError, normalizeNativeClaudeEffortArgs,
  shouldNormalizeNativeClaudeEffort,
  shouldPassthroughNativeCodexFlagCommand,
  getNativeCodexPassthroughArgs.
- src/dispatcher/environment-builder.ts (125 LOC):
  resolveCodexRuntimeConfigOverrides, refreshUpdateCache,
  showCachedUpdateNotification, resolveNativeClaudeLaunchArgs.
- src/dispatcher/target-executor.ts (56 LOC):
  ProfileError, execNativeCodexFlagCommand.

ccs.ts: 1775 -> 1475 LOC (-300). Cleaned up 8 now-orphaned imports.
Behavior unchanged; full suite passes 1824/1824.

Refs #1165
2026-05-02 22:49:45 -04:00
github-actions[bot] 74898210f9 chore(release): 7.76.0-dev.1 2026-05-01 02:23:06 -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
semantic-release-bot 66865127d7 chore(release): 7.76.0 [skip ci]
## [7.76.0](https://github.com/kaitranntt/ccs/compare/v7.75.0...v7.76.0) (2026-05-01)

### Features

* add native Claude effort override ([e5fe86f](https://github.com/kaitranntt/ccs/commit/e5fe86f520f313632a8627ca70f551dd5bcb665b))
* **auth,commands:** instrument oauth handler, profile registry, and doctor pipeline ([bf87594](https://github.com/kaitranntt/ccs/commit/bf8759460df0828ddec1138866dae3ef86ff2a42)), closes [#1141](https://github.com/kaitranntt/ccs/issues/1141) [#1138](https://github.com/kaitranntt/ccs/issues/1138)
* **logging:** add structured contract, ALS context, stage helpers, and redaction coverage ([7a22e89](https://github.com/kaitranntt/ccs/commit/7a22e89046ecb4af79291ecd3b4c885275ab5787)), closes [#1141](https://github.com/kaitranntt/ccs/issues/1141) [#1138](https://github.com/kaitranntt/ccs/issues/1138)
* **providers:** instrument copilot, cursor, and glmt across daemons and executors ([1ff4329](https://github.com/kaitranntt/ccs/commit/1ff4329ee4b58e68648cd1f331f3dd64d4eb10df)), closes [#1141](https://github.com/kaitranntt/ccs/issues/1141) [#1138](https://github.com/kaitranntt/ccs/issues/1138)
* **proxy,cli:** emit lifecycle stages with x-ccs-request-id propagation ([4700727](https://github.com/kaitranntt/ccs/commit/47007279156545f81c615824065a0094aafa07d0)), closes [#1141](https://github.com/kaitranntt/ccs/issues/1141) [#1138](https://github.com/kaitranntt/ccs/issues/1138)
* **targets,management:** instrument adapter spawn lifecycle and instance manager ([8afee34](https://github.com/kaitranntt/ccs/commit/8afee344e1b1e8f45d029affc011e229e069b949)), closes [#1141](https://github.com/kaitranntt/ccs/issues/1141) [#1138](https://github.com/kaitranntt/ccs/issues/1138)
* **ui:** align logs page visual language with dashboard markers ([e04598e](https://github.com/kaitranntt/ccs/commit/e04598eef777746d1898d6ddc22eb527c9badcd3)), closes [#1138](https://github.com/kaitranntt/ccs/issues/1138) [#1141](https://github.com/kaitranntt/ccs/issues/1141) [#1142](https://github.com/kaitranntt/ccs/issues/1142)
* **ui:** hide dashboard self-polling internals via default filter ([4a77251](https://github.com/kaitranntt/ccs/commit/4a772510215a0e8081853eee6c32d1cb8e47ec9b)), closes [#1138](https://github.com/kaitranntt/ccs/issues/1138) [#1141](https://github.com/kaitranntt/ccs/issues/1141) [#1142](https://github.com/kaitranntt/ccs/issues/1142)
* **ui:** redesign dashboard logs page with virtualized 3-pane shell ([ae3240d](https://github.com/kaitranntt/ccs/commit/ae3240d4c8ae540cfcd354a662eaf0a7979a1ded)), closes [#1141](https://github.com/kaitranntt/ccs/issues/1141) [#1142](https://github.com/kaitranntt/ccs/issues/1142) [#1138](https://github.com/kaitranntt/ccs/issues/1138) [#1141](https://github.com/kaitranntt/ccs/issues/1141)
* **ui:** show split Claude quota bars ([a8b686d](https://github.com/kaitranntt/ccs/commit/a8b686d643f38bf11efb83f1753442783ebed2c9))

### Bug Fixes

* address red-team review findings — cache aliasing, jitter cap, cause shadowing ([9bb1bdb](https://github.com/kaitranntt/ccs/commit/9bb1bdbad960140db177e1cec6a30ea56b97263e))
* **ci:** align release sync with protected dev checks ([0381fa9](https://github.com/kaitranntt/ccs/commit/0381fa9b52cc6ffb49c91b528de0f9ed7c182b9f))
* **ci:** align stable release runner ([4458774](https://github.com/kaitranntt/ccs/commit/4458774d5c0413b70001402100c366f6fc87ade2))
* **ci:** invoke semantic-release through bun x ([63a10e0](https://github.com/kaitranntt/ccs/commit/63a10e0e8d7f62e209828e41194ad16cf86fbc5c))
* **cliproxy:** clear stale cleanup timer and fix session/tunnel edge cases ([20c2005](https://github.com/kaitranntt/ccs/commit/20c2005df965e34f68af36734008ee043857db28))
* **cliproxy:** correct relative import paths in colocated tests ([273214d](https://github.com/kaitranntt/ccs/commit/273214d1665f367a03490ec600cc52dc70058ca1))
* **cliproxy:** exclude colocated tests from tsconfig and eslint ([c3c8cb7](https://github.com/kaitranntt/ccs/commit/c3c8cb7a8276a001c7d9603fade5484f94d5fad3))
* **cliproxy:** fix base-config-loader __dirname path and stale mock.module paths ([31dc186](https://github.com/kaitranntt/ccs/commit/31dc18657ce7140a7ef02c6219e61b859c110039))
* **cliproxy:** handle all invalid prefixes and reverse-order collisions ([6633bf4](https://github.com/kaitranntt/ccs/commit/6633bf456bcb9095a59e05e08741810af6030f39))
* **cliproxy:** sanitize invalid tool name chars and disambiguate collisions ([218d0cf](https://github.com/kaitranntt/ccs/commit/218d0cf6c63e2d4a5e0b56a5ae061de4b6e861dc))
* **cliproxy:** update remaining stale imports in non-colocated tests ([2c817fa](https://github.com/kaitranntt/ccs/commit/2c817fae484b762a62a79737efb4c84a91c87988))
* **config-facade:** mtime-based staleness detection for cache ([1e5580a](https://github.com/kaitranntt/ccs/commit/1e5580a30ae4c2eef64975b688b13440cb2d3b07))
* **proxy:** avoid leaking tool_result image URLs ([83c16e2](https://github.com/kaitranntt/ccs/commit/83c16e216a2be549306434a1afa317844337b607))
* **proxy:** shape direct OpenAI reasoning chat payloads ([d9ace60](https://github.com/kaitranntt/ccs/commit/d9ace607e58caafd71224e02ed9f297b7dcacecb))
* **proxy:** stringify tool_result images for OpenAI upstreams ([f6bb31c](https://github.com/kaitranntt/ccs/commit/f6bb31c95657d219373ec09009e0f7bed991c439))
* remove raw write re-exports from facade (cache bypass) ([6d266fc](https://github.com/kaitranntt/ccs/commit/6d266fc7e89d7e7ddee3ec4235152e9a9bcaba0d)), closes [#1150](https://github.com/kaitranntt/ccs/issues/1150)
* round 2 red-team fixes — onRetry safety, validation, barrel ([18e865e](https://github.com/kaitranntt/ccs/commit/18e865ea364de0f7c811d447bacaf644d98f10d2))
* round 3 red-team — test false-positive, dead code, ([b8ed36e](https://github.com/kaitranntt/ccs/commit/b8ed36e3705f9e6795a99864610727026be5fc52))
* **ui:** align logs row and detail panel via shared accessors ([d5b14be](https://github.com/kaitranntt/ccs/commit/d5b14bec1c48b2f97c2fbadcc39124c5c54ddec8)), closes [#1138](https://github.com/kaitranntt/ccs/issues/1138) [#1141](https://github.com/kaitranntt/ccs/issues/1141) [#1142](https://github.com/kaitranntt/ccs/issues/1142)
* **ui:** coalesce leaves only when truly adjacent in original stream ([871b682](https://github.com/kaitranntt/ccs/commit/871b6826f786b08f89caa86f7aff439594c9fdf7)), closes [#1138](https://github.com/kaitranntt/ccs/issues/1138) [#1151](https://github.com/kaitranntt/ccs/issues/1151)
* **ui:** drop dedicated stage column; render stage chip inline in message ([7f086c8](https://github.com/kaitranntt/ccs/commit/7f086c8685cf1ec3f4dd44bedc96fbd5c6928164))
* **ui:** import MouseEvent type explicitly in logs-row ([6f1396c](https://github.com/kaitranntt/ccs/commit/6f1396cf1e99dfac460040b0a6a3f5d7f72bec5d)), closes [#1138](https://github.com/kaitranntt/ccs/issues/1138) [#1151](https://github.com/kaitranntt/ccs/issues/1151)
* **ui:** improve split quota bar readability ([476c6d8](https://github.com/kaitranntt/ccs/commit/476c6d827fbdbca8d8aa8535c9b6c894bb84dd1c))
* **ui:** include message in coalesce key so distinct entries stay visible ([a465e3f](https://github.com/kaitranntt/ccs/commit/a465e3fec184464042c8ae8d5e16e9045ef56e52)), closes [#1138](https://github.com/kaitranntt/ccs/issues/1138) [#1151](https://github.com/kaitranntt/ccs/issues/1151)
* **ui:** include source in trace child coalesce key ([75cdc02](https://github.com/kaitranntt/ccs/commit/75cdc02c1f4a9881b1d64e8d6608da15d74d6378)), closes [#1138](https://github.com/kaitranntt/ccs/issues/1138) [#1151](https://github.com/kaitranntt/ccs/issues/1151)
* **ui:** include stage in leaf coalesce key ([e7058b6](https://github.com/kaitranntt/ccs/commit/e7058b6b6da82a1bc54fa43f437e53748ba78c20)), closes [#1138](https://github.com/kaitranntt/ccs/issues/1138) [#1151](https://github.com/kaitranntt/ccs/issues/1151)
* **ui:** make logs row keyboard-accessible without nested interactive markup ([b7cfbd1](https://github.com/kaitranntt/ccs/commit/b7cfbd14e2c7057270f3e8b482c73208fcb1ca47)), closes [#1138](https://github.com/kaitranntt/ccs/issues/1138) [#1151](https://github.com/kaitranntt/ccs/issues/1151)
* **ui:** make trace chevron actually collapse auto-expanded traces ([04ddc33](https://github.com/kaitranntt/ccs/commit/04ddc33518d43302e650283a3d7be43cf616dd9d)), closes [#1138](https://github.com/kaitranntt/ccs/issues/1138) [#1151](https://github.com/kaitranntt/ccs/issues/1151)
* **ui:** only show "Copied" feedback when clipboard write succeeds ([39ec84a](https://github.com/kaitranntt/ccs/commit/39ec84a8a9a78489565c27e1e599d8383291400a)), closes [#1138](https://github.com/kaitranntt/ccs/issues/1138) [#1151](https://github.com/kaitranntt/ccs/issues/1151)
* **ui:** remove intra-trace coalescing — preserve every stage for inspection ([2ddc5d5](https://github.com/kaitranntt/ccs/commit/2ddc5d5afd4cdb2e6a063180f47469a5298460fc)), closes [#1138](https://github.com/kaitranntt/ccs/issues/1138) [#1151](https://github.com/kaitranntt/ccs/issues/1151)
* **ui:** reserve leading chevron column so trace and leaf rows align ([0dfb7b8](https://github.com/kaitranntt/ccs/commit/0dfb7b85833aec6b26e0ae02452ecc19a9494629)), closes [#1138](https://github.com/kaitranntt/ccs/issues/1138)
* **ui:** reserve stage column on every row for consistent alignment ([40cc62a](https://github.com/kaitranntt/ccs/commit/40cc62a67f03a86f163d679ae15ef0df78e6e248)), closes [#1138](https://github.com/kaitranntt/ccs/issues/1138) [#1151](https://github.com/kaitranntt/ccs/issues/1151)

### Documentation

* **config-facade:** clarify cache coherence contract ([2290a1d](https://github.com/kaitranntt/ccs/commit/2290a1dc5a575c0875524571c64ee24968851855)), closes [#1150](https://github.com/kaitranntt/ccs/issues/1150)
* **logging:** add structured contract reference and bump Node engines to 18+ ([c0c856a](https://github.com/kaitranntt/ccs/commit/c0c856af988277d2d79b869e1be98c5261d8c7c0)), closes [#1141](https://github.com/kaitranntt/ccs/issues/1141) [#1138](https://github.com/kaitranntt/ccs/issues/1138)

### Code Refactoring

* **cliproxy:** flatten module structure and colocate tests ([#1135](https://github.com/kaitranntt/ccs/issues/1135)) ([1c72b4b](https://github.com/kaitranntt/ccs/commit/1c72b4b8d5bf783bc3c6306d687065ac8eac9922))
* **config:** add config-loader-facade with memoization ([1e9a7f3](https://github.com/kaitranntt/ccs/commit/1e9a7f3fa01e40ab569932e66ce37f8653bf8c97))
* **config:** reorganize unified-config-types into schemas directory ([51df0ee](https://github.com/kaitranntt/ccs/commit/51df0ee55b52ecc858544ec8d8ff7e7932db0f11))
* **errors:** add RetryableError and retry-strategy utility ([d089ab0](https://github.com/kaitranntt/ccs/commit/d089ab06c2c007e4a46173efcac9ea9ff23f0bb5))
* extract plugin path normalizer ([3330229](https://github.com/kaitranntt/ccs/commit/333022968689a5584347c1fa66cdf18ee0a3a7b4))

### Tests

* include colocated cliproxy tests in buckets ([33a1553](https://github.com/kaitranntt/ccs/commit/33a1553431afdcca1a5c1fca54aff8da8d8bb05e))
* **logging:** add cross-stage requestId correlation integration test in slow bucket ([c0a019b](https://github.com/kaitranntt/ccs/commit/c0a019bf7e83287dddfb333633941d3142541778)), closes [#1141](https://github.com/kaitranntt/ccs/issues/1141) [#1138](https://github.com/kaitranntt/ccs/issues/1138)
* **proxy:** assert tool_result image URLs stay redacted ([2c0f9c4](https://github.com/kaitranntt/ccs/commit/2c0f9c41ff1fff94c35e93535b9a8343ef7ce953))
* **ui:** cover logs page redesign with virtuoso-mocked render ([a10e570](https://github.com/kaitranntt/ccs/commit/a10e570310c2655553cd62dae1bf6d84478f8090)), closes [#1142](https://github.com/kaitranntt/ccs/issues/1142) [#1138](https://github.com/kaitranntt/ccs/issues/1138)
* **ui:** cover trace-coalesce, leaf-coalesce, and stage-hint helpers ([6ada2b2](https://github.com/kaitranntt/ccs/commit/6ada2b243e339067071fe1c00d41a57581c3e403)), closes [#1138](https://github.com/kaitranntt/ccs/issues/1138) [#1151](https://github.com/kaitranntt/ccs/issues/1151)
2026-05-01 01:15:14 -04:00
Kai (Tam Nhu) TranandGitHub a621cf3de7 Merge pull request #1156 from kaitranntt/dev
fix(ci): restore stable release semantic-release invocation
2026-05-01 01:12:17 -04:00
github-actions[bot] 4885a4647f chore(release): 7.75.0-dev.12 2026-05-01 01:02:53 -04:00
Tam Nhu Tran 63a10e0e8d fix(ci): invoke semantic-release through bun x 2026-05-01 00:55:53 -04:00
Kai (Tam Nhu) TranandGitHub 241ec16719 Merge pull request #1155 from kaitranntt/dev
feat: promote dev to main
2026-05-01 00:51:07 -04:00
github-actions[bot] 6035f6354d chore(release): 7.75.0-dev.11 2026-04-30 22:46:19 -04:00
Kai (Tam Nhu) TranandGitHub 0b31d0ac2f Merge pull request #1154 from kaitranntt/kai/feat/1153-effort-session-override
feat: add native Claude effort override
2026-04-30 22:42:49 -04:00
Tam Nhu Tran e5fe86f520 feat: add native Claude effort override 2026-04-30 22:36:47 -04:00
github-actions[bot] ec9d0982d8 chore(release): 7.75.0-dev.10 2026-04-30 17:18:53 -04:00
Kai (Tam Nhu) TranandGitHub bbf121d808 Merge pull request #1152 from kaitranntt/kai/feat/1138-logging-revamp
feat(logs): structured logging contract and dashboard logs page redesign (#1138)
2026-04-30 17:14:33 -04:00
Tam Nhu Tran 7bc1fbddb5 chore(pr): add force-UI evidence for integration PR #1152
Three light-theme captures of the merged integration branch (backend
#1141 + UI #1142 + final-touches #1151) at the dev-merge commit:

1. 01-overview-mock.png — full logs page with ?mock=logs:
   LOGS.STREAM marker, Live activity title, ENTRIES/TRACES/ERRORS
   stat strip, trace grouping with inline stage chips, populated
   detail panel showing all structured fields.
2. 02-real-backend-clean.png — real backend with default
   Hide-dashboard-internals filter active: clean empty state.
3. 03-mobile.png — 390x844 responsive layout.
2026-04-30 17:01:40 -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 3b15082ea4 Merge remote-tracking branch 'origin/dev' into kai/feat/1138-logging-revamp 2026-04-30 16:47:28 -04:00
Kai (Tam Nhu) TranandGitHub 92761903eb Merge pull request #1151 from kaitranntt/kai/feat/1138-final-touches
feat(ui): logs page final-touches audit fixes (#1138)
2026-04-30 16:44:36 -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
github-actions[bot] 9ce485e8d0 chore(release): 7.75.0-dev.9 2026-04-30 16:24:24 -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
Kai (Tam Nhu) TranandGitHub 769ebbd43b Merge pull request #1150 from kaitranntt/kai/refactor/1135-structural-maintainability
refactor: Phase 2 structural maintainability (#1135)
2026-04-30 16:20:30 -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 1e5580a30a fix(config-facade): mtime-based staleness detection for cache
getCachedConfig() now checks config file mtime on each call.
If external code writes via unified-config-loader directly,
the facade detects the file change and re-reads from disk
automatically. Resolves PR-Agent "Stale Cache" finding.
2026-04-30 15:56:50 -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 2290a1dc5a docs(config-facade): clarify cache coherence contract
Document that uncached reads (loadOrCreateUnifiedConfig)
bypass the cache and callers should use
invalidateConfigCache() if they mix uncached reads
with cached writes outside the facade. Resolves
remaining PR-Agent concern from #1150 comment.
2026-04-30 15:44:34 -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
Tam Nhu Tran 6d266fc7e8 fix: remove raw write re-exports from facade (cache bypass)
PR-Agent #1150 review flagged that re-exporting
saveUnifiedConfig/mutateUnifiedConfig/updateUnifiedConfig
allows callers to bypass the cache. Only export the
cache-coherent wrappers (saveConfig/mutateConfig/updateConfig).
Raw functions still available via direct import from
unified-config-loader if needed.

- Remove raw write re-exports from facade
- Add test verifying raw writes are NOT exported
- Add test verifying cache-coherent wrappers ARE exported
2026-04-30 15:37:17 -04:00
Tam Nhu Tran b7cfbd14e2 fix(ui): make logs row keyboard-accessible without nested interactive markup
PR-Agent flagged that the row's copy-requestId widget was a
`<span role="button" tabIndex={-1}>` nested inside a row `<button>`.
Two issues:
1. Nested interactive elements inside a `<button>` is invalid HTML.
2. `tabIndex={-1}` made the copy widget unreachable via keyboard, so
   the new affordance was effectively mouse-only.

Convert the row's outer element from `<button>` to `<div role="row"
tabIndex={0}>` with `onKeyDown` for Enter/Space → select. Now the row
itself is keyboard-focusable and the copy widget can be a real
`<button>` with focus-visible styling — keyboard users can Tab to it
and Enter to copy the requestId.

Refs #1138, #1151
2026-04-30 15:26:29 -04:00
Tam Nhu Tran a465e3fec1 fix(ui): include message in coalesce key so distinct entries stay visible
PR-Agent flagged that the leaf and trace-child coalesce keys collapsed
on `(event, module, level, requestId, source)` which merges adjacent
entries that share that tuple but report different content (e.g.
`User logged in: alice` vs `User logged in: bob` would appear as a
single `× 2` row, hiding bob).

Add `message` to both coalesce keys so distinct content stays
distinct. Skip `latencyMs` and `metadata` — those drift per request
even on truly redundant polls and would defeat the dedup the feature
exists for.

Refs #1138, #1151
2026-04-30 15:26:06 -04:00
Tam Nhu Tran b8ed36e370 fix: round 3 red-team — test false-positive, dead code,
edge-case coverage

- Fix false-positive test: use CCSError with recoverable=false
  instead of plain Error (never exercised recoverable check)
- Remove redundant retryableCheck ?? defaultRetryableCheck
  (destructuring already defaults)
- Add test: retryAfter > maxDelayMs (server directive wins)
- Add test: baseDelayMs=0 produces immediate retries
- Add test: onRetry not called when maxRetries=0
2026-04-30 15:16:07 -04:00
Tam Nhu Tran 18e865ea36 fix: round 2 red-team fixes — onRetry safety, validation, barrel
- retry-strategy: wrap onRetry in try/catch to prevent
  callback errors from aborting retries
- retry-strategy: validate baseDelayMs >= 0
- retry-strategy: update JSDoc to clarify
  retryAfter/maxDelayMs interaction
- errors/index.ts: add ValidationError to barrel
- Tests: onRetry throw test, negative baseDelayMs test
2026-04-30 14:59:44 -04:00
Tam Nhu Tran 0dfb7b8583 fix(ui): reserve leading chevron column so trace and leaf rows align
Trace rows pushed the TIME column ~30px right because the expand chevron
was an inline flex child while leaf rows had nothing in that position.
Result: every column drifted right whenever a trace row was visible.

Reserve a 16px slot at the start of every row (header + leaf + trace).
Leaf rows render an empty span; trace rows render the chevron centered
inside the slot. All columns now share the same x-coordinates regardless
of row type.

Refs #1138
2026-04-30 14:56:32 -04:00
Tam Nhu Tran 9bb1bdbad9 fix: address red-team review findings — cache aliasing, jitter cap, cause shadowing
- config-loader-facade: use structuredClone() to prevent cache aliasing
- retry-strategy: re-cap delay after jitter to enforce maxDelayMs boundary
- retry-strategy: wire retryAfter from RetryableError into delay computation
- retry-strategy: guard against negative maxRetries
- error-types: rename RetryableError.cause to originalError to avoid shadowing Error.cause
- Tests updated for all fixes
2026-04-30 14:37:28 -04:00
Tam Nhu Tran 2d95e40ff9 chore(pr): pin force-UI evidence directory to PR #1151
Refs #1138
2026-04-30 14:33:50 -04:00
Tam Nhu Tran 2c0bbae943 chore(pr): add force-UI evidence for #1138 final-touches audit fixes
Light-theme captures from Playwright MCP against `bun run dev` with
`?mock=logs` deterministic fixture and real backend (no mock):

1. `01-after-overview-mock.png` — LOGS.STREAM marker, Live activity
   title, ENTRIES/TRACES/ERRORS stat strip, populated detail panel
2. `02-after-real-backend-clean.png` — real backend with default filter
   active: 0 entries because all are dashboard internals; no noise
3. `03-hide-internals-toggle.png` — advanced filters showing the new
   labelled toggle with red callout
4. `04-internals-shown-with-coalesce.png` — toggle off: dashboard
   internals visible but a 149-stage trace coalesces to 3 rows; detail
   panel shows full requestId UUID + module (C1 fix proven)
5. `05-after-mobile.png` — 390x844: header marker + title + stat strip
   wrap, expanded trace renders cleanly

Asset directory will be renamed from PLACEHOLDER_PR to actual PR number;
HEAD SHA placeholder pinned after final commit.

Refs #1138, #1141, #1142
2026-04-30 14:31:57 -04:00
Tam Nhu Tran 4a77251021 feat(ui): hide dashboard self-polling internals via default filter
On real backend, the logs page was drowning in dashboard self-polling
noise — every `/api/logs` poll emitted a 149-stage `web-server:http`
trace, burying real provider activity.

- New workspace state `hideDashboardInternals` defaults ON. Entries
  whose `source` matches `/^web-server:/i` are filtered client-side
  before they reach the list.
- Toggle exposed in advanced filters as a labelled checkbox/switch with
  a one-line description, so users can opt in to see internals when
  debugging the dashboard itself.
- `clearAdvancedFilters` resets the toggle back to ON to keep the
  default signal-clean experience.
- Header stat strip (entries / traces / errors) wired through the shell.

Backend-side `web-server:*` instrumentation stays intact (still useful
for ops debugging) — just hidden from the user-facing log feed by
default.

Refs #1138, #1141, #1142
2026-04-30 14:31:32 -04:00
Tam Nhu Tran e04598eef7 feat(ui): align logs page visual language with dashboard markers
Logs page was visually disconnected from the rest of the dashboard. Health
uses ornamental `HEALTH.ATTENTIONREQUIRED` markers, Home uses `LIVE
Account Monitor` + stat cards. Logs shipped with a 14px h1 + clinical
table that felt like a different product.

- Header now opens with a `LOGS.STREAM` mono-uppercase marker matching
  the dashboard's `HEALTH.X` style, plus a 16px "Live activity" title
  and a status pill.
- Below the header, a stat strip mirrors the home page's monitor layout:
  ENTRIES / TRACES / ERRORS counters, errors highlighted red when >0.
- Trace row + child row font sizes lifted from 11px to 12-13px;
  request-id column widened to 112px to match the standalone-row table.
- Stage-hint fallback derived from event names so the trace timeline
  still renders meaningful chips when backend entries lack an explicit
  `stage` field (e.g. dashboard self-polling).
- Intra-trace coalesce: identical consecutive child rows collapse to a
  single row with `× N` badge so a 149-stage self-poll trace renders as
  3 rows of signal instead of 149 rows of noise.

Refs #1138, #1141, #1142
2026-04-30 14:30:54 -04:00
Tam Nhu Tran cb8b34b36d Merge branch 'kai/refactor/1135-item2-config-loader-facade' into kai/refactor/1135-structural-maintainability 2026-04-30 14:10:42 -04:00
Tam Nhu Tran b5fae5e8c9 Merge branch 'kai/refactor/1135-item9-error-hierarchy-retry' into kai/refactor/1135-structural-maintainability 2026-04-30 14:10:30 -04:00
Tam Nhu Tran b7aea78512 Revert "Revert "refactor(config): reorganize unified-config-types into schemas directory""
This reverts commit 06bce198eb.
2026-04-30 14:07:32 -04:00
Tam Nhu Tran 0868e92bb1 Revert "Revert "refactor(config): reorganize unified-config-types into schemas directory""
This reverts commit 06bce198eb.
2026-04-30 14:05:33 -04:00
Tam Nhu Tran 1e9a7f3fa0 refactor(config): add config-loader-facade with memoization
Single import path for all config loading. Re-exports all 26 functions
from unified-config-loader and 4 from config-manager. Adds memoization
for loadOrCreateUnifiedConfig via getCachedConfig() with automatic cache
invalidation on write operations (mutateConfig, updateConfig). Pure
structural refactor -- no existing imports modified.
2026-04-30 14:03:48 -04:00
Tam Nhu Tran 06bce198eb Revert "refactor(config): reorganize unified-config-types into schemas directory"
This reverts commit 51df0ee55b.
2026-04-30 13:57:08 -04:00
Tam Nhu Tran 51df0ee55b refactor(config): reorganize unified-config-types into schemas directory
Split the 1,128-line unified-config-types.ts into focused schema modules
under src/config/schemas/ for maintainability. Each file is under 200 LOC.

New schema files:
- version.ts: UNIFIED_CONFIG_VERSION constant
- auth.ts: AccountConfig, ProfileConfig, OAuthAccounts, CLIProxyAuthConfig, etc.
- cliproxy.ts: CLIProxyConfig, CompositeTierConfig, routing/safety types
- copilot-cursor.ts: CopilotConfig, CursorConfig + defaults
- proxy-server.ts: CliproxyServerConfig, GlobalEnvConfig, ImageAnalysisConfig
- quota.ts: QuotaManagementConfig + all quota types and defaults
- thinking.ts: ThinkingConfig + tier defaults
- channels.ts: OfficialChannelsConfig (Telegram, Discord, iMessage)
- websearch.ts: All WebSearch backend types (DuckDuckGo, Brave, Exa, etc.)
- browser.ts: BrowserConfig, BrowserClaudeConfig, BrowserCodexConfig
- logging.ts: LoggingConfig, PreferencesConfig
- unified-config.ts: UnifiedConfig interface, factory, type guard
- index.ts: Barrel re-export of all schema modules

unified-config-types.ts is now a thin backward-compatible barrel that
re-exports everything from schemas/index. All 67 existing imports across
the codebase continue to resolve unchanged.
2026-04-30 13:54:40 -04:00
Tam Nhu Tran d089ab06c2 refactor(errors): add RetryableError and retry-strategy utility
Extract retryable error class and reusable withRetry wrapper from
scattered retry logic in glmt-proxy and binary/downloader.
2026-04-30 13:46:33 -04:00