// 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"; /** Daemon-inferred activity dimension, orthogonal to `SessionStatus` (NAP-340). * Absent on payloads from daemons that predate the field. */ export type ActivityState = "Active" | "Idle" | "AwaitingInput"; export interface Session { id: Uuid; daemon_id: string; cwd: string; command: string; env: Record; metadata: Record; status: SessionStatus; created_at: IsoTimestamp; /** Current foreground command in the pane (e.g. `claude`, `bash`), as the * daemon's activity watcher observed it. Absent until observed (NAP-340). */ foreground?: string | null; /** Inferred activity. Defaults to `Idle` on the wire when omitted. */ activity?: ActivityState; /** Wall-clock of the most recent observed PTY output (NAP-340). */ last_activity_at?: IsoTimestamp; /** The pane's *current* working directory, as the daemon's activity watcher * observed it (`#{pane_current_path}`) — distinct from `cwd` (the spawn dir). * Drives the directory-based session tree. Absent until first observed. */ current_cwd?: string | null; } export interface DaemonInfo { daemon_id: string; hostname: string; version: string; daemon_url: string; /** Home dir of the user the daemon runs as; used to prefill the spawn form's * working directory. Empty/absent for older daemons. */ home_dir?: string; } /** One directory's immediate subdirectories on a daemon's host (NAP-329). */ export interface DirListing { /** Resolved absolute directory that was listed (after ~/relative expansion). */ path: string; /** Immediate subdirectory names, sorted case-insensitively. */ entries: string[]; /** True when the listing was capped server-side. */ truncated?: boolean; } /** A spawn-form command preset advertised by the daemon (#22/#26). The `custom` * preset has an empty `command` and reveals the free-text command input. */ export interface SpawnPreset { id: string; label: string; command: string; } /** `GET /api/web/info` — the connected daemon's identity plus its spawn presets * (#26). Mirrors the daemon-side `WebInfo`. */ export interface WebInfo { daemon_id: string; hostname: string; version: string; daemon_url: string; /** Command presets (claude/opencode/zsh + custom), config-resolved. */ presets: SpawnPreset[]; } /** One deduplicated recent working dir for the spawn form's recents picker * (#24/#26). */ export interface RecentDir { cwd: string; last_command: string; last_used: IsoTimestamp; } /** `GET /api/daemons/:id/recent-dirs` — a host's recent working dirs (#26). */ export interface RecentDirs { dirs: RecentDir[]; truncated?: boolean; } /** `GET /api/daemons/:id/gitroot?path=` — the enclosing repo toplevel of a path * on a host, or absent when the path isn't inside a repo (#26). */ export interface GitRoot { root?: 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; metadata?: Record; 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; const name = meta?.name; if (typeof name === "string" && name.length > 0) return name; return s.command; } /** The directory a session lives in: its live `current_cwd` if the daemon has * observed one, else the spawn `cwd`. Drives the directory-based session tree. */ export function sessionCwd(s: Session): string | undefined { if (typeof s.current_cwd === "string" && s.current_cwd) return s.current_cwd; return s.cwd || undefined; } /** Collapse a daemon's home dir to `~`. `home` comes from `DaemonInfo.home_dir`; * absent/empty leaves the path untouched. Mirrors the CLI's `abbreviate_dir`. */ export function abbreviateCwd(cwd: string, home?: string): string { if (home && (cwd === home || cwd.startsWith(`${home}/`))) { return `~${cwd.slice(home.length)}`; } return cwd; }