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/src/types.ts
T
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

82 lines
2.0 KiB
TypeScript

// Mirror of `maestro-protocol` JSON shapes. Keep in sync with
// crates/maestro-protocol/src/lib.rs.
export type Uuid = string;
export type IsoTimestamp = string;
export type SessionStatus = "Running" | "Dead";
export interface Session {
id: Uuid;
daemon_id: string;
cwd: string;
command: string;
env: Record<string, string>;
metadata: Record<string, unknown>;
status: SessionStatus;
created_at: IsoTimestamp;
}
export interface DaemonInfo {
daemon_id: string;
hostname: string;
version: string;
daemon_url: string;
}
export interface ConnectInfo {
daemon_url: string;
jwt: string;
}
export interface WorktreeSpec {
base_repo: string;
branch: string;
cleanup_on_kill?: boolean;
}
export interface CreateSessionRequest {
daemon_id: string;
cwd: string;
command: string;
env?: Record<string, string>;
metadata?: Record<string, unknown>;
worktree?: WorktreeSpec;
}
export type RegistryEvent =
| {
type: "Snapshot";
daemons: DaemonInfo[];
sessions: Session[];
}
| { type: "DaemonAdded"; daemon: DaemonInfo }
| { type: "DaemonRemoved"; daemon_id: string }
| { type: "SessionAdded"; session: Session }
| { type: "SessionRemoved"; daemon_id: string; id: Uuid }
| { type: "SessionUpdated"; session: Session }
| { type: "Lagged"; skipped: number };
export type ClientControl =
| { type: "Resize"; cols: number; rows: number }
| { type: "Ping" }
| { type: "Pong" }
| { type: "Error"; code: string; message: string };
export interface ApiError {
error: { code: string; message: string };
}
export function sessionName(s: Session): string {
const meta = s.metadata as Record<string, unknown>;
const name = meta?.name;
if (typeof name === "string" && name.length > 0) return name;
return s.command;
}
export function sessionLabel(s: Session): string | undefined {
const meta = s.metadata as Record<string, unknown>;
const label = meta?.label;
return typeof label === "string" ? label : undefined;
}