import type { MessageJSON } from "smoltalk";
import { type Interrupt } from "./interrupts.js";
import { type RunBatchResult } from "./runBatch.js";
import type { SourceLocationOpts } from "./state/checkpointStore.js";
import type { RuntimeContext } from "./state/context.js";
import type { State, StateStack } from "./state/stateStack.js";
/**
 * Thrown by {@link PromptRunner.step} when a step body returns interrupts.
 *
 * Caught only at the top of `runPrompt`, which extracts the batched
 * `interrupts` and returns them as `runPrompt`'s result so the generated
 * caller can checkpoint and propagate them. NEVER propagates outside
 * `lib/runtime/prompt.ts`.
 */
export declare class PromptBailout extends Error {
    readonly interrupts: Interrupt[];
    constructor(interrupts: Interrupt[]);
}
/**
 * Frame-backed completion tracking. Lives on `self.runnerState` so it
 * survives checkpoint/restore the same way `self.messagesJSON` does:
 * the frame's `locals` object is what gets serialized. An array (used
 * as a set) keeps the format JSON-safe and matches the project's
 * "arrays instead of sets" convention.
 */
export type RunnerState = {
    completedSteps: string[];
};
export type PromptRunnerOpts = {
    /** Frame-local `self` object (== the function's locals bag). */
    self: any;
    ctx: RuntimeContext<any>;
    stateStack: StateStack;
    /** The runPrompt frame (== `stateStack.lastFrame()`). Used by
     * `parallel()` as `runBatch`'s `parentFrame` for per-tool branch
     * lifecycle. Defaulted from `stateStack.lastFrame()` for callers that
     * don't pass it explicitly. */
    parentFrame?: State;
    /** Source location of the surrounding generated call site. Used as the
     *  base `stepPath` when stamping a checkpoint on bailout — see
     *  `step()` for the per-key suffix.  */
    checkpointInfo: SourceLocationOpts | undefined;
    /** Callback that snapshots the current message thread JSON. Called only
     *  on bailout so it doesn't pay the cost on the happy path. */
    snapshotMessages: () => MessageJSON[];
};
/**
 * Control-flow helper for `runPrompt`. Owns the idempotent-step +
 * checkpoint-on-interrupt machinery so the surrounding `runPrompt`
 * body can be a linear script.
 *
 * See `docs/superpowers/plans/2026-05-22-prompt-runner.md`.
 */
export declare class PromptRunner {
    private opts;
    constructor(opts: PromptRunnerOpts);
    /**
     * Run `body` as an idempotent step, identified by `key`.
     *
     * If `key` is already recorded as completed (resume case), this is a
     * no-op. Otherwise the body runs:
     *   - if it returns `Interrupt[]`, snapshot messages, stamp a
     *     checkpoint (non-pinned, matching `Runner`'s interrupt
     *     checkpoints), attach the checkpoint id to every interrupt, and
     *     throw `PromptBailout` so `runPrompt` can return the batch up
     *     the stack. The key is NOT marked completed — on resume, the
     *     step re-enters, the body re-runs, and the saved
     *     `__interruptId_N` matches the user's response.
     *   - if it returns nothing (the happy path), the key is marked
     *     completed so the next resume skips this step.
     *
     * The checkpoint's `stepPath` is `${checkpointInfo.stepPath}/${key}`
     * so multiple steps within one `runPrompt` produce distinct
     * checkpoints. Without this they would all share the runPrompt-level
     * `stepPath` and the checkpoint store could not tell them apart on
     * resume.
     */
    step(key: string, body: () => Promise<Interrupt[] | void>): Promise<void>;
    /**
     * Run `branchFn` concurrently for every item in `items`. Each call
     * receives a {@link BranchRunner} which exposes its own `step()` that
     * COLLECTS interrupts rather than throwing — siblings keep running
     * even when one halts so we can batch all interrupts into a single
     * shared checkpoint.
     *
     * Thin adapter over {@link runBatch} with `mode: "all"` and
     * `recordBranchOutcomes: false` (the caller's `branchFn` body manages
     * branch state itself via `stack.setResultOnBranch` / `deleteBranch`).
     * `runBatch` owns: per-branch abort composition, ALS-isolated invoke,
     * settle, shared checkpoint stamp at
     * `${checkpointInfo.stepPath}/${keyPrefix}` with
     * `intr.checkpoint`/`checkpointId` overwrite, and `popBranches` on
     * the no-interrupt success path. Returns a {@link RunBatchResult}
     * tagged union — `"interrupts"` if any branch halted (the caller
     * bails out of runPrompt with `result.interrupts`), `"values"`
     * otherwise.
     *
     * `keyFor(item, i)` MUST produce the same branch key the `branchFn`
     * body uses for its `stack.getOrCreateBranch(...)` — otherwise
     * `runBatch` would allocate a separate branch from the one the body
     * manages, and the leaf-checkpoint vehicle into State.toJSON's
     * branches walk would be lost.
     *
     * IMPORTANT: do NOT call `pr.step(...)` (which throws `PromptBailout`)
     * from inside a branch — use `b.step(...)` instead. A throw from
     * `branchFn` propagates out of `runBatch` and aborts the whole batch.
     */
    parallel<T>(keyPrefix: string, items: T[], keyFor: (item: T, index: number) => string, branchFn: (item: T, b: BranchRunner) => Promise<void>): Promise<RunBatchResult<void>>;
}
/**
 * Branch-local step runner produced by {@link PromptRunner.parallel}.
 *
 * Differs from `PromptRunner.step` in two ways:
 *   - On interrupt, collects them on `this.interrupts` rather than
 *     throwing. The parallel orchestrator merges across siblings.
 *   - All subsequent `step()` calls on the same branch short-circuit
 *     once `interrupts` is set — the branch is effectively halted.
 *
 * Completion keys live on the same `self.runnerState.completedSteps`
 * map as the outer runner, so callers must pick keys that are unique
 * per-branch (e.g. include the per-item id in the key).
 */
export declare class BranchRunner {
    private self;
    interrupts: Interrupt[] | null;
    constructor(self: any);
    step(key: string, body: () => Promise<Interrupt[] | void>): Promise<void>;
}
