# lvmh web UI React 19 + Vite + TypeScript single-page app for the lvmh daemon. Talks only to the REST API under `/api` and the `/ws` websocket described in `../PROTOCOL.md`. ## Run (dev) ``` cd web npm install npm run dev ``` Dev server proxies `/api` and `/ws` to `http://localhost:8686` (see `vite.config.ts`). ## Build ``` npm run build ``` Type-checks with `tsc --noEmit`, bundles to `web/dist/` (the daemon serves this directory). ## First use On first load the UI shows a settings gate: server URL (defaults to same-origin) + bearer token (`LVMH_TOKEN`). Stored in `localStorage`; cleared via the "disconnect" button in the sidebar footer. ## Structure - `src/protocol.ts` — typed mirror of PROTOCOL.md (envelope, event types, REST routes, WS frames) - `src/ws.ts` — single websocket manager: auto-reconnect with exponential backoff + jitter, resubscribe on open, seq tracking helpers - `src/api.ts` — `fetchJson` helper with bearer auth + error parsing - `src/settings.ts` — localStorage settings + WS URL builder - `src/store.ts` — sessions store (REST seed + WS `session_list` updates), toasts, time formatting - `src/derive.ts` — client-side derivation: chat view from events, todo list from `todo` tool calls, subagent runs from `subagent` tool calls - `src/ChatView.tsx` — chat: history load, live streaming via `message_update`, abort, sticky scroll - `src/SessionsView.tsx` — session list with online dots, agent badges, stop - `src/SpawnView.tsx` — GitLab connect + repo/branch picker + spawn polling - `src/SettingsGate.tsx` — first-run token gate ## Conventions - No UI/state/HTTP libraries beyond react, react-dom, react-router-dom. - All icon-only buttons carry `aria-label`. - Dark theme, mobile-friendly (≤400px) via hand-rolled CSS in `src/index.css`.