Skip to content

vx serve --ui: bundle SPA, delete vx insights#145

Merged
Exelord merged 3 commits into
mainfrom
claude/serve-ui-flag
Jun 21, 2026
Merged

vx serve --ui: bundle SPA, delete vx insights#145
Exelord merged 3 commits into
mainfrom
claude/serve-ui-flag

Conversation

@Exelord

@Exelord Exelord commented Jun 21, 2026

Copy link
Copy Markdown
Member

Summary

User: "Maybe we don't even need insight if it spawns a server. Maybe we just need —ui flag""Vx serve should serve it when flag passed".

vx insights was just spawning vx serve + a Vite dev server. Cut it. vx serve --ui now serves the prebuilt SPA at / alongside the same JSON API + WS + SSE.

⚠️ Stacks on #144 (insights overhaul). Will rebase cleanly once that merges.

What changed

  • startServe gains a uiDir option. The fetch handler serves files from it with proper MIME, no-store for HTML, immutable cache for Vite's hashed assets, SPA fallback to index.html for hash-router routes. path.resolve containment check guards against traversal.
  • New flags. parseServeArgs (renamed from parsePort) handles --ui and --open. resolveUiDist() points at <vx-checkout>/apps/insights/dist (VX_INSIGHTS_DIST overrides). --open shells out to xdg-open / open / cmd start as best effort.
  • Delete vx insightssrc/cli/insights.ts, tests/insights.test.ts, the insights case in src/cli/index.ts, and the parseInsightsArgs re-export. Help text updated.

Docs

  • Rewrite guides/insights.md around vx serve --ui --open
  • README + introduction + docs/cli.md + apps/docs/.../cli.md + Astro sidebar updated
  • Replace mentions of "vx insights" with "Insights dashboard"

Test plan

  • bun src/bin.ts run ci — full gate green (12 serve tests, 943 total)
  • New tests cover: bundled SPA static-serving with proper MIME, no-store HTML / immutable assets cache headers, SPA hash-router fallback, /v1/* still wins over the static handler, --ui off keeps the bare vx serve response, parseServeArgs (port/ui/open combinations, errors)
  • SPA still builds (Vite 8, UnoCSS 66, 21.8 KB gzipped)

One-liner UX

vx serve --ui --open

→ unified backend boots, SPA serves at /, browser opens. Ctrl-C stops it.


Generated by Claude Code

claude added 3 commits June 21, 2026 18:42
- apps/insights: vite 6→8, unocss 0.65→66 (calver renumber), Solid
  Router 0.15→0.16. SPA builds clean (17.5 KB gzipped JS).
- apps/docs: astro 6.4.6→6.4.8, mermaid 11.6→11.15, sharp 0.34→0.35,
  unist-util-visit 5.0→5.1.
- root: @anthropic-ai/sandbox-runtime 0.0.51→0.0.56, @types/bun
  1.3.0→1.3.14, oxfmt 0.48→0.55, oxlint 1.63→1.70, oxlint-tsgolint
  0.22→0.23. Lint + 923 tests green.
The SPA was a placeholder — one Overview list, no per-task drilldown,
nothing about cache, no charts. Now it's a real dashboard.

New SQL backed by /v1/* HTTP routes:
- /v1/top-tasks — biggest time-burners (non-hit success totals)
- /v1/failures — recent failed runs
- /v1/cache/breakdown — bytes per project
- /v1/cache/savings — estimated time the cache saved you (24h + all-time)
- /v1/cache/entries — full entries listing, sortable by size/age/duration
- /v1/tasks/:id — full per-task aggregate + 100 recent runs + latest cache entry

Extended TaskHistoryRow with min/avg/max/total/lastSeenAt. RunSummaryRow
now carries cpuMs + peakRssBytes (the columns were always there, just
not surfaced).

SPA pages:
- Overview: 4-card hero (time saved 24h, hit rate, entries, total time
  saved), Top time-burners + Recent failures side-by-side, cache breakdown
  with bars, recent invocations.
- Tasks (new): sortable table over every (project, task) — runs, success
  rate, hit rate, avg, p50, p99, total time, last run; substring filter;
  failure-mode dot.
- TaskDetail (new): 10 stats (runs, success/hit rate, failure mode, last
  run, min/avg/p50/p99/max), Sparkline of last 100 durations with cache
  hits dotted in cyan, latest cache entry card (hash/size/exec/duration/
  created/accessed), full recent-run table with CPU + peak RSS + hash.
- Cache (new): stat cards, by-project breakdown, sortable entries table
  (largest/newest/recently-accessed/slowest).

New Sparkline component — pure inline SVG, no chart lib.

Tests: 6 new query tests (16 total); full CI gate green (946 tests).
SPA bundle: 17.5 KB → 21.8 KB gzipped (still tiny).
The vx insights command was just spawning vx serve + Vite. Cut it:
vx serve --ui serves the prebuilt SPA at /, alongside the same JSON
API + WS + SSE. One process, one stack.

- startServe gains a uiDir option; the fetch handler serves files
  from it with proper MIME, no-store for HTML, immutable cache for
  Vite's hashed assets, SPA fallback to index.html for hash-router
  routes. Containment check via path.resolve.
- parseServeArgs adds --ui and --open. resolveUiDist() points at
  <vx-checkout>/apps/insights/dist (VX_INSIGHTS_DIST overrides).
  --open shells out to xdg-open / open / cmd start (best effort).
- Delete src/cli/insights.ts, tests/insights.test.ts, the
  insights case in src/cli/index.ts, parseInsightsArgs export.
- Add 12 serve tests covering --ui static serving (MIME, cache
  headers, SPA fallback, /v1/* still wins, traversal), --ui-off
  path, parseServeArgs.

Docs:
- Rewrite guides/insights.md around vx serve --ui --open
- README + introduction + cli.md + docs/cli.md + sidebar updated
- 943 tests pass (was 940). Lint clean.
@Exelord Exelord merged commit 080247d into main Jun 21, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants