// ── Process abstraction ──────────────────────────────────────────────── export interface ProcessResult { code: number | null; stdout: string; stderr: string; timedOut: boolean; } export interface ProcessRunner { run(bin: string, args: string[], timeoutMs: number): Promise; } // ── Docker abstraction ────────────────────────────────────────────────── export interface DockerResult { ok: boolean; stdout: string; stderr: string; } export interface DockerClient { /** Run a docker CLI command. */ run(args: string[], timeoutMs?: number): Promise; /** Execute a command inside a running container. Returns trimmed stdout. */ exec(container: string, cmd: string, timeoutMs?: number): Promise; /** Stop a running container (docker kill). */ stop(container: string): Promise; /** Force-remove a container (docker rm -f). */ rm(container: string): Promise; /** Check whether the docker daemon is reachable. */ version(): Promise; /** Check whether an image exists locally. */ imageExists(image: string): Promise; /** Pull an image from a registry. */ pull(image: string): Promise; /** Build an image from a Dockerfile directory. */ build(dir: string, image: string): Promise; } // ── File I/O abstraction (for toggle persistence) ──────────────────────── export interface FileStore { /** Read a file as a UTF-8 string, or null if it doesn't exist. */ read(path: string): string | null; /** Write a UTF-8 string to a file (overwrites). */ write(path: string, data: string): void; /** Check whether a file exists. */ exists(path: string): boolean; } // ── Skill discovery abstraction ────────────────────────────────────────── export interface SkillResolver { /** Return absolute paths to skill directories on the host. */ discover(): string[]; } // ── Sandbox configuration (plain data, no pi SDK dependency) ───────────── export interface SandboxFlags { network: boolean; mountCwd: boolean; mountSkills: boolean; mountSsh: boolean; containerName?: string; memory: string; cpus: string; } // ── Path translation context (subset of Container needed by toRemote) ──── export interface PathContext { hostCwd: string; hasCwd: boolean; hasSkills: boolean; skillSources: string[]; /** When set, paths inside this directory map to /home/node/.agent/docs/. */ docsPath?: string; } // ── UI abstraction (for command handlers) ──────────────────────────────── export interface UIContext { notify(message: string, severity?: "info" | "warning" | "error"): void; confirm(title: string, body: string): Promise; reload(): Promise; setStatus(key: string, text: string): void; } /** Raw pi SDK context shape — what the command handler receives. */ export interface PIContext { ui: { notify(message: string, severity?: string): void; confirm(title: string, body: string): Promise; setStatus(key: string, text: string): void; }; reload(): Promise; } /** Adapt pi's ctx (ui methods on ctx.ui, reload on ctx) to our UIContext. */ export function createUIContext(ctx: PIContext): UIContext { return { notify: (msg, severity) => ctx.ui.notify(msg, severity), confirm: (title, body) => ctx.ui.confirm(title, body), setStatus: (key, text) => ctx.ui.setStatus(key, text), reload: () => ctx.reload(), }; } // ── Sandbox handle (subset of SandboxManager for consumers) ────────────── export interface SandboxHandle { readonly name: string; readonly hostCwd: string; readonly hasCwd: boolean; readonly hasNetwork: boolean; readonly hasSkills: boolean; readonly hasSsh: boolean; readonly hasDocs: boolean; readonly memory: string; readonly cpus: string; exec(cmd: string, timeoutMs?: number): Promise; toRemote(hostPath: string): string; stop(): Promise; }