import { type Result } from "@fjall/generator"; import type { DeployCallbacks } from "../types/callbacks.js"; export interface StepDescriptor { readonly stepId: string; readonly stepName: string; readonly stepIndex?: number; readonly totalSteps?: number; } export type StepOutcome = { kind: "completed"; data: T; } | { kind: "skipped"; data: T; } | { kind: "error"; error: Error; }; /** * Wraps a single-step async operation in the onStepStart → onStepComplete * lifecycle envelope. The wrapper is the only path that emits these events, * which structurally prevents the recurrence class where a new orchestrator * branch forgets the matching onStepComplete (B-1 in 2026-04-30 deployment-flow review). * * If `fn` throws, the throw is caught, an "error" complete event is emitted, * onError is invoked, and a failure Result is returned — so an exception * cannot leave the step rail visually frozen. * * When `abortSignal` has fired (caller Ctrl-C / worker SIGTERM), a failing step * is reported as **"cancelled"** rather than "error", and onError is suppressed * — an abort is a deliberate stop, not a deploy failure. The failure Result is * still returned so the orchestrator short-circuits; the top-level engine * surfaces the cancellation via `DeployResult.cancelled`. */ export declare function withStepLifecycle(callbacks: DeployCallbacks, step: StepDescriptor, fn: () => Promise>, abortSignal?: AbortSignal): Promise>;