refactor(maestro): flatten web UI to a single host
Session tree nests by working directory only; the daemon chips in the header become a session tally, and the spawn form loses its host picker. API calls move from /api/daemons/:id/* to /api/dirs, /api/recent-dirs, /api/gitroot, and /api/info.
This commit is contained in:
+19
-35
@@ -2,7 +2,7 @@
|
||||
// main.ts (`?mock`), so it never ships in a production bundle. It pushes a
|
||||
// synthetic Snapshot through the store's normal event path.
|
||||
import type { CatalogStore } from "./events.js";
|
||||
import type { ActivityState, Session, DaemonInfo } from "./types.js";
|
||||
import type { ActivityState, Session } from "./types.js";
|
||||
|
||||
// Rotate inferred activity across the fixture so the debug HUD (#20) shows all
|
||||
// three states. Keyed off the id's last hex digit for stable variety.
|
||||
@@ -10,7 +10,6 @@ const ACTIVITIES: ActivityState[] = ["Active", "Idle", "AwaitingInput"];
|
||||
|
||||
function sess(
|
||||
id: string,
|
||||
daemon: string,
|
||||
command: string,
|
||||
status: "Running" | "Dead",
|
||||
cwd: string,
|
||||
@@ -19,7 +18,6 @@ function sess(
|
||||
const seed = parseInt(id.slice(-1), 16) || 0;
|
||||
return {
|
||||
id,
|
||||
daemon_id: daemon,
|
||||
cwd,
|
||||
command,
|
||||
env: {},
|
||||
@@ -48,13 +46,12 @@ function stubSpawnApi(): void {
|
||||
globalThis.fetch = (input: RequestInfo | URL, init?: RequestInit) => {
|
||||
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
||||
const path = url.startsWith("http") ? new URL(url).pathname + new URL(url).search : url;
|
||||
if (path.startsWith("/api/web/info")) {
|
||||
if (path.startsWith("/api/info")) {
|
||||
return Promise.resolve(
|
||||
json({
|
||||
daemon_id: "thinkpad",
|
||||
hostname: "thinkpad.lan",
|
||||
version: "0.1.0",
|
||||
daemon_url: "wss://thinkpad.lan/daemon",
|
||||
home_dir: "/home/dev",
|
||||
presets: [
|
||||
{ id: "claude", label: "Claude", command: "claude" },
|
||||
{ id: "opencode", label: "opencode", command: "opencode" },
|
||||
@@ -87,38 +84,31 @@ function stubSpawnApi(): void {
|
||||
}
|
||||
|
||||
export function seedMock(store: CatalogStore): void {
|
||||
const daemons: DaemonInfo[] = [
|
||||
{ daemon_id: "thinkpad", hostname: "thinkpad.lan", version: "0.1.0", daemon_url: "wss://thinkpad.lan/daemon", home_dir: "/home/dev" },
|
||||
{ daemon_id: "tower", hostname: "tower.lan", version: "0.1.0", daemon_url: "wss://tower.lan/daemon", home_dir: "/home/dev" },
|
||||
{ daemon_id: "pi", hostname: "pi.lan", version: "0.1.0", daemon_url: "wss://pi.lan/daemon", home_dir: "/home/pi" },
|
||||
];
|
||||
const sessions: Session[] = [
|
||||
// ~/git/maestro/web/* — deep dir chain; "~/git/maestro" collapses to one node.
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000001", "thinkpad", "claude", "Running", "/home/dev/git/maestro/web", "redesign"),
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000002", "thinkpad", "vite dev", "Running", "/home/dev/git/maestro/web", "dev-server"),
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000003", "tower", "bash", "Dead", "/home/dev/git/maestro/web", "scratch"),
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000004", "thinkpad", "claude", "Running", "/home/dev/git/maestro/web/tests", "e2e-fixes"),
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000001", "claude", "Running", "/home/dev/git/maestro/web", "redesign"),
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000002", "vite dev", "Running", "/home/dev/git/maestro/web", "dev-server"),
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000003", "bash", "Dead", "/home/dev/git/maestro/web", "scratch"),
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000004", "claude", "Running", "/home/dev/git/maestro/web/tests", "e2e-fixes"),
|
||||
// ~/git/maestro/crates/* — sibling subtree under the same repo.
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000005", "thinkpad", "claude", "Running", "/home/dev/git/maestro/crates/registry", "registry-broker"),
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000006", "tower", "cargo watch -x test", "Running", "/home/dev/git/maestro/crates/registry", "test-loop"),
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000007", "tower", "cargo run -- daemon", "Running", "/home/dev/git/maestro/crates/daemon", "daemon"),
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000005", "claude", "Running", "/home/dev/git/maestro/crates/daemon", "daemon-work"),
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000006", "cargo watch -x test", "Running", "/home/dev/git/maestro/crates/daemon", "test-loop"),
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000007", "cargo run -- daemon", "Running", "/home/dev/git/maestro/crates/daemon", "daemon"),
|
||||
// ~/work/acme/* — a separate top-level dir on the same host.
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000008", "tower", "claude", "Running", "/home/dev/work/acme/api", "billing-api"),
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000009", "tower", "pnpm dev", "Dead", "/home/dev/work/acme/web", "dashboard"),
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000008", "claude", "Running", "/home/dev/work/acme/api", "billing-api"),
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000009", "pnpm dev", "Dead", "/home/dev/work/acme/web", "dashboard"),
|
||||
// ~/git/dotfiles — single session, fully collapsed chain.
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000010", "tower", "opencode", "Running", "/home/dev/git/dotfiles", "dotfiles"),
|
||||
// pi's home (different home_dir) — sits directly under ~.
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000011", "pi", "btop", "Running", "/home/pi", "monitor"),
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000010", "opencode", "Running", "/home/dev/git/dotfiles", "dotfiles"),
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000011", "btop", "Running", "/home/dev/git/infra", "monitor"),
|
||||
// outside any home dir → shown verbatim (no ~ collapse).
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000012", "pi", "ssh gateway", "Dead", "/etc"),
|
||||
// home root on thinkpad — a leaf directly under ~ (name from command).
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000013", "thinkpad", "htop", "Running", "/home/dev"),
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000012", "ssh gateway", "Dead", "/etc"),
|
||||
// home root — a leaf directly under ~ (name from command).
|
||||
sess("a1b2c3d4-0000-0000-0000-000000000013", "htop", "Running", "/home/dev"),
|
||||
];
|
||||
// The store applies RegistryEvents internally; feed a Snapshot the same way
|
||||
// The store applies CatalogEvents internally; feed a Snapshot the same way
|
||||
// the WS would. `apply` is private, so reach it through an index cast.
|
||||
(store as unknown as { apply: (e: unknown) => void }).apply({
|
||||
type: "Snapshot",
|
||||
daemons,
|
||||
sessions,
|
||||
});
|
||||
|
||||
@@ -126,12 +116,6 @@ export function seedMock(store: CatalogStore): void {
|
||||
// backend endpoints stubbed so presets/recents/gitroot all render.
|
||||
if (location.search.includes("spawn")) {
|
||||
stubSpawnApi();
|
||||
void import("./spawn.js").then((m) =>
|
||||
m.openSpawnModal(
|
||||
new Map(daemons.map((d) => [d.daemon_id, d])),
|
||||
undefined,
|
||||
new Map(sessions.map((s) => [s.id, s])),
|
||||
),
|
||||
);
|
||||
void import("./spawn.js").then((m) => m.openSpawnModal());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user