import type { SourceLocationOpts } from "./state/checkpointStore.js";
import type { RuntimeContext } from "./state/context.js";
import type { State } from "./state/stateStack.js";
import { StateStack } from "./state/stateStack.js";
import type { ThreadStore } from "./state/threadStore.js";
import type { HandlerFn } from "./types.js";
/** Options bag for the new `Runner.thread(id, method, opts, callback)`
 *  signature. All fields are optional; emitter passes only the ones
 *  the user supplied via `thread(label: ..., summarize: ..., continue: ..., session: ...) { ... }`. */
export type ThreadStepOpts = {
    label?: string;
    summarize?: boolean;
    /** Slug form (e.g. "t3"). Stripped to raw counter id internally. */
    continueId?: string;
    /** Session name; runtime maps it to a thread id via openSession. */
    session?: string;
    /** When true, the created thread is excluded from `listThreads()`. */
    hidden?: boolean;
};
/** Strip the leading `t` from a public thread slug to recover the
 *  internal counter-string id. Only strips when the slug matches the
 *  canonical `t<digits>` shape so user-chosen ids that happen to
 *  begin with `t` (e.g. session names like `"telephone"`) are not
 *  silently mangled. */
export declare function stripSlug(slug: string): string;
/**
 * Runner centralizes step execution logic for generated Agency code.
 *
 * Each node/function gets its own Runner wrapping its State frame.
 * The builder assigns explicit step IDs that match the source map paths.
 * The Runner maintains a `path` array that tracks nesting depth —
 * push when entering a nested scope, pop when leaving.
 *
 * Halt propagation: when an interrupt or debug pause occurs, call runner.halt(result).
 * All subsequent step calls become no-ops.
 */
export declare class Runner {
    halted: boolean;
    haltResult: any;
    private ctx;
    private frame;
    private path;
    private nodeContext;
    private state;
    private moduleId;
    private scopeName;
    /** The StateStack this Runner is operating on. When the Runner is running
     * inside a fork/race branch, this is the branch's stack — and reading
     * `stack.abortSignal` lets us notice if the branch has been cancelled
     * (e.g., a race loser whose winner already resolved). */
    private stack?;
    /** ThreadStore active for this Runner's scope. Captured into the
     *  per-step AsyncLocalStorage frame so stdlib helpers that read
     *  `getRuntimeContext().threads` (e.g. the std::thread `*Message`
     *  builtins migrated off the context-injected pattern) see the same
     *  ThreadStore the codegen would otherwise have prepended as a
     *  positional arg. Optional so existing call sites (and the runner
     *  unit tests) keep working without passing it. */
    private threads?;
    constructor(ctx: RuntimeContext<any>, frame: State, opts?: {
        nodeContext?: boolean;
        state?: any;
        moduleId?: string;
        scopeName?: string;
        stack?: StateStack;
        threads?: ThreadStore;
    });
    /** Run `fn` inside an `agencyStore.run` frame seeded with this
     *  Runner's `ctx` / `stack` / `threads`. Stdlib helpers invoked from
     *  inside `fn` will see those values via `getRuntimeContext()` —
     *  matching what the deprecated `__ctx, __stateStack, __threads`
     *  positional args would have carried. If `stack` or `threads` is
     *  missing (older test harnesses that build a Runner without them),
     *  fall through to whatever frame is already on the ALS stack to
     *  avoid clobbering an outer frame with `undefined`. */
    private runInScope;
    /** Whether this runner is driving a graph-node body (vs. a function or
     *  resumable-scope body). TS helpers that need to produce the same halt
     *  payload shape as the codegen `interrupt` templates (`{messages, data}`
     *  in a node body, raw `data` in a function body) read this. Public to
     *  let `agency.interrupt` mirror the codegen branch without exposing
     *  the rest of Runner internals. */
    get isNodeContext(): boolean;
    /** The current step path as a string, e.g. "1.0.2" */
    key(): string;
    /** Return checkpoint metadata for the current step. */
    getCheckpointInfo(): SourceLocationOpts;
    private getCounter;
    private setCounter;
    halt(result: any): void;
    /** Resume any paused guards on the active stack. Idempotent — a
     *  guard already in "running" state no-ops. Called at the top of
     *  every step-equivalent entry point (step, hook, pipe, thread,
     *  fork, debugger). After a halt, the first step entry re-arms
     *  TimeGuards' timers; subsequent entries within the same active
     *  window are no-ops. Also rebuilds non-serialized runtime state
     *  (AbortController, abortSignal composition) after deserialization. */
    private beforeStep;
    private _break;
    private _continue;
    /** Signal the current loop to break after this iteration */
    breakLoop(): void;
    /** Signal the current loop to continue to the next iteration */
    continueLoop(): void;
    /** Check if execution should skip (halted, breaking, or continuing).
     *  Also halts if the runner's branch stack has been aborted — but
     *  if any guard's `check()` reports a trip, throw the structured
     *  GuardExceededError instead of silently halting. That lets the
     *  stdlib `guard` function's `try block()` convert it to a Failure
     *  with maxTime/actualTime (or maxCost/actualCost). Race-loser
     *  branch cancels (no guard tripped) still halt silently.
     *
     *  Three-way decision when `abortSignal.aborted`:
     *   1. Some guard.check() returns an error → throw it (first trip
     *      reaches user code via stdlib `guard`'s `try`).
     *   2. No guard returns an error but some guard.isTripped() → the
     *      abort came from a guard whose trip is already consumed
     *      (caught by `try`). The popGuard cleanup steps still need to
     *      run, so don't halt; fall through.
     *   3. No guard returns an error and none isTripped() → external
     *      abort (race-loser branch cancel). Halt silently as before. */
    private shouldSkip;
    /**
     * Fires the debug/trace hook for a step. Returns truthy if the debugger
     * wants to pause (in which case the caller should halt).
     *
     * Uses a flag in frame.locals to avoid re-triggering on resume:
     * - First entry: no flag → fire hook → if it halts, set flag
     * - Resume: flag exists → skip hook → run code → clean up flag
     *
     * The flag is NOT deleted here on resume. Instead, step() deletes it
     * after the callback completes without halting. This handles the case
     * where a step halts due to a nested interrupt (e.g., function call
     * that pauses) — the flag stays set so the next resume skips the hook.
     */
    private maybeDebugHook;
    /** Clean up the debug flag for a step after it completes without halting. */
    private clearDebugFlag;
    private stepPath;
    private debugFlagKey;
    /** Seed branch.stack.localCost / localTokens from the parent stack
     *  unless they're already populated (e.g., restored from a checkpoint
     *  on resume). Idempotent.
     *
     *  Also records `seedCost` / `seedTokens` — the IMMUTABLE baseline used
     *  later by propagateBranchCost to compute this branch's delta. Storing
     *  the baseline on the branch (rather than re-reading the parent at
     *  join time) means the delta survives the parent being mutated in the
     *  meantime — e.g. race losers propagating their spend into the parent
     *  before the winner resumes. See docs/superpowers/specs/2026-05-20-
     *  thread-builtins-and-stdlib-design.md. */
    private seedBranchCost;
    /** Propagate cost/token deltas from a set of branches back to the
     *  outer stack. Delta = branch.localCost - branch.seedCost (the baseline
     *  captured when the branch was seeded). Using the per-branch seed
     *  rather than the parent's current totals is what makes the math
     *  correct when sibling branches have already propagated their spend
     *  into the parent (race losers → parent before winner resumes).
     *  Caller invokes this BEFORE popBranches() or deleteBranch —
     *  otherwise the branch stacks are gone. */
    private propagateBranchCost;
    step(id: number, callback: (runner: Runner) => Promise<void>): Promise<void>;
    /**
     * Fire a codegen-emitted callback hook (onFunctionStart, onNodeStart,
     * onNodeEnd, onEmit) as a substep-counter-idempotent step. Unlike
     * `runner.step`, this does NOT call `maybeDebugHook` — codegen-emitted
     * hook sites have no user-visible source line, so pausing on them
     * would surprise the user (single-step would land on an internal hook
     * with no current line).
     *
     * Callback bodies cannot raise interrupts (statically forbidden by the
     * typechecker — see `checkCallbackBodyInterrupts`), so `bodyFn` is
     * fire-and-forget. The substep counter advances after `bodyFn`
     * resolves so resume re-entries (after a deeper interrupt or debug
     * pause) skip the hook instead of re-firing it.
     */
    hook(id: number, bodyFn: () => Promise<void>): Promise<void>;
    debugger(id: number, label: string): Promise<void>;
    pipe(id: number, input: any, fn: (value: any) => any): Promise<any>;
    thread(id: number, method: "create" | "createSubthread", opts: ThreadStepOpts, callback: (runner: Runner) => Promise<void>): Promise<void>;
    handle(id: number, handlerFn: HandlerFn, callback: (runner: Runner) => Promise<void>): Promise<void>;
    ifElse(id: number, branches: {
        condition: () => boolean | Promise<boolean>;
        body: (runner: Runner) => Promise<void>;
    }[], elseBranch?: (runner: Runner) => Promise<void>): Promise<void>;
    loop(id: number, items: any[] | Record<string, any>, callback: (item: any, index: number, runner: Runner) => Promise<void>): Promise<void>;
    whileLoop(id: number, condition: () => boolean | Promise<boolean>, callback: (runner: Runner) => Promise<void>): Promise<void>;
    branchStep(id: number, branchKey: string, callback: (runner: Runner) => Promise<void>): Promise<void>;
    /**
     * Run blockFn for each input in parallel. Each branch gets its own
     * BranchState (StateStack) for isolation and serialization.
     *
     * mode "all" (fork): waits for all, returns results array.
     * mode "race": returns first to complete.
     *
     * blockFn receives (item, index, branchStack) where branchStack is the
     * branch's isolated StateStack (new or deserialized from interrupt).
     *
     * If any branch (fork) or the winner (race) interrupts, returns an
     * `Interrupt[]` — the caller (generated code) detects this via
     * `hasInterrupts(...)` and halts. All concurrent interrupts are batched
     * into the same array under a single shared checkpoint.
     */
    fork(id: number, items: any[], blockFn: (item: any, index: number, branchStack: StateStack) => Promise<any>, mode: "all" | "race", stateStack: StateStack): Promise<any>;
    /** Run all branches in parallel (fork mode). Returns an array of values,
     * or an Interrupt[] if any branch interrupted.
     *
     * Thin adapter over `runBatch({ mode: "all" })`. The primitive owns:
     * branch lifecycle, abort composition, settle, leaf checkpoint capture,
     * shared checkpoint stamp + intr.checkpoint overwrite, popBranches on
     * success. This adapter wires up the fork-specific statelog events and
     * cost propagation. */
    private runForkAll;
    /** Run all branches concurrently but return as soon as one settles.
     *
     * Thin adapter over `runBatch({ mode: "race" })`. The primitive owns
     * branch lifecycle, abort composition, settle (`Promise.race` with
     * loser abort), shared checkpoint stamp + intr.checkpoint overwrite,
     * winner-index persistence under `raceWinnerLocalKey`, loser-branch
     * deletion, and resume dispatch (re-running only the recorded winner
     * when a persisted winner is present). The adapter wires up race-
     * specific statelog events and the asymmetric cost-propagation hooks:
     * losers propagate eagerly at race time, winner propagates when it
     * finally completes (no-interrupt resume). */
    private runRace;
    private raceWinnerKey;
    private forkBranchKey;
    private forkResultKey;
}
