import { type ContextData } from "@boardwalk-labs/workflow/runtime"; import { type HostCapabilities } from "./host_server.js"; /** * Link THIS runtime's `@boardwalk-labs/workflow` into the exec dir's `node_modules` so the program's * bare import resolves from ANY program root — this link, not an ancestor `node_modules`, is what * makes resolution work. A symlink — not a copy — is load-bearing: Node resolves it to the REAL * path, so the program gets the same module instance the loader's protocol client was installed * on (the active-host singleton in the SDK's host_client). `junction` covers Windows without * elevation; a failed link is only logged, since a resolvable ancestor may still exist. */ export declare function ensureSdkLink(execDir: string): Promise; /** Resolve the program's entry module inside the extraction dir, refusing any path that escapes it. * The control plane validates `entry` at deploy, but a self-hosted runner may be pointed at an * arbitrary control plane, so this is defense-in-depth: an absolute path or a `..` that resolves * outside `dir` throws rather than importing code from elsewhere on the machine. */ export declare function resolveEntryPath(dir: string, entry: string): string; /** * Resolve a program entry by LANGUAGE, binding the ratified artifact layout: a TS/JS entry is a * BUILT module at the artifact root (`index.mjs` — the CLI bundles, the api-server type-strips); * a `.py` entry is a SOURCE path under `.bw-src/` (`main.py` ⇒ `/.bw-src/main.py` — Python * has no bundle step, the shipped source is what runs). A leading `./` on the stored entry is * tolerated (`join` collapses it). Both lanes keep the containment guard; for Python the guard's * base is the `.bw-src` tree itself, so an escaping entry (`../evil.py`) is rejected even when * it would still land inside the extract dir. */ export declare function resolveProgramEntryPath(dir: string, entry: string): string; /** * Enforce I2: the extracted program must not live inside the run's workspace. Compares RESOLVED * paths, and treats "the workspace itself" as inside. */ export declare function assertProgramRootOutsideWorkspace(programRoot: string, workspaceRoot: string): void; export interface RunProgramArgs { /** Run id — used for the temp dir path + correlation. */ runId: string; /** The VERIFIED program artifact tarball (sha256 already checked against the pinned digest). */ tarball: Uint8Array; /** Entry module to import after extraction (a safe relative POSIX path). TS/JS: the BUILT * module at the artifact root (`index.mjs`). Python: the SOURCE path relative to the * artifact's `.bw-src/` tree (`main.py` ⇒ `.bw-src/main.py` on disk). */ entry: string; /** The run's RAW JSON input (trigger payload / inline input). The revival pass is CLIENT-side. */ input: unknown; /** The stored derived input schema (`null` for an untyped workflow) — carried on `bootstrap` * so the SDK revives rich fields (`date-time` → `Date`, base64 → `Uint8Array`, …). */ inputSchema: Record | null; /** The stored derived output schema (`null` ⇒ the return persists unvalidated). */ outputSchema: Record | null; /** The context DATA for `bootstrap` (P3.3) — the client builds the live `Context` from it. */ context: ContextData; } export interface ProgramRunnerDeps { /** The capability seam the host server dispatches onto (agent leaf, sleep hold, child calls, * secrets, shell, usage, auth, browser, phase). */ capabilities: HostCapabilities; /** * The run's `/workspace` — the working directory AND `HOME` for author code (I1). Must already * exist (the orchestrator's `ensureWorkspace` guarantees it); a missing workspace fails the run * loudly rather than silently running from wherever the process happened to start. */ workspaceRoot: string; /** * Root the program artifact extracts under. MUST be outside {@link workspaceRoot} (I2) — * enforced, because a bundle inside the workspace is tarred into every pre-sleep snapshot. */ programRoot: string; /** * Extract a gzipped tar file into a directory (created already). System `tar` in production * (matches WorkspaceArchiver); injected in tests. */ extract: (tgzPath: string, destDir: string) => Promise; /** * Called once with the extracted program directory, right after the artifact is unpacked * (before `run()` is invoked). The worker uses it to point the `agent()` leaf at the run's * bundled files (`/skills/.md`). */ onExtracted?: (programDir: string) => void; /** * Scrubs known secret values out of a string (the run's `SecretRedactor.redactText`). Applied * to a thrown error's message/code/hint before logging + finalize. Defaults to identity. */ redactText?: (text: string) => string; /** * Called once with the run's reported return IFF it is non-null (a void return sends null, * which is not an author-declared output). The worker wires this to emit an `output` activity * entry into the run's event log. Best-effort: it must not throw. */ onOutput?: (value: unknown) => void; /** * The run's cooperative-cancellation signal. The host server pushes the `cancel` notification * to the program when it fires (the SDK aborts `context.signal`); the capability layer already * honors it server-side at every hook. */ signal?: AbortSignal | undefined; /** Override the socket directory (tests). Default `os.tmpdir()` (short paths — sun_path cap). */ sockDir?: string | undefined; /** Interpreter a `.py` entry is launched with (P5.5). Default `python3`, resolved on PATH — * the base image bakes one CPython (P5.3). May be an absolute path. */ pythonInterpreter?: string | undefined; /** How long after SIGTERM an aborted Python child gets before SIGKILL. Default 5s. */ pythonKillGraceMs?: number | undefined; } /** Terminal result of running a workflow program. `output` is the validated value `run()` * returned (`null` for void); for a failure it's null and `error` is set. A waiting seam never * surfaces here — it freezes with the VM or holds the process, and `run()` simply continues. */ export type ProgramResult = { kind: "completed"; output: unknown; } | { kind: "failed"; output: null; error: { code: string; message: string; hint?: string; }; }; /** * Run a workflow program to completion: start the host-protocol server, extract the VERIFIED * artifact, drive the loader (`bootstrap` → import entry → `run(input, context)` → * `reportReturn`), and return the terminal result. Always tears the server + temp tree down. */ export declare function runWorkflowProgram(args: RunProgramArgs, deps: ProgramRunnerDeps): Promise;