/**
 * Workflow Controller — automation driver: create / run / pause / resume + concurrency (spec §B4/B5).
 *
 * Owns workflow lifecycle on top of the WorkflowStore (persistence) and WorkflowRuntime (execution).
 * Concurrency (spec §B5): when a workflow is triggered while a previous run is still in-flight, the
 * record's `concurrency` policy decides:
 *   - "skip"     -> drop the new trigger (returns status "skipped")
 *   - "queue"    -> run after the current one finishes. Each trigger gets a fresh runtime/cache;
 *                   only pause/resume of the SAME run reuses runtime state.
 *   - "parallel" -> start a fresh independent runtime concurrently (own cache)
 *
 * The caller supplies a `runtimeFactory` so host capabilities (D13), the node registry, the
 * budget/permission gate (D15), and the clock are injected per workflow — the controller never
 * imports those subsystems (engine stays a pure executor; plan D12).
 *
 * fail-loud: unknown workflow ids throw; executor/gate errors propagate out of run().
 */
import type { RunCheckpoint } from "./run-checkpoint-store.js";
import { type RunResult, type WorkflowRuntime } from "./workflow-runtime.js";
import type { NodeRegistry } from "./node-registry.js";
import type { ExecutorHost } from "./node-schema.js";
import { type WorkflowTriggerKind } from "./budget-permission-gate.js";
import type { WorkflowDef } from "./node-schema.js";
import { type PatchEnvelope, type WorkflowPatch } from "./workflow-patch.js";
import { type RenderOptions } from "./workflow-render.js";
import { WorkflowStore, type ConcurrencyPolicy, type WorkflowRecord } from "./workflow-store.js";
import { type WorkflowRunHistoryStore } from "./run-history-store.js";
export interface TriggerEvent {
    type: WorkflowTriggerKind;
    payload?: Record<string, unknown>;
}
/**
 * Per-run context handed to the RuntimeFactory: the trigger KIND (so the factory can wire the D15
 * permission gate — unattended kinds are restricted) plus its payload (exposed to expressions).
 */
export interface RunContext {
    /** The workflow record id (so the runtime factory can tag per-node status notifications). */
    workflowId: string;
    /** Stable id for this run, used by history, checkpointing, pause/resume, and cancellation. */
    runId: string;
    type: WorkflowTriggerKind;
    payload?: Record<string, unknown>;
    /** Cancellation propagated to the runtime and host-backed node executors. */
    signal?: AbortSignal;
    /** The record's unattended capability grant at run start (D30; feeds the permission gate). */
    permissionScope?: WorkflowRecord["permissionScope"];
    /**
     * R5 媒体工作室(D44):跨 run 内容寻址缓存 —— 本 run 从工作流级共享 checkpoint seed,
     * 完成后保留(不清),下次"改参数只重跑下游"(ComfyUI 语义:未变节点命中缓存被跳过)。
     * 默认关:自动化的副作用节点(发消息/HTTP POST)绝不能因"没变"被静默跳过;
     * 工作室画布的"运行"显式带上(纯数据流面,跳过未变工序正是期望)。
     */
    reuseCache?: boolean;
}
/** Per-node lifecycle status surfaced for live canvas coloring (not durable; fire-and-forget). */
export type NodeRunStatus = "running" | "completed" | "failed";
/** Builds a runtime for a workflow run. `ctx` carries the run's trigger kind + payload (spec §B3). */
export type RuntimeFactory = (def: WorkflowDef, ctx: RunContext) => WorkflowRuntime;
export interface RunOutcome {
    workflowId: string;
    status: "completed" | "failed" | "paused" | "skipped" | "canceled";
    /** Absent when status === "skipped" (a busy run under the "skip" policy). */
    result?: RunResult;
    /** Durable run-history id (present when a run-history store is wired). */
    runId?: string;
}
export interface CreateInput {
    id: string;
    name: string;
    def: WorkflowDef;
    concurrency?: ConcurrencyPolicy;
    active?: boolean;
    /** Owning user (D38); the handler stamps resolveActiveOwnerUserId(). */
    owner?: string;
}
/** Result of a `patch()` call (spec §C `WorkflowToolResult`). */
export type PatchOutcome = {
    ok: true;
    rev: number;
    applied: WorkflowPatch[];
} | {
    ok: false;
    conflict: {
        latestRev: number;
    };
};
export declare class WorkflowController {
    private readonly store;
    private readonly runtimeFactory;
    /** Optional durable run-history recorder. Wired here (not the handler) so every
     *  trigger path — manual RPC, cron scheduler, IM, webhook — is captured alike. */
    private readonly runHistory?;
    private readonly slots;
    private readonly activeRuns;
    private readonly activeRunIdsByWorkflow;
    private readonly suppressedHistoryRunIds;
    constructor(store: WorkflowStore, runtimeFactory: RuntimeFactory, 
    /** Optional durable run-history recorder. Wired here (not the handler) so every
     *  trigger path — manual RPC, cron scheduler, IM, webhook — is captured alike. */
    runHistory?: WorkflowRunHistoryStore | undefined);
    create(input: CreateInput): Promise<WorkflowRecord>;
    update(id: string, patch: Partial<Pick<WorkflowRecord, "name" | "def" | "concurrency" | "active" | "permissionScope">>): Promise<WorkflowRecord>;
    setActive(id: string, active: boolean): Promise<WorkflowRecord>;
    /**
     * Publish (D31): snapshot the current draft (`def`) as the version triggers execute.
     * Editing the draft afterwards never touches the running version until the next publish.
     */
    publish(id: string): Promise<WorkflowRecord>;
    /** Archive (D31): keep the data, kill the lifecycle (deactivates; activation/publish refuse). */
    archive(id: string, archived: boolean): Promise<WorkflowRecord>;
    /**
     * Revert a workflow to a stored revision snapshot (undo 基座). Git-revert semantics:
     * the snapshot's def/name/trigger are re-applied as a NEW revision (rev bumps), so
     * history stays forward-only and optimistic-concurrency baseRev checks keep working.
     * fail-loud: unknown id or pruned/absent revision throws.
     */
    revertTo(id: string, rev: number): Promise<WorkflowRecord>;
    /**
     * Import an n8n workflow JSON (read-format only, plan M5 §2.1) into the single store. Converts
     * via the deterministic translator then routes through `create`, so the graph passes the same
     * `validateWorkflowDef` gate every write path uses — fail-loud on unsupported nodes or bad graph.
     */
    importN8n(id: string, json: string | unknown, opts?: {
        concurrency?: ConcurrencyPolicy;
        owner?: string;
    }): Promise<{
        record: WorkflowRecord;
        report: import("./n8n-import.js").N8nConversionReport;
    }>;
    /** Load a single record or throw (fail-loud lookup; used by the scheduler to re-read triggers). */
    get(id: string): Promise<WorkflowRecord>;
    /**
     * Render a workflow as compact agent-context text (spec §B / §A `get`). Fail-loud on unknown id.
     * This is the engine half of the agent `workflow.get`/describe action: the agent reads this and
     * emits a WorkflowPatch against the shown `rev`.
     */
    describe(id: string, opts?: RenderOptions): Promise<string>;
    /**
     * Apply a WorkflowPatch — the single mutation channel for agent edits and canvas hand-edits
     * (spec §C). Loads the latest record, applies the patch transactionally through the engine
     * (scope enforcement + validateDag), bumps `rev`, and persists. Optimistic concurrency (LWW):
     *   - baseRev omitted or == current rev → apply against the latest.
     *   - baseRev < current rev (someone edited in between) → replay onto the latest; if every op
     *     still references valid nodes/edges it applies (last-write-wins), otherwise a conflict is
     *     returned so the caller can redo against the latest rendering.
     * A rejected patch (illegal op / scope violation / invalid graph) throws PatchError unchanged.
     */
    patch(id: string, env: PatchEnvelope): Promise<PatchOutcome>;
    /** Trigger a run, honoring the workflow's concurrency policy (spec §B5). */
    run(id: string, trigger?: TriggerEvent, opts?: {
        recordHistory?: boolean;
        reuseCache?: boolean;
    }): Promise<RunOutcome>;
    /**
     * Wrap a run with durable history recording (when wired). Lives at this choke point —
     * not in the RPC handler — so cron/IM/webhook runs are recorded identically to manual
     * ones. History writes are best-effort: a recording failure never blocks the run.
     */
    private recordRun;
    /** Cooperatively pause the in-flight run; it suspends before the next node (cache retained). */
    pause(id: string, opts?: {
        runId?: string;
    }): void;
    /** Resume a paused workflow: re-run the same runtime so cached nodes hit and only the
     * unfinished remainder executes. When the run paused on an exhausted budget, pass `extraBudget`
     * to raise the gate's ceiling first (D15 "抬预算后 resume"); otherwise the first not-yet-run
     * node would immediately re-trip the same budget and pause again. */
    resume(id: string, opts?: {
        runId?: string;
        extraBudget?: {
            executions?: number;
            durationMs?: number;
        };
    }): Promise<RunOutcome>;
    cancelRun(id: string, opts?: {
        runId?: string;
        reason?: string;
    }): Promise<RunOutcome>;
    delete(id: string): Promise<void>;
    /** Active workflows whose triggers the gateway should re-register after restart (spec §B4). */
    listActive(): Promise<WorkflowRecord[]>;
    private slotFor;
    private registerActiveRun;
    private unregisterActiveRun;
    private requireActiveRun;
    private finishRunHistory;
    /**
     * Track a fresh or queued run on the slot. `chained` runs wait for the slot's tail (the prior
     * run) before starting → strict serialization for the "queue" policy. `pending` is incremented
     * synchronously so concurrent triggers observe the slot as busy across the run→queue handoff.
     */
    private track;
    private startParallel;
    private startTrackedRuntime;
}
/**
 * The production RuntimeFactory: builds a WorkflowRuntime wired with the D15 BudgetPermissionGate
 * derived from the run's trigger kind. This is the consumer that turns the gate from a bare
 * interface into an enforced guarantee — every run the controller starts through this factory has
 * its per-run budget and (for unattended triggers) its permission allowlist checked before each
 * node. Hosts supply the registry/host capabilities and the budget ceilings; the gate wiring is
 * fixed so no run can accidentally execute ungated.
 */
export declare function defaultRuntimeFactory(opts: {
    registry?: NodeRegistry;
    host?: ExecutorHost;
    /** Per-run budget ceilings (D15 "每轮过 budget"). maxNodeExecutions is required and must be > 0. */
    budget: {
        maxNodeExecutions: number;
        maxDurationMs?: number;
    };
    /** Sensitive kinds an unattended run may execute (D15 permission gate). */
    allowUnattendedKinds?: readonly string[];
    /** Optional durable cache for crash/restart replay, keyed by workflow id + run id. */
    checkpoint?: (workflowId: string, runId: string) => RunCheckpoint | undefined;
    now?: () => Date;
    /** Per-node lifecycle for live canvas coloring; workflowId comes from the run ctx. */
    emitNodeStatus?: (workflowId: string, nodeId: string, status: NodeRunStatus) => void;
}): RuntimeFactory;
