/** * Run a governed child in a herdr pane — ADR-0016 point 6. * * The second executor for the same plan. `runChild` spawns `pi` directly and captures its stdout; * `runHerdrPane` asks herdr to launch it in a visible, attachable terminal pane. `planSpawn` produces the * argv either way, so the grant is identical and only the *place it runs* differs. * * **Why go through herdr's CLI rather than the third-party `pi-herdr` extension.** That extension exposes * `agentArgs` and `env` as MODEL-facing tool parameters (R-30), which hands a model an argv array and the * environment variable the grant travels on. Here the model chooses a definition and a task; this package * builds the argv. Measured facts this relies on (probe `g16-herdr`): * * - `herdr agent start … -- ` delivers argv **verbatim**, echoed back in the reply. * - `--tools` is enforced inside a pane exactly as it is for a direct spawn; `--no-tools` yields none. * - `herdr agent start` has **no `--env`**, but `tab create` / `pane split` do, and a pane's environment * reaches the shell that launches the agent — verified by reading `$PI_DADDY_GRANT` back out of a * pane created with it. That is how the grant, depth and ledger path propagate on this path. * * **What a pane is not: a boundary.** It is a terminal. `--tools` remains the enforcement point, ADR-0012's * `bash` escape is unchanged, and a pane is *attachable by design*, so a human can type into a governed * child. Humans are not this project's threat model, but nothing here should be read as containing one. */ import type { ChildRunResult } from "../kernel/run-child.ts"; import { type HerdrExec } from "./herdr-cli.ts"; import { type PollTarget } from "./herdr-poll.ts"; /** * Re-exported so importers of the executor still reach the protocol at the name they always used. * * Deliberate rather than lazy: `test/run-herdr.test.ts` imports `HerdrExec` from here and must pass * **unmodified** across this extraction — that is the only available proof the move changed no behaviour. */ export { type HerdrExec, parseReply } from "./herdr-cli.ts"; /** Re-exported: `splitSystemPrompt` moved to `./herdr-stage.ts` under the ceiling, its tests import it here. */ export { splitSystemPrompt, stageSystemPrompt } from "./herdr-stage.ts"; /** Re-exported: the name rules moved to `./herdr-name.ts` under the ceiling; tests import them here. */ export { uniqueAgentName } from "./herdr-name.ts"; /** Re-exported after startup retry extraction; existing executor importers keep this public constant. */ export { PANE_READY_POLL_MS } from "./herdr-start.ts"; /** * Re-exported so `test/run-herdr.test.ts` and any importer keep reaching these where they always were. * * `POLL_INTERVAL_MS` and `newSuffix` moved to `./herdr-poll.ts` under the 400-line ceiling; the names are part * of this module's surface and moving a file should not move an export. */ export { DEFAULT_SNAPSHOT_LINES, POLL_INTERVAL_MS, readPane, tailLines, waitForLifecycleBaseline, waitForSettled, type PollTarget, } from "./herdr-poll.ts"; export interface HerdrRunRequest { /** `planSpawn` args **without** the prompt — see `prompt`. */ args: string[]; /** * The task, delivered with `herdr agent prompt` rather than as an argv element. * * This is strictly safer than the direct-spawn path, which has to defend a model-authored string from * pi's argv parser by prefixing a space (`neutralisePrompt`, probe `g1-argv`). Here the task never * reaches argv at all, so there is no parser in front of it. */ prompt: string; /** Grant/depth/ledger variables. Set on the PANE, which the agent's shell inherits. */ env: Record; cwd: string; /** Unique pane and agent name. */ name: string; /** herdr workspace to create the tab in. Omitted lets herdr choose. */ workspace?: string; signal?: AbortSignal; timeoutMs?: number; /** Inactivity bound and its progress probe (PR 3e); see `PollTarget`. */ idleTimeoutMs?: number; activityProbe?: PollTarget["activityProbe"]; maxOutputBytes?: number; /** * Leave the pane open after the run so a human can read or resume it. * * Default **false**: a fan-out that leaks a pane per child fills the operator's workspace, and * probe `g16-herdr` records that panes are not trivially closable once orphaned. */ keepPane?: boolean; exec?: HerdrExec; /** * The pane's last few lines, re-reported every poll — a SNAPSHOT the consumer REPLACES, not appends. * * **Display only**, exactly as in `runChild`: the child's answer is still the returned `text`. Unlike * `runChild`'s `onOutput`, this is not a stream: `agent read` returns a snapshot of a bounded terminal, and * the previous append-shaped design produced an 89,000× amplification once a pane scrolled or passed the * output cap. See `tailLines` in `./herdr-poll.ts`. * * Exceptions are swallowed; a renderer must not be able to break a governed run. */ onSnapshot?: (lines: string[]) => void; /** Available pane snapshots only, not a structured session transcript. Never awaited. */ onObservation?: (bytes: Uint8Array) => void; /** How many pane lines to report per poll. Defaults to `DEFAULT_SNAPSHOT_LINES`. */ snapshotLines?: number; /** * The pane id, reported as soon as `tab create` returns it. * * Separate from `onOutput` because it arrives once and arrives *early*: it is what lets the parent print a * name a human can switch to **while the child is alive**, which is the whole point of the pane surviving. */ onPane?: (paneId: string, agentName: string) => void; /** Called only after agent start and prompt both succeed; pane creation alone is still `starting`. */ onRunning?: (paneId: string, agentName: string) => void; /** Security hook for attaching a writer lease to the tab. Unlike display callbacks, errors fail the run. */ onTab?: (tabId: string) => void; /** Optional observation, unlike the required lease hook above. */ onNativeTab?: (tabId: string) => void; onSessionReference?: PollTarget["onSessionReference"]; /** Close even a settled pane before releasing a writer lease; no post-lease prompt may remain live. */ closeOnSettle?: boolean; /** Poll cadence override. Exists so tests do not wait `POLL_INTERVAL_MS` per state transition. */ pollIntervalMs?: number; } export declare class HerdrWriterCloseError extends Error { constructor(tabId: string); } /** * Run one governed child in a pane and return its output. * * Deliberately returns `ChildRunResult` — the same shape as `runChild` — so the extension can choose an * executor without knowing which one it got. */ export declare function runHerdrPane(request: HerdrRunRequest): Promise; //# sourceMappingURL=run-herdr.d.ts.map