Commit Graph
8 Commits
Author SHA1 Message Date
naps62-yoloandClaude Opus 4.8 a429c69956 chore(maestro): drop obsolete web/dist/.gitkeep handling
ci / rust (push) Failing after 3m2s
build.rs now builds web/dist before include_dir! evaluates, so the
checked-in .gitkeep placeholder is no longer needed for a fresh checkout
to compile (verified by building with web/dist entirely absent). Ignore
dist/ wholesale and update the static_bundle doc comment.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-28 22:21:59 +00:00
naps62-yolo 0f3770f711 feat(maestro-tui): CatalogStore over WS /api/events (NAP-278)
ci / rust (push) Failing after 5m5s
CatalogStore is the TUI's view of the daemons-and-sessions tree, backed by
`WS /api/events` on the local daemon. The daemon's WS opens with a Snapshot
frame, so that's bootstrap; subsequent frames are deltas. No separate REST
round-trip needed.

Surface:
- `apply_event` — pure, used by tests directly and by the WS loop.
- `snapshot()` — cheap O(d+s) read returning sorted Vec views + monotonic
  version for cheap render staleness checks.
- `wait_for_initial_snapshot` / `changed` — render-loop wakeups.
- `run_events_loop(ws_url)` — long-running task with exponential backoff
  (1s → 30s, ±25% jitter). Reconnect re-sends a fresh Snapshot, which
  reconciles state without server-side replay.

8 unit tests + 1 axum WS round-trip integration test passing.
2026-05-28 22:08:06 +00:00
naps62-yoloandClaude Opus 4.7 a671e15114 feat(maestro): daemon WS /api/events for live catalog updates (NAP-248)
ci / rust (push) Failing after 7m28s
New module `local_events::LocalEventBus` (broadcast<RegistryEvent>) with
two publishers:

* `spawn_session_publisher` — translates SessionManager's own session
  events into the matching `RegistryEvent` variants (with daemon_id
  filled in for the SessionRemoved case).
* `CatalogMirror::apply` — re-publishes peer events after applying them
  to the local mirror, so subscribers see the post-apply state.

New `WS /api/events` route on the daemon: subscribes to the bus, sends
an initial `Snapshot` built from manager.snapshot() ∪ catalog state,
then forwards live deltas. `Lagged` follows the registry's convention
(client resyncs via REST).

Revert the REST-seed hack in web/src/events.ts — the WS endpoint now
exists, so `CatalogStore::start()` can go back to just `connect()`.

E2E: subscribe to a daemon's events WS, expect Snapshot then a
SessionAdded after POSTing /api/sessions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 22:01:08 +00:00
naps62-yoloandClaude Opus 4.7 54b5763871 fix(maestro): seed catalog from REST so the UI renders without /api/events
ci / rust (push) Successful in 2m6s
CatalogStore.start() previously connected the events WS only — fine when
loaded from the registry, broken when loaded from maestro-web (the daemon
has no /api/events endpoint yet, so the WS handshake 404s and the catalog
stays empty). Issue an initial resync() before connect(); the WS, when it
succeeds, takes over with live deltas. Daemon-side WS is filed as NAP-248.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 21:02:57 +00:00
naps62-yoloandClaude Opus 4.7 464bea2fae refactor(web): rewire attach.ts to same-origin broker endpoint (NAP-241)
ci / rust (push) Failing after 8m45s
Browser now opens ws://{host}/api/attach/:id directly — maestro-web
reverse-proxies it to the home daemon's broker, which short-circuits to
the local PTY (NAP-243) or, once NAP-247 lands, brokers to a peer over T2.

Drops the old getConnectInfo + daemon_url path: the browser no longer
knows or cares which daemon owns a session. ConnectInfo type and the
helper are gone.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 18:23:21 +00:00
naps62-yolo f0b01ae295 feat(maestro): let vite dev proxy honor \$MAESTRO_REGISTRY
ci / rust (push) Successful in 1m27s
`web/vite.config.ts` was hard-coded to proxy `/api` at
`http://127.0.0.1:8080`, so pointing the dev UI at a remote registry meant
hand-editing the file. Read `MAESTRO_REGISTRY` from the environment via
`loadEnv` instead, with the local default preserved. Accept either the HTTP
base URL (`https://…`) or the daemon-facing URL (`wss://…/daemon`) — the
latter is rewritten to `https://…` and the `/daemon` suffix stripped, since
the proxy needs the HTTP origin. Flips `changeOrigin: true` for HTTPS
upstreams so the proxied Host matches the cert.

Documented under `web/README.md` § Dev.
2026-05-25 15:35:57 +00:00
naps62-yoloandClaude Opus 4.7 50f24a2cf9 fix(maestro): pin pnpm via packageManager so corepack doesn't grab v11
ci / rust (push) Successful in 1m26s
The Dockerfile's `web-builder` stage (NAP-218) uses Node 20 + corepack.
Without a `packageManager` field, corepack defaulted to pnpm@latest,
which is now 11.3.0 — that release requires Node ≥22.13 and imports
`node:sqlite`, so it dies on Node 20 with
`ERR_UNKNOWN_BUILTIN_MODULE: node:sqlite`. Dokploy builds were failing
in the `pnpm install` step.

Pin pnpm@9.15.4 (latest 9.x, fully Node-20 compatible). No code change
to the web bundle itself.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 10:44:34 +00:00
naps62-yoloandClaude Opus 4.7 e68c9b6d73 feat(maestro): web client (Vite + TS + xterm.js)
NAP-218. Browser UI for the prototype: catalog tree derived from
`metadata.label`, live updates over `WS /api/events`, search across
session name+label, spawn modal (with optional git worktree), and an
attach view that opens the daemon's per-session WS for xterm.js.

Framework choice: vanilla TypeScript. The interactivity surface is
small enough that pulling in a framework wouldn't pay back; xterm.js
does the heavy lifting. Easy to swap later without protocol impact.

Hash-based routing (`#/`, `#/attach/<id>`) keeps the registry's
static surface dumb — no SPA fallback needed; concurrent attaches
work by opening the same hash URL in another tab.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 09:57:11 +00:00