import { S as StepAgentActivity } from '../agent-activity-C8ZG0F0M.js';
export { W as WithAgentActivity, s as stepAgentActivity } from '../agent-activity-C8ZG0F0M.js';

/**
 * Durable mission state — the guarded status machine for a multi-step agent run.
 *
 * A mission is a persisted plan (ordered steps), a cursor (count of completed
 * steps), a cost ledger + budget, and a status machine. This module owns the
 * legal transitions and the guarded mutation surface; it does NOT execute steps
 * (the engine in `./engine` does) and it does NOT own persistence — products
 * implement {@link MissionStorePort} over their own tables. Every state change
 * appends a {@link MissionAuditEvent} so the run timeline is a single durable
 * audit trail.
 *
 * Concurrency contract: a mission MUST be driven by a single serialized owner
 * (a Durable Object, a Cloudflare Workflow, a queue consumer — one per
 * mission). The service is the typed guard layer, not a serializer: every
 * mutation re-reads the record and asks the store for a compare-and-set write
 * guarded on the values it read. When the guard misses, the row changed under
 * us and the caller gets `{ succeeded: false, conflict: true }` — never a
 * silent clobber, never a stale overwrite.
 */
type MissionStatus = 'scheduled' | 'running' | 'paused' | 'waiting_approval' | 'blocked' | 'succeeded' | 'failed' | 'aborted' | 'cancelled';
type MissionStepStatus = 'pending' | 'running' | 'waiting_approval' | 'done' | 'failed';
interface MissionStep {
    id: string;
    /** What the step should accomplish — an intent, never an implementation. */
    intent: string;
    /** Product-defined kind label. Labels intent for gating/UX; it never selects
     *  a different execution path. */
    kind: string;
    status: MissionStepStatus;
    /** Count of genuine `* -> running` edges (retries inflate this; idempotent
     *  re-asserts do not). */
    attempts: number;
    /** One-line live status surfaced on the step row ("7/15 refs"). */
    sublabel?: string;
    /** Small pointer at the produced artifact (vault path, asset id) — never the
     *  full payload. */
    resultRef?: string;
}
interface MissionCostLedger {
    tokensIn: number;
    tokensOut: number;
    costUsd: number;
    wallMs: number;
    llmCalls: number;
}
/** The durable mission row, shape-normalized. Timestamps are epoch ms. */
interface MissionRecord {
    id: string;
    workspaceId: string;
    status: MissionStatus;
    /** Product-defined origin label ('chat', 'manual', 'cron', …). */
    trigger: string;
    summary: string | null;
    plan: MissionStep[];
    /** Count of durably-completed steps; the next step to run is `plan[cursor]`. */
    cursor: number;
    cost: MissionCostLedger | null;
    budgetUsd: number | null;
    spentUsd: number;
    pauseReason: string | null;
    /** The single owning engine's instance id, write-once (see `setEngineRef`). */
    engineRef: string | null;
    scheduledAt: number | null;
    startedAt: number;
    completedAt: number | null;
    metadata: Record<string, unknown> | null;
}
/**
 * Discriminated outcome for guarded operations. Callers MUST inspect
 * `succeeded` before reading `value` — illegal transitions and missing rows
 * surface here, never as a throw-and-swallow or a silent no-op. `conflict`
 * distinguishes a lost guarded race (retryable — re-read and re-apply) from a
 * logic rejection (illegal edge, missing step — deterministic, never retried).
 */
type MissionOutcome<T> = {
    succeeded: true;
    value: T;
} | {
    succeeded: false;
    error: string;
    conflict: boolean;
};
/** Fields a guarded write compares against the values the caller read. A SQL
 *  implementation compares JSON columns as serialized text
 *  (`coalesce(col, 'null') = JSON.stringify(expected)`), matching how the
 *  in-memory store compares. An absent field is unguarded. */
interface MissionUpdateGuard {
    status?: MissionStatus;
    cursor?: number;
    plan?: MissionStep[];
    cost?: MissionCostLedger | null;
    metadata?: Record<string, unknown> | null;
    /** Guard that no engine has bound yet (the write-once bind). */
    engineRefIsNull?: true;
}
/** Fields a guarded write sets when the guard holds. `null` values are real
 *  writes (clear the column), not skips. */
interface MissionUpdatePatch {
    status?: MissionStatus;
    pauseReason?: string | null;
    summary?: string;
    completedAt?: number | null;
    plan?: MissionStep[];
    cursor?: number;
    cost?: MissionCostLedger;
    spentUsd?: number;
    metadata?: Record<string, unknown>;
    engineRef?: string;
}
/** One audit-trail row. Appended after every committed state change, so an
 *  event always denotes a real transition (no phantom rows on rejected or
 *  no-op calls). */
interface MissionAuditEvent {
    missionId: string;
    workspaceId: string;
    level: 'info' | 'warn' | 'error';
    /** Machine-readable transition name ('mission.created', 'mission.step.done',
     *  'mission.cursor', 'mission.cost', 'mission.paused', …). */
    step: string;
    message: string;
    metadata: Record<string, unknown>;
    at: number;
}
/**
 * Persistence seam — the product implements this over its own tables. The
 * invariant the implementation MUST keep: `update` applies `patch` ONLY when
 * every guard field still equals the stored value, and returns `null` when the
 * guard misses. That null is how a concurrent write surfaces as a typed
 * failure instead of a clobber.
 */
interface MissionStorePort {
    load(id: string): Promise<MissionRecord | null>;
    /** `extras` are the opaque product-column values from
     *  `CreateMissionInput.extras` — write them in the SAME statement as the
     *  record (single-write creation) or ignore them if the table has no extra
     *  columns. */
    insert(record: MissionRecord, extras?: Record<string, unknown>): Promise<MissionRecord>;
    update(id: string, guard: MissionUpdateGuard, patch: MissionUpdatePatch): Promise<MissionRecord | null>;
    appendEvent(event: MissionAuditEvent): Promise<void>;
}
/** Statuses a mission can never leave — the run is done. */
declare function isMissionTerminal(status: MissionStatus): boolean;
/** The cooperative kill switch: a stop request rides metadata so it survives
 *  any status and is honored by the engine before the next side effect. */
declare function isMissionStopRequested(mission: MissionRecord): boolean;
interface CreateMissionInput {
    /** Explicit row id. Omit to use the service's id generator. Pass a
     *  DETERMINISTIC id (derived from the originating turn) when the caller may
     *  re-create the same mission under at-least-once delivery — the duplicate
     *  insert then trips the store's uniqueness instead of spawning a second run. */
    id?: string;
    workspaceId: string;
    /** Becomes the mission summary. */
    title: string;
    /** Plan step ids MUST be unique: the owning workflow keys its durable step
     *  cache by step id, so a collision would silently replay the wrong result.
     *  A duplicate is rejected here (fail loud). */
    plan: MissionStep[];
    budgetUsd?: number | null;
    /** Epoch ms. Present → the mission starts `scheduled` instead of `running`. */
    scheduledAt?: number | null;
    trigger: string;
    /** Caller-defined context stamped onto the record (thread ids, source turn,
     *  model). Read back via `mission.metadata`; the engine only reads
     *  `stopRequested` from it. */
    metadata?: Record<string, unknown> | null;
    /**
     * Opaque product-column values handed VERBATIM to `MissionStorePort.insert`
     * (e.g. a `workflowId` FK on the product's mission table), so creation is a
     * single write — no post-insert stamp. The service never reads, validates,
     * or persists them itself; they exist only on the insert call.
     */
    extras?: Record<string, unknown>;
}
interface SetStepStatusPatch {
    sublabel?: string;
    resultRef?: string;
    error?: string;
    /**
     * Spend committed ATOMICALLY with the step transition. Folding the cost into
     * the SAME guarded write makes step completion the per-step idempotency key:
     * a same-status replay (the step is already `done`) short-circuits as a no-op
     * BEFORE the write, so the charge lands exactly once even when an engine
     * RESUME re-dispatches a step whose cost previously committed. `deltaUsd` is
     * the marginal spend; `ledgerDelta` carries the token/wall/llm breakdown.
     */
    cost?: {
        deltaUsd: number;
        ledgerDelta?: Partial<MissionCostLedger>;
    };
}
interface CompleteMissionInput {
    ok: boolean;
    summary?: string;
}
interface MissionService {
    createMission(input: CreateMissionInput): Promise<MissionRecord>;
    getMission(id: string): Promise<MissionRecord | null>;
    /** Bind the executing engine's instance id, write-once from the single
     *  owner: re-asserting the same ref is a no-op; binding a DIFFERENT ref over
     *  an existing one is rejected so a second owner can never steal the run. */
    setEngineRef(id: string, engineRef: string): Promise<MissionOutcome<MissionRecord>>;
    /** Shallow-merge keys into metadata. Guarded on the metadata read, so racing
     *  merges surface as conflicts instead of silently dropping keys. */
    mergeMetadata(id: string, patch: Record<string, unknown>): Promise<MissionOutcome<MissionRecord>>;
    /** Mutate one plan step's status (+ optional sublabel/resultRef) and append a
     *  transition event. Rejects unknown steps and illegal step edges. Does NOT
     *  move the cursor — call `advanceCursor` for that. */
    setStepStatus(id: string, stepId: string, status: MissionStepStatus, patch?: SetStepStatusPatch): Promise<MissionOutcome<MissionRecord>>;
    /** Move the done-count cursor forward by one. Rejects advancing past the end
     *  of the plan so the caller learns the mission has no further work. */
    advanceCursor(id: string): Promise<MissionOutcome<MissionRecord>>;
    /** Increment spentUsd and merge a partial ledger into the cumulative ledger.
     *  `deltaUsd` is the marginal spend; `ledgerDelta` carries the token/wall/
     *  llm-call breakdown for the same unit of work. */
    addCost(id: string, deltaUsd: number, ledgerDelta?: Partial<MissionCostLedger>): Promise<MissionOutcome<MissionRecord>>;
    pause(id: string, reason: string): Promise<MissionOutcome<MissionRecord>>;
    resume(id: string): Promise<MissionOutcome<MissionRecord>>;
    abort(id: string): Promise<MissionOutcome<MissionRecord>>;
    /** Flip one step and the whole mission to waiting_approval together. The
     *  mission transition is validated FIRST so an illegal source is rejected
     *  without mutating the step — no half-applied state. */
    markWaitingApproval(id: string, stepId: string): Promise<MissionOutcome<MissionRecord>>;
    complete(id: string, input: CompleteMissionInput): Promise<MissionOutcome<MissionRecord>>;
}
interface MissionServiceOptions {
    store: MissionStorePort;
    /** Injectable clock (epoch ms). Default `Date.now`. */
    now?: () => number;
    /**
     * Row-id generator when `CreateMissionInput.id` is omitted. Default
     * `crypto.randomUUID()` — a 36-char dashed UUID. Inject your own when your
     * mission table already has an id shape (e.g. 32-hex matching D1 row
     * defaults): the service stamps the generated id verbatim onto the inserted
     * record, so a mismatch with the rest of your schema surfaces only at the
     * product layer. Keep id shape parity here, not in the store.
     */
    generateId?: () => string;
}
declare function createMissionService(options: MissionServiceOptions): MissionService;
interface InMemoryMissionStore extends MissionStorePort {
    /** The full audit trail, append order. */
    events(): MissionAuditEvent[];
    /** Unguarded direct write — simulates a concurrent owner or a crash-shaped
     *  state in tests. Production writers go through the guarded `update`. */
    put(record: MissionRecord): void;
}
/**
 * In-memory {@link MissionStorePort} — the portable backend for tests and
 * sandbox/eval shells. Guard comparison uses JSON serialization of the read
 * value, the same contract a SQL implementation honors by comparing stored
 * JSON text. Records are deep-copied on every boundary so callers can never
 * mutate stored state around the guards.
 */
declare function createInMemoryMissionStore(): InMemoryMissionStore;

/**
 * Shared mission realtime contract — the single source of truth for the typed
 * events the engine BROADCASTS over a live channel and the client REDUCES into
 * live mission state. Server emit and client reduce import the same module so
 * the wire shape can never drift between the two ends.
 *
 * This module is CLIENT-SAFE: no server imports, no platform globals, no DB
 * types. It is pure data + a pure reducer. Keep it that way — a server-only
 * import here would leak into the browser bundle.
 *
 * Sink contract — best-effort UI notification, never load-bearing:
 *   - fire-and-forget: the engine never awaits `emit` and a sink failure can
 *     never fail a step (the engine wraps every emit). The durable audit-event
 *     row is the authoritative timeline; the socket is a convenience.
 *   - replay-safe: the engine re-emits on a resume/replay. The reducer below is
 *     idempotent + order-tolerant, so a re-sent or duplicated event converges.
 *     The sink itself does no dedupe.
 */

interface MissionEventSink {
    emit(event: MissionStreamEvent): void;
}
/** A sink that drops every event — the engine default when no live channel is
 *  wired (and the unit-test default). */
declare const noopEventSink: MissionEventSink;
/** Workspace-wide channel id missions broadcast on (alongside any per-thread
 *  channel the product keys). */
declare const MISSION_CONTROL_CHANNEL_ID = "missions";
/** One plan step as it appears on the wire — only what a live UI needs
 *  (`sublabel` updates travel separately via `step.updated` so the snapshot
 *  stays small). */
interface MissionStreamStep {
    id: string;
    intent: string;
    kind: string;
    status: MissionStreamStepStatus;
}
type MissionStreamStepStatus = 'pending' | 'running' | 'done' | 'failed' | 'waiting_approval';
type MissionStreamStatus = 'scheduled' | 'running' | 'paused' | 'waiting_approval' | 'succeeded' | 'aborted' | 'cancelled' | 'failed';
/**
 * Discriminated union of every live mission event. Every member carries
 * `missionId` (one channel may multiplex several missions) and a `type` the
 * client switches on. `at` is the emitter's wall-clock ms — used only for
 * display ordering; the reducer never trusts it for causality.
 */
type MissionStreamEvent = {
    type: 'mission.created';
    missionId: string;
    at: number;
    title: string;
    status?: MissionStreamStatus;
    steps: MissionStreamStep[];
    budgetUsd?: number | null;
} | {
    type: 'mission.started';
    missionId: string;
    at: number;
} | {
    type: 'step.started';
    missionId: string;
    at: number;
    stepId: string;
} | {
    type: 'step.updated';
    missionId: string;
    at: number;
    stepId: string;
    sublabel?: string;
    /**
     * Full CURRENT snapshot of the step's delegated runs — never a delta.
     * The reducer replaces the whole lane (latest snapshot wins by `at`), so
     * emitters re-send everything they know each time and at-least-once /
     * out-of-order delivery converges.
     */
    agentActivity?: StepAgentActivity[];
} | {
    type: 'step.completed';
    missionId: string;
    at: number;
    stepId: string;
    ok: boolean;
    reason?: string;
    durationMs?: number;
} | {
    type: 'cost.updated';
    missionId: string;
    at: number;
    spentUsd: number;
    capUsd?: number | null;
} | {
    type: 'mission.paused';
    missionId: string;
    at: number;
    reason?: string;
} | {
    type: 'mission.waiting_approval';
    missionId: string;
    at: number;
    reason?: string;
} | {
    type: 'mission.resumed';
    missionId: string;
    at: number;
} | {
    type: 'mission.plan.updated';
    missionId: string;
    at: number;
    title: string;
    steps: MissionStreamStep[];
    budgetUsd?: number | null;
} | {
    type: 'mission.completed';
    missionId: string;
    at: number;
    ok: boolean;
    status?: Extract<MissionStreamStatus, 'succeeded' | 'failed' | 'aborted' | 'cancelled'>;
    summary?: string;
};
/**
 * Reconstruct the flat MissionStreamEvent from a broadcast envelope of shape
 * `{ type, data: { ...missionFields } }` (transports may also stamp routing
 * fields like workspaceId/threadId into `data`). The envelope `type` is the
 * AUTHORITATIVE discriminant set by the server, so it is spread LAST — a
 * payload that happens to carry a top-level `type` inside `data` cannot shadow
 * it and mis-render as a mission event. Non-mission envelopes and malformed
 * payloads return null and are simply skipped, so one channel can carry both
 * streams.
 */
declare function parseSessionStreamEnvelope(raw: unknown): MissionStreamEvent | null;
/** Narrow an arbitrary channel payload to a MissionStreamEvent. Returns null
 *  for non-mission events and anything malformed — the reducer skips those. */
declare function asMissionStreamEvent(value: unknown): MissionStreamEvent | null;
/** Live per-step view the reducer maintains. `status` only ever moves FORWARD
 *  (see STEP_RANK) so a duplicate/out-of-order event can never regress a step
 *  from done back to running. */
interface MissionStepState {
    id: string;
    intent: string;
    kind: string;
    status: MissionStreamStepStatus;
    sublabel?: string;
    reason?: string;
    durationMs?: number;
    /** Latest delegated-run snapshot for the step (see `step.updated`). */
    agentActivity?: StepAgentActivity[];
    /** The `at` of the snapshot currently held — an older snapshot arriving
     *  late never replaces a newer one. */
    agentActivityAt?: number;
}
/** Live per-mission view the reducer folds events into. */
interface MissionState {
    missionId: string;
    title?: string;
    status: MissionStreamStatus;
    steps: MissionStepState[];
    spentUsd: number;
    capUsd?: number | null;
    pauseReason?: string;
    summary?: string;
    /** The largest `at` folded so far — purely for display; never gates folding. */
    lastEventAt: number;
    /** The largest pause/resume control `at` folded — lets a newer resume beat an
     *  older pause that arrives late. */
    lastControlAt?: number;
}
/**
 * Fold one event into one mission's state. PURE: returns a new state, mutates
 * nothing. Idempotent + order-tolerant — every status move is clamped through
 * the monotonic ranks above, so duplicates and out-of-order delivery converge
 * to the same terminal state regardless of arrival order.
 */
declare function applyMissionEvent(prev: MissionState | undefined, event: MissionStreamEvent): MissionState;
/**
 * Merge a loader SEED into the live state for one mission, advancing through
 * the SAME monotonic clamps the event reducer uses. The durable mission row is
 * the authoritative converged state: while the live channel is down the row
 * advances but the frozen live state does not, and nothing re-fires the gap to
 * a reconnecting client. Folding the seed THROUGH the clamps backfills that gap
 * on reconnect while never regressing a more-advanced live value:
 *   - a stale seed for a more-advanced live mission is a no-op,
 *   - an advanced seed after an outage fills the gap (status/steps/spend move
 *     forward to the row's converged state).
 * `live === undefined` (mission unknown to the client) just adopts the seed.
 */
declare function mergeMissionState(live: MissionState | undefined, seed: MissionState): MissionState;
/**
 * Fold a whole event sequence into a Map<missionId, MissionState>. PURE and
 * order-tolerant: feeding the same events in any order (with duplicates)
 * converges to the same map. `seed` lets a reload start from loader-rehydrated
 * state before live events arrive.
 */
declare function reduceMissionEvents(events: MissionStreamEvent[], seed?: Map<string, MissionState>): Map<string, MissionState>;

/**
 * Mission execution engine — drives one mission's plan to completion under a
 * SINGLE serialized owner (a Cloudflare Workflow, a Durable Object alarm, a
 * queue consumer — one per mission). The owner wraps each `runStep` call in its
 * durable-step primitive (e.g. Workflows `step.do(step.id, …)`) so a completed
 * step's result is persisted and replayed instead of re-run after a mid-run
 * restart. This module holds the logic that must be correct independent of any
 * runtime, so it is injectable and unit-testable with the dispatch mocked.
 *
 * Idempotency is layered, belt-and-suspenders:
 *   1. The owner's durable-step cache replays a completed step's result.
 *   2. `runStep` re-reads the mission first; a step already `done` (with a
 *      resultRef) returns the cached pointer WITHOUT re-dispatching — this
 *      closes the at-least-once window where a callback re-runs after the
 *      side effect committed but before the owner durably recorded it.
 *   3. The cursor advances only after a step is `done`, so a fresh run resumes
 *      from `mission.cursor` and never re-touches earlier steps.
 *
 * Seams (the product supplies domain; the engine owns mechanism):
 *   - {@link SandboxDispatch} — how a step actually executes.
 *   - {@link MissionEngineOptions.estimateStepCostUsd} — per-step USD estimate.
 *   - {@link MissionGateOptions.classifyStep} — which steps need approval.
 *   - {@link MissionApprovalsPort} — where gate proposals live and how they
 *     resolve.
 */

/**
 * A side-effecting unit of per-step work. The owner supplies the real
 * implementation (e.g. a detached sandbox-session dispatcher); tests supply a
 * mock. MUST return a SMALL pointer — large output is written to the product's
 * storage and only the resultRef is returned.
 */
type SandboxDispatch = (input: SandboxDispatchInput) => Promise<SandboxDispatchResult>;
interface SandboxDispatchInput {
    mission: MissionRecord;
    step: MissionStep;
    stepIndex: number;
}
interface SandboxDispatchDoneResult {
    kind?: 'done';
    /** Small pointer at the produced artifact/output (vault path, asset id, exec
     *  digest). Stored on the step as `resultRef`; never the full payload. */
    resultRef: string;
    /** Optional one-line status surfaced on the step row. */
    sublabel?: string;
    /** Optional marginal spend for this step. `ledgerDelta` carries platform-
     *  reported truth (real token counts, wall time); `deltaUsd` is set ONLY when
     *  a provider-authored price is known. Omit fields rather than synthesizing
     *  zeros — the engine substitutes its injected per-step estimate for a
     *  missing deltaUsd and records that estimate in the ledger. */
    cost?: {
        deltaUsd?: number;
        ledgerDelta?: Partial<MissionCostLedger>;
    };
}
/** The dispatched step's detached session is still executing on the platform.
 *  The owner sleeps `pollAfterMs` and re-invokes the step; the dispatch is
 *  idempotent on the session ref, so the re-invocation settles the same session
 *  rather than starting a second run. */
interface SandboxDispatchInProgressResult {
    kind: 'in_progress';
    sessionRef: string;
    pollAfterMs: number;
    sublabel?: string;
}
type SandboxDispatchResult = SandboxDispatchDoneResult | SandboxDispatchInProgressResult;
/** Outcome of running a single step. `cached` distinguishes a replay/skip
 *  (step was already done) from a fresh execution so the engine and its tests
 *  can assert the dispatch was NOT re-invoked. */
type StepOutcome = {
    kind: 'done';
    resultRef: string;
    cached: boolean;
} | {
    kind: 'in_progress';
    sessionRef: string;
    pollAfterMs: number;
    sublabel?: string;
} | {
    kind: 'skipped-cursor';
    reason: string;
} | {
    kind: 'failed';
    error: string;
    fatal: boolean;
};
/** Outcome of running the whole plan from the cursor to the end. */
type PlanOutcome = {
    kind: 'completed';
    summary: string;
} | {
    kind: 'in_progress';
    stepId: string;
    sessionRef: string;
    pollAfterMs: number;
    sublabel?: string;
} | {
    kind: 'failed';
    failedStepId: string;
    error: string;
} | {
    kind: 'halted';
    status: MissionStatus;
    reason?: string | null;
} | {
    kind: 'terminal';
    status: MissionStatus;
} | {
    kind: 'not-found';
};
interface MissionPlanRunOptions {
    /** Pre-step veto (kill switch, schedule window). A non-null return pauses the
     *  mission with that reason before the step's side effect starts. */
    beforeStep?: (mission: MissionRecord, step: MissionStep) => Promise<string | null>;
}
/** Thrown to make the owner's durable-step wrapper retry. The single-owner
 *  invariant makes a genuine concurrent change rare (it means another writer
 *  touched the row), so retrying — rather than corrupting state by forcing a
 *  stale write — is the correct response. Distinct from a task failure, which
 *  is recorded on the step. */
declare class MissionConcurrencyError extends Error {
    constructor(message: string);
}
/** Thrown by a {@link SandboxDispatch} for a TRANSIENT failure (platform blip,
 *  exec-time network fault) that should be re-attempted. `runStep` RE-THROWS it
 *  so the owner engages its bounded retry+backoff; the step is left `running`
 *  and the re-dispatch is made idempotent by the cached-done guard. A
 *  deterministic failure must be a plain Error instead — that is recorded as a
 *  fatal `failed` step and is never retried (no money-burning loop on a
 *  deterministic error). */
declare class RetryableStepError extends Error {
    constructor(message: string);
}
/** Resolution states a gate proposal can be in. `approved`/`executed` unblock
 *  the gated step; everything else keeps the mission parked. */
type MissionProposalResolution = 'pending' | 'approved' | 'rejected' | 'executed' | 'ignored';
type MissionGateKind = 'step' | 'budget' | 'volume';
/** Product classification of one step. Returned by
 *  {@link MissionGateOptions.classifyStep}; the matching rules (regexes, intent
 *  vocabularies, path allowlists) are product domain and never live here. */
interface StepGateClassification {
    /** Product approval-type label persisted on the proposal ('generate',
     *  'integration_invoke', …). */
    type: string;
    /** Counted against the per-mission external-action volume cap. */
    externalAction?: boolean;
    estCostUsd?: number | null;
}
/** A gate proposal the engine asks the product to persist. The id is
 *  deterministic per (gate, mission, step) — see the `*ProposalId` helpers —
 *  so a replay re-finds the same proposal instead of duplicating it. The
 *  product composes its own title/description from the structured fields. */
interface MissionGateProposal {
    id: string;
    missionId: string;
    stepId: string;
    gate: MissionGateKind;
    mission: MissionRecord;
    step: MissionStep;
    /** Present for `gate: 'step'` — the classification that triggered the gate. */
    classification?: StepGateClassification;
    /** Present for `gate: 'budget'`. */
    budget?: {
        spentUsd: number;
        budgetUsd: number;
        estimatedCostUsd: number;
    };
    /** Present for `gate: 'volume'`. */
    volume?: {
        externalActionCount: number;
        cap: number;
    };
}
/** Approval persistence seam — the product implements this over its own
 *  proposal table and resolution flow. */
interface MissionApprovalsPort {
    /** Resolution of the proposal with this id, or null when none exists. */
    findResolution(proposalId: string): Promise<MissionProposalResolution | null>;
    /** Persist a new gate proposal (id is deterministic; called at most once per
     *  (gate, mission, step) absent a resolution). */
    createProposal(proposal: MissionGateProposal): Promise<void>;
    /** Count of this mission's `gate: 'step'` proposals whose classification was
     *  `externalAction: true` — the denominator of the volume cap. */
    countExternalActionProposals(missionId: string): Promise<number>;
}
interface MissionGateOptions {
    approvals: MissionApprovalsPort;
    /** Which steps need human approval, and as what. Return null for an ungated
     *  step. The rules are product domain (intent regexes, kind tables). */
    classifyStep: (step: MissionStep) => StepGateClassification | null;
    /** Max external-action approvals per mission before an approved override is
     *  required to request another. Default 5. */
    externalActionCap?: number;
}
interface MissionEngineOptions {
    service: MissionService;
    /** Per-step USD estimate. Load-bearing twice: the budget gate parks on it
     *  BEFORE a step runs, and the engine records it as the step's spend when the
     *  dispatch reports no provider-authored price — using one estimator keeps
     *  spend and gate consistent. */
    estimateStepCostUsd: (step: MissionStep) => number;
    /** Best-effort live notifier. Fired AFTER each guarded write commits, so a
     *  broadcast always reflects persisted state; re-fired on idempotent replays
     *  so a reconnecting client converges. Never awaited; a throwing sink can
     *  never fail a step. Default: drop everything. */
    sink?: MissionEventSink;
    /** Approval gating. Omitted → no classification/volume gates, and a budget
     *  overrun pauses the mission (fail closed) instead of parking it
     *  waiting_approval behind an override proposal. */
    gates?: MissionGateOptions;
    /** Step kinds whose failure does NOT abort the whole mission — enrichment
     *  steps the plan can complete without. Every other kind is fatal-on-failure.
     *  Default `['optional', 'best-effort']`. */
    nonFatalStepKinds?: readonly string[];
}
interface MissionEngine {
    /** Run exactly one plan step. Idempotent: re-invoking for a step already
     *  `done` returns the cached pointer without re-dispatching. A lost guarded
     *  race throws {@link MissionConcurrencyError} so the owner's durable-step
     *  wrapper retries instead of writing a stale value. */
    runStep(missionId: string, stepId: string, dispatch: SandboxDispatch): Promise<StepOutcome>;
    /** Walk the plan from the durable cursor to the end, re-reading the mission
     *  between steps so a pause/stop control that lands while a step is running
     *  is honored before the next side effect. `runStep` is the owner's boundary:
     *  in production `(step) => durableStep.do(step.id, () => engine.runStep(…))`;
     *  in tests `engine.runStep` directly. */
    runPlan(missionId: string, runStep: (step: MissionStep, stepIndex: number) => Promise<StepOutcome>, options?: MissionPlanRunOptions): Promise<PlanOutcome>;
    /** Record spend durable-first, live second: the guarded ledger write commits,
     *  then the sink sees the new total. A guarded failure returns unchanged. */
    recordCost(missionId: string, deltaUsd: number, ledgerDelta?: Partial<MissionCostLedger>): Promise<MissionOutcome<MissionRecord>>;
    /** Pause durable-first, live second (the paused event fires only on a real
     *  edge, not an idempotent re-pause). */
    pauseMission(missionId: string, reason: string): Promise<MissionOutcome<MissionRecord>>;
}
/** Deterministic proposal id for a step-classification gate. */
declare function stepGateProposalId(missionId: string, stepId: string): string;
/** Deterministic proposal id for a budget-overrun override. */
declare function budgetGateProposalId(missionId: string, stepId: string): string;
/** Deterministic proposal id for an external-action volume-cap override. */
declare function volumeGateProposalId(missionId: string, stepId: string): string;
declare function createMissionEngine(options: MissionEngineOptions): MissionEngine;

/**
 * Parsing for the agent-authored `:::mission` block — the bridge from a chat
 * prompt contract to the engine's MissionStep[] shape. The block format:
 *
 *   :::mission
 *   title: <mission title>
 *   <id>: <kind> | <intent>
 *   :::
 *
 * The allowed kind vocabulary is a PARAMETER — products pass their own list to
 * match their prompt directive; {@link DEFAULT_MISSION_STEP_KINDS} is the
 * default. Kinds label intent for gating and UX; they never select a different
 * execution path.
 */

/** Default step-kind vocabulary. `best-effort` matches the engine's default
 *  non-fatal kind (a failure does not abort the mission); the rest are
 *  fatal-on-failure agent sub-tasks. */
declare const DEFAULT_MISSION_STEP_KINDS: readonly string[];
interface ParsedMissionStep {
    id: string;
    kind: string;
    intent: string;
}
interface ParsedMission {
    title: string;
    steps: ParsedMissionStep[];
}
interface ParseMissionBlocksOptions {
    /** Allowed step kinds (lowercase). Default {@link DEFAULT_MISSION_STEP_KINDS}. */
    kinds?: readonly string[];
}
/**
 * Parse every well-formed `:::mission` block. A block without a title or
 * without at least one valid step yields nothing (it is malformed — never
 * guess a plan from loose prose). Unknown kinds and malformed step lines are
 * dropped; an empty result lets the caller skip the block rather than start an
 * empty mission.
 */
declare function parseMissionBlocks(fullContent: string, options?: ParseMissionBlocksOptions): ParsedMission[];
/**
 * Materialize parsed steps into the engine's MissionStep[] shape. Rejects a
 * duplicate step id (fail loud — the owner keys its durable step cache by
 * step id and `createMission` rejects duplicates anyway; catching it here
 * gives a clearer diagnostic). Every step starts `pending` with zero attempts.
 */
declare function buildAgentMissionPlan(steps: ParsedMissionStep[]): MissionStep[];

export { type CompleteMissionInput, type CreateMissionInput, DEFAULT_MISSION_STEP_KINDS, type InMemoryMissionStore, MISSION_CONTROL_CHANNEL_ID, type MissionApprovalsPort, type MissionAuditEvent, MissionConcurrencyError, type MissionCostLedger, type MissionEngine, type MissionEngineOptions, type MissionEventSink, type MissionGateKind, type MissionGateOptions, type MissionGateProposal, type MissionOutcome, type MissionPlanRunOptions, type MissionProposalResolution, type MissionRecord, type MissionService, type MissionServiceOptions, type MissionState, type MissionStatus, type MissionStep, type MissionStepState, type MissionStepStatus, type MissionStorePort, type MissionStreamEvent, type MissionStreamStatus, type MissionStreamStep, type MissionStreamStepStatus, type MissionUpdateGuard, type MissionUpdatePatch, type ParseMissionBlocksOptions, type ParsedMission, type ParsedMissionStep, type PlanOutcome, RetryableStepError, type SandboxDispatch, type SandboxDispatchDoneResult, type SandboxDispatchInProgressResult, type SandboxDispatchInput, type SandboxDispatchResult, type SetStepStatusPatch, StepAgentActivity, type StepGateClassification, type StepOutcome, applyMissionEvent, asMissionStreamEvent, budgetGateProposalId, buildAgentMissionPlan, createInMemoryMissionStore, createMissionEngine, createMissionService, isMissionStopRequested, isMissionTerminal, mergeMissionState, noopEventSink, parseMissionBlocks, parseSessionStreamEnvelope, reduceMissionEvents, stepGateProposalId, volumeGateProposalId };
