/** * `useProcesses` — the supervisor's managed-process list + lifecycle. * * Polls `/__nwire/run/processes` and exposes start/stop/forget plus the two * launch verbs (topology `start`, package-script `exec-script`, CLI `exec`). * Shared by the Run + Commands panels; the optional `filter` narrows the list * (Commands only shows `nwire …` processes it launched). */ import { ref, onMounted, onUnmounted } from "vue"; import type { ManagedProcess } from "@/lib/operate"; interface Options { /** Narrow the polled list (e.g. only CLI processes). */ filter?: (p: ManagedProcess) => boolean; /** Poll cadence in ms. Default 2000. */ intervalMs?: number; } export function useProcesses(options: Options = {}) { const { filter, intervalMs = 2000 } = options; const processes = ref([]); const error = ref(null); let poll: ReturnType | null = null; async function load(): Promise { try { const res = await fetch("/__nwire/run/processes"); const body = (await res.json()) as { processes: ManagedProcess[] }; processes.value = filter ? body.processes.filter(filter) : body.processes; } catch { /* transient — keep the last good list */ } } async function start(payload: { topology: string; port?: number; env?: Record; }): Promise { return launch("/__nwire/run/start", payload); } async function execScript(payload: { script: string; port?: number; env?: Record; }): Promise { return launch("/__nwire/run/exec-script", payload); } async function exec(command: string, args: string[] = []): Promise { return launch("/__nwire/run/exec", { command, args }); } async function launch(url: string, body: unknown): Promise { error.value = null; try { const res = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }); const data = (await res.json()) as { process?: ManagedProcess; error?: string; }; if (!res.ok) { error.value = data.error ?? `request failed (${res.status})`; return null; } if (data.process) { processes.value = [...processes.value, data.process]; return data.process; } await load(); return null; } catch (err) { error.value = (err as Error).message; return null; } } async function stop(id: string): Promise { try { await fetch(`/__nwire/run/stop/${encodeURIComponent(id)}`, { method: "POST", }); } catch { /* ignore */ } await load(); } async function forget(id: string): Promise { try { await fetch(`/__nwire/run/forget/${encodeURIComponent(id)}`, { method: "POST", }); } catch { /* ignore */ } await load(); } onMounted(() => { void load(); poll = setInterval(load, intervalMs); }); onUnmounted(() => { if (poll) clearInterval(poll); }); return { processes, error, load, start, execScript, exec, stop, forget }; }