Commit Graph
7 Commits
Author SHA1 Message Date
DevvynandClaude Sonnet 5 2df9355367 fix(cli-registry): address PR B2 review — fix two test guards, drop unused catalogue
Two required fixes from Ark0N's review of #458:

1. test/frontend-cli-no-id-branching.test.ts's ALLOWED_BRANCHES keyed on
   <file>::<line>::<expression>. A single inserted line anywhere above an
   entry shifted every subsequent line number, so all 21 entries went stale
   simultaneously and the same 21 branches were reported as "new" — on a
   file six other open PRs also touch. Dropped the line number from the key
   (<file>::<expression>, matching the backend guard's own design), which
   collapses 21 line-keyed entries to 11 or-collapse where the same
   expression recurs at multiple call sites in the same file.

2. test/run-mode-ui.test.ts's terminal-ownership guard scanned method
   bodies via `^ {2}async (run[A-Za-z]*)\(\) \{$`, which matched the 8
   one-line run<Mode>() wrappers PR B2 introduced but not _runCliMode(mode),
   where the real logic (and the actual risk the guard exists to catch) now
   lives. Fixed the regex to `^ {2}async (_?run[A-Za-z]*)\(\w*\) \{$` and
   added _runCliMode to the sanity list. Same-class fix in
   test/opencode-resize.test.ts, which had the identical blind spot via
   runOpenCode.toString().

Both reproduced live before fixing (inserted the same comment line; added
this.terminal.clear() to _runCliMode) to confirm the bug, then confirmed
the fix catches it and the suite stays green otherwise.

Also resolves Open Question 2 by dropping window.__codemanCliCatalog
entirely: nothing consumed it, and a registry DECLARED_FOR_LATER field
costs nothing until read while an unconsumed script tag on every page
render is a different trade. Reverts Phase 1 cleanly — server.ts's
injection, shortBadge back in types.ts's DECLARED_FOR_LATER list and the
pinned guard test, and the three associated render-index-html.test.ts /
server-index-title.test.ts assertions.

Full gate: 405 files / 7717 tests / 0 failures (net unchanged), typecheck/
lint/format clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GuHtuPiHXdykq9T6rKQJ9n
2026-09-20 02:04:37 +08:00
DevvynandClaude Sonnet 5 cd64b0a3f7 feat(cli-registry): drive the run-menu frontend from the CLI catalogue (PR B2)
PR #380 (PR B) held back the frontend half of the CLI registry refactor,
explicitly deferring window.__codemanCliCatalog and making session-ui.js /
mobile-overview.js catalogue-driven as "PR B2".

- Inject window.__codemanCliCatalog in renderIndexHtml(), following the
  existing __codemanCustomModelClis pattern (escapeScriptJson-guarded,
  resolved per-request). Reading CliEntry.shortBadge here is what makes it
  genuinely read, so it drops out of types.ts's DECLARED_FOR_LATER list.
- Consolidate session-ui.js's 8 near-duplicate run<Mode>() launch functions
  (opencode/codex/gemini/antigravity/pi/omp/grok/deepseek) into one shared
  _runCliMode() plus a local RUN_MODE_LAUNCH config table. The 8 method
  names stay as thin wrappers (index.html calls them by name; tests assert
  on the name). Also collapses a duplicated 8-way isAltMode/isExternalCli
  OR-chain (same expression, copy-pasted twice in openSessionOptions) into
  one EXTERNAL_CLI_MODES check.
- Add test/frontend-cli-no-id-branching.test.ts, a guard scoped to
  session-ui.js/mobile-overview.js only (not the rest of src/web/public/,
  which stays explicitly out of scope per CLAUDE.md), mirroring the
  backend's own no-id-branching guard.

mobile-overview.js and the wiring of accent/echo/wheelForward/
keyboardAccessory were investigated and deliberately left alone: the first
is already a single, tested, gated table (not duplicated logic); the second
set belongs to terminal-ui.js/keyboard-accessory.js/styles.css, files
outside this PR's mandate.

Verified on a tmux-capable devbox (this sandbox has no tmux): full CI gate
at 405 files / 7717 tests / 0 failures, typecheck clean, 94 targeted tests
covering exact per-CLI wire-body shapes unmodified and passing, and a live
anti-vacuity check on the new guard (injected a real branch, confirmed it
fails, reverted, confirmed green).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GuHtuPiHXdykq9T6rKQJ9n
2026-09-19 21:16:31 +08:00
DevvynandClaude Sonnet 5 fed6582d3e fix(test): strip the custom-model Run-menu picker's injected script too
CI on PR #430 failed test/server-index-title.test.ts's byte-identity
check: renderIndexHtml now injects a second unconditional <script> before
</head> (window.__codemanCustomModelClis, added alongside the existing
__codemanCliAvailable one), and the test only knew to strip the older one
before comparing the rendered HTML against the raw template.

Strip both. Unlike __codemanCliAvailable (an object, historically injected
only where something resolved), the new one is a plain array injected
unconditionally, possibly empty, so it needs stripping on every machine,
not just one with CLIs installed.

Verified the two replace() calls compose correctly against the exact
strings server.ts actually produces (simulated in isolation; this box has
no tmux, so the real WebServer-backed test file cannot run here at all --
same environment gap noted throughout this PR's review).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RqZeHrRS6DYcGcGX2p9EwG
2026-09-16 07:01:23 +08:00
Codeman maintainer 5d2899907e fix(cli-gating): gate the tunnel button instead of deleting it, and cover antigravity
Follow-up to #200 and #201, which gate the welcome buttons and the run-mode
dropdown on whether the CLI is actually installed. Four corrections:

1. #200 also DELETED the Cloudflare Tunnel welcome button and the QR widget
   outright. Its rationale is right (offering a tunnel where cloudflared is not
   installed is a bad default) but the conclusion overshoots: the welcome QR is
   the whole scan-to-connect-from-your-phone flow, and deleting it left a large
   block of live tunnel code in settings-ui.js driving elements that no longer
   existed. Both are restored and the button is gated on cloudflared, which is
   what the stated rationale actually asks for. New cloudflared-resolver.ts
   mirrors the CLI resolvers, and TunnelManager now shares its search path so
   the button and the spawn can never disagree about where cloudflared lives.

2. Antigravity was missing from the run-mode gating, the one run mode LEAST
   likely to be installed. It slipped past because #201 predates it. Covered
   now, plus a static test that fails if a sixth mode reaches the dropdown
   without being gated, so the next one cannot slip the same way.

3. The per-surface fetches are replaced by the injected availability object
   already used for the Codex settings tab, so the codebase has one mechanism
   rather than two. The status routes buy nothing as a gating source: every
   resolver memoizes its PATH probe server-side, so a fetch is exactly as stale
   as an injected value while costing a round trip every time the dropdown opens
   and leaving the welcome buttons to flicker in after paint. The routes
   themselves stay, including the /api/claude/status that #200 adds.

4. Unknown availability now reads as AVAILABLE for run buttons. Both PRs hid the
   button on a failed fetch, so a blip left a working install with nothing to
   click; a genuinely missing CLI only ever produced an error toast. The Codex
   settings TAB keeps the opposite default, since hiding it costs nothing.

The dropdown query is also scoped to the menu: `.run-mode-option` is the class
the saved-dashboard and history rows use too, and a document-wide querySelector
would have found whichever came first in the DOM.

Fixes a latent environment-sensitivity in 816d900 while here: the index-title
test asserted the template was untouched apart from the title, which held only
on a machine with no codex installed.

Verified end-to-end against a real server on an isolated instance+socket, with
Playwright: gemini/codex hidden and claude/opencode/antigravity/shell shown,
matching this host, tunnel button back, Codex settings tab still hidden, no
console errors. Full test:ci sweep green (3902 tests).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 01:53:43 +02:00
arkonandClaude Opus 4.8 534712e50f fix(usage): address code-review findings in plan-usage telemetry
Review of the plan-usage chip feature (commits since 1.0.0) surfaced several
issues; this fixes all confirmed findings:

- HIGH: applyStatusLineConfig clobbered a user's hand-authored statusLine on
  the enable path (the isOurs guard only protected disable). Now bails out when
  an existing statusLine isn't ours, on both the enable and disable paths.
- MED: StatusTelemetrySchema used z.optional() (rejects null) on Claude's
  undocumented statusline fields — a single stray null 400'd the entire POST and
  silently killed the chip's data feed. Switched the modeled fields to .nullish().
- MED: dropping the Token Count / Show Cost header toggles left their features
  reading settings.showTokenCount/showCost, but saveAppSettings rebuilds settings
  fresh from the DOM, dropping those keys and resetting them to defaults on every
  save (re-enabling the token chip with no UI to turn it off). Preserve the prior
  stored preference.
- telemetrySignature keyed on contextUsedPercentage (never displayed) and the raw
  unrounded %, churning a redundant SSE broadcast + localStorage write + identical
  chip re-render on every assistant message. Now keys on the rounded displayed
  window values only.
- Plan-usage chip flashed hidden on load (no server-side reveal): renderIndexHtml
  now strips header-plan-usage--hidden when enabled, matching btn-multimonitor;
  fixes the FOUC and makes the "server renders initial state" comments accurate.
- Serialize all settings.local.json read-modify-write writers in hooks-config via
  a shared per-path mutex (previously lock-free; concurrent session-create +
  settings-toggle on the same repo could lose writes).
- Hardened the chip's innerHTML against any future string field; removed the dead
  _latestPlanUsage field; clamped ctx% in the footer formatter; corrected the
  session-create comment (the path is add-only by design — a per-repo settings
  file is shared by sibling sessions).
- Tests: new test/routes/status-telemetry-routes.test.ts (route behavior, dedup,
  null-tolerance) + NaN/Infinity/fractional and signature-churn unit tests; made
  server-index-title.test.ts deterministic against the ambient settings.json.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 07:33:52 +02:00
arkonandClaude Opus 4.8 6ee88be549 test: fix title tests for new host constructor arg + async renderIndexHtml
The WebServer constructor now takes `host` as the 4th positional arg
(titleHostname shifted to 5th), and renderIndexHtml became async (it
reads settings.json for the gesture bundle) and cache-busts asset URLs.
Update the two title tests accordingly:
- pass '127.0.0.1' as the bind host so the title value lands in the
  5th titleHostname slot (server-index-title + push-payload-host-title)
- await renderIndexHtml and make the cases async
- strip ?v=<mtime> cache-bust params before the byte-identical assertion

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 18:01:20 +02:00
arkonandClaude Opus 4.7 453a5383d2 test: cover hostname title (#82) and tmux size-query (#80)
Backfill the two regression gaps flagged on master after the recent
hostname-title and tmux-flicker fixes shipped without server-side
assertions.

* test/server-index-title.test.ts (8 tests) — exercises WebServer's
  index.html templating path: default os.hostname(), --title-hostname
  override, HTML-escape against `<script>`-style breakout, ampersand
  non-double-encoding, exact-once substitution, and byte-identical
  template-tail invariance.

* test/tmux-window-size-query.test.ts (15 tests) — mocks
  child_process.execFileSync and walks the helper through the
  browser-resize-between-attaches happy path, query-then-die race,
  zero/negative/empty/non-numeric output, plus argv-form/timeout
  assertions to lock down the no-shell-interpolation guarantee.

* src/session.ts — extracts the inline 14-line tmux size query into
  a named `queryTmuxWindowSize()` export so the test surface is a
  pure function. Behavior unchanged.

* src/web/public/notification-manager.js — Browser Notification API
  (layer 3) now uses `${this.originalTitle}: ${title}` so OS-level
  desktop pop-ups carry the same `codeman:<host>` prefix that the
  tab title and Web Push payloads already do, finishing the
  hostname plumb-through started in #82.

* CLAUDE.md, README.md — document the dual-CLI env-prefix discipline
  (CLAUDE_CODE_* vs OPENCODE_*), expand the xterm-zerolag-input
  duplication gotcha to mention the published-package side-effect,
  and note that the hostname prefix now applies uniformly to tab
  title, tab-flash, and OS notifications.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 10:23:44 +02:00