This repository has been archived on 2026-10-08. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
maestro/web/README.md
T
naps62-yoloandClaude Opus 4.8 815ad695df
ci / rust (pull_request) Failing after 3m32s
feat(maestro): redesign web UI — token system, dark/light, a11y status
Rewrite styles.css as an OKLCH design-system: cool-slate neutrals with a
single committed signal-green for "alive" (running status, primary action,
focus, selection). Monospace becomes the UI typeface; dark is default with a
full light theme via tokens, OS-following with a persisted header toggle.

- catalog: pulsing wordmark, status-bar tally (N sessions / M live) + daemon
  chips, color-independent session status (pulsing dot for running, hollow
  ring + "exited" badge for dead), reveal-on-hover kill, three teaching
  empty states.
- attach: state pill (live/closed/error), framed dark xterm w/ green cursor.
- spawn: bottom-sheet/dialog form, mono inputs with green focus rings.
- a11y: AA contrast both themes, visible focus, prefers-reduced-motion paths,
  status never color-only.
- theme.ts: dark/light toggle + persistence; mock.ts: DEV-only review fixture
  (?mock / ?mock&spawn / ?theme=), tree-shaken from production builds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 18:40:42 +00:00

79 lines
2.9 KiB
Markdown

# maestro-web
Browser UI for Maestro. Connects to the registry HTTP/WS API for the catalog
and to individual daemons (via direct WebSocket) for terminal I/O.
## Framework choice: vanilla TypeScript
No frontend framework. The UI is small enough that the cost of pulling in
Preact / Solid / Leptos doesn't pay back. xterm.js does all the heavy
rendering; everything else is a session tree and a spawn form, both trivial
in plain DOM.
This decision is non-architectural — swap in a framework later without
touching the registry or daemon if needed.
## Layout
```
src/
main.ts # entry point, hash-route dispatch
api.ts # registry HTTP API client
events.ts # `/api/events` WebSocket subscriber
catalog.ts # session tree view (groups by metadata.label)
attach.ts # xterm.js + daemon WS attach view
spawn.ts # spawn-session modal
theme.ts # dark/light theme toggle + persistence
types.ts # mirror of `maestro-protocol` JSON shapes
styles.css # design-system tokens + component styles
mock.ts # DEV-only review fixture (see Design)
```
## Design
The visual system (OKLCH token palette, monospace-first typography, dark+light
theming, motion, components) is documented in [`../DESIGN.md`](../DESIGN.md);
the tokens live in the `:root` block of `src/styles.css`. Strategic intent
(register, brand, principles) is in [`../PRODUCT.md`](../PRODUCT.md). Theme
follows the OS by default and can be pinned via the header toggle (persisted in
`localStorage`).
`mock.ts` is a DEV-only fixture (stripped from production builds): visit the dev
server with `?mock` to seed a representative catalog without a running registry,
`?mock&spawn` to open the spawn modal, and `?theme=light|dark` to pin a theme.
Routing is hash-based:
- `#/` → catalog
- `#/attach/<session-id>` → terminal
This keeps the registry's static handler dumb (no SPA fallback needed).
Concurrent attaches: open the same `#/attach/<id>` URL in another tab.
## Dev
```sh
pnpm install
pnpm dev # http://localhost:5173, proxies /api → http://127.0.0.1:8080
pnpm build # → dist/, embedded into the registry binary at cargo build time
```
The Vite dev server proxies `/api` and the events WebSocket to a
`maestro-registry`. Default is `http://127.0.0.1:8080`; point it elsewhere by
exporting `MAESTRO_REGISTRY` before `pnpm dev`:
```sh
MAESTRO_REGISTRY=https://maestro-registry.example.com pnpm dev
# Daemon-facing URL also works — `wss://...` is rewritten to `https://...`
# and a trailing `/daemon` is stripped.
MAESTRO_REGISTRY=wss://maestro-registry.example.com/daemon pnpm dev
```
Direct daemon WS connections (for attach) bypass the proxy and use the URL
returned by `GET /api/sessions/:id/connect-info`.
## Production
`pnpm build` writes the bundle to `web/dist/`. The Rust registry crate
embeds that directory via `rust-embed` at compile time and serves it from
`/`. See `crates/maestro-registry/src/web_assets.rs`.