import { type V3RunStatus } from './state.js'; import type { V3NodeStatus } from './orchestrator.js'; export declare function isValidRunId(runId: string): boolean; export declare function isValidWaitId(waitId: string): boolean; /** Default run root, aligned with cli-run.ts / grill-state.ts. */ export declare function defaultRunsDir(): string; export interface WebTerminalView { sessionId: string; webPort?: number; /** `live` while the node's work worker is in flight; `closed` once the node * reached a terminal verdict (then replay via the pty-log endpoint). */ status: 'live' | 'closed'; } export interface RunNodeView { id: string; status: V3NodeStatus; /** Upstream node ids (graph edges) — from the persisted dag.json. */ depends: string[]; goal?: string; attemptId?: string; /** Present once the node's worker reported `nodeSessionReady`. */ webTerminal?: WebTerminalView; /** Whether a raw PTY log exists for replay. The absolute path is NOT exposed * to the frontend (codex review) — a replay endpoint locates it server-side * via `ptyLogPathFor(runsDir, runId, nodeId)`. */ hasPtyLog: boolean; /** Whether the node produced a manifest (i.e. succeeded with a recorded * manifest). The raw fs path is NOT exposed — same rationale as `hasPtyLog`: * `GET /api/v3/runs/:id` is link-shareable public-read, so a public reader * must never see absolute `/root/.botmux/...` paths (codex security review * 2026-06-02). A download, if ever needed, goes through a cookie-auth * endpoint that locates the file server-side via runId/nodeId. */ hasManifest: boolean; /** For blocked/failed nodes: the coarse error class + the node's * self-reported `manifest.error.code` (e.g. AUTH_REQUIRED). The free-text * `message` is deliberately NOT projected — it can quote validator problems * containing absolute paths, and this view is link-shareable public-read. */ errorClass?: string; errorCode?: string; /** True for composite loop nodes (from dag.json). */ isLoop?: boolean; /** Composite loop progress (loop nodes only, once started). `lastDecision` * is the coarse enum; the free-text decision `detail` is deliberately NOT * projected (it can quote agent-written result strings) — same public-read * rationale as `message`. */ loopState?: { iteration: number; maxIterations?: number; granted: number; lastDecision?: 'exit' | 'continue' | 'exhausted'; /** Per-iteration verdict history (enum ONLY — same no-detail rationale). * Lets the dashboard draw an honest round timeline instead of guessing * past verdicts from `lastDecision`. */ decisions: Array<{ iteration: number; decision: 'exit' | 'continue' | 'exhausted'; }>; /** Body template shape (authored ids + body-internal depends) — the * dashboard lays every round's mini-dag on this skeleton, so a round * whose later nodes have not dispatched yet still shows its full shape * (undispatched slots render as pending ghosts). */ bodyTemplate: Array<{ id: string; depends: string[]; }>; }; /** For loop BODY INSTANCE nodes (`repairLoop.i001.code`): the structured * membership ref from the dispatch event. The id stays opaque — group by * THIS, never parse the id string. */ loop?: { loopId: string; iteration: number; bodyNodeId: string; }; } export interface RunView { runId: string; runStatus: V3RunStatus; failedNodeId?: string; blockedNodeId?: string; nodes: RunNodeView[]; } /** * Project an already-resolved run dir into a `RunView`. Read-only + defensive: * a missing journal / dag still yields a (possibly sparse) view rather than * throwing — the dashboard polls this while a run is mid-flight. */ export declare function projectRun(runId: string, runDir: string): RunView; /** * Validate a caller-supplied `runId`, resolve it under `runsDir` (re-checking * the join stays inside runsDir — defense in depth), and project. Returns * `undefined` for an invalid id / traversal attempt / missing run. */ export declare function projectRunById(runsDir: string, runId: string): RunView | undefined; /** * Server-side resolver for a node's raw PTY log path (for the replay endpoint). * The absolute path is NEVER in the public RunView — callers locate it here by * runId/nodeId, and it's re-validated to be inside the run dir (defense in * depth) before any read. Returns undefined for invalid id / traversal / no log. */ export declare function ptyLogPathFor(runsDir: string, runId: string, nodeId: string): string | undefined; export interface RunSummary { runId: string; runStatus: V3RunStatus; nodeCount: number; } /** List runs under `runsDir` (dirs that have a journal.ndjson), newest-first by * name (runIds carry a `-` stamp so name sort ≈ time sort). */ export declare function listRuns(runsDir: string): RunSummary[]; //# sourceMappingURL=ops-projection.d.ts.map