@orkestrel/workflow 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3179 @@
1
+ import { AbortInterface } from '@orkestrel/abort';
2
+ import { AgentInterface } from '@orkestrel/agent';
3
+ import { ArrayShape } from '@orkestrel/contract';
4
+ import { BudgetInterface } from '@orkestrel/budget';
5
+ import { ContractInterface } from '@orkestrel/contract';
6
+ import { DriverInterface } from '@orkestrel/database';
7
+ import { EmitterErrorHandler } from '@orkestrel/emitter';
8
+ import { EmitterHooks } from '@orkestrel/emitter';
9
+ import { EmitterInterface } from '@orkestrel/emitter';
10
+ import { LiteralShape } from '@orkestrel/contract';
11
+ import { NumberShape } from '@orkestrel/contract';
12
+ import { ObjectShape } from '@orkestrel/contract';
13
+ import { OptionalShape } from '@orkestrel/contract';
14
+ import { Result } from '@orkestrel/contract';
15
+ import { StringShape } from '@orkestrel/contract';
16
+ import { TableInterface } from '@orkestrel/database';
17
+ import { TokenUsage } from '@orkestrel/budget';
18
+ import { ToolInterface } from '@orkestrel/agent';
19
+ import { ToolManagerInterface } from '@orkestrel/agent';
20
+ import { UnionShape } from '@orkestrel/contract';
21
+
22
+ /**
23
+ * The ancestry identifier of an agent in a run chain — `agent:<name>`.
24
+ *
25
+ * @remarks
26
+ * The agent counterpart of {@link workflowTag}: the runner adds one when it dispatches an
27
+ * `agent` task, and rejects the task (a typed `DEPTH` `task.fail`) when the same tag is
28
+ * already in the ancestry (a re-entry cycle). The `agent:` namespace keeps it distinct
29
+ * from a same-string workflow id.
30
+ *
31
+ * @param name - The agent's registry name (the `agent`-form's `name`)
32
+ * @returns The namespaced ancestry tag (`agent:<name>`)
33
+ */
34
+ export declare function agentTag(name: string): string;
35
+
36
+ /**
37
+ * Assert that a {@link WorkflowSnapshot} carries a `boolean` `bail` — at the workflow tier AND
38
+ * on every phase — and that its every node's status (and its `override`, when present) is drawn
39
+ * from the lifecycle vocabulary, throwing a `RESTORE` {@link WorkflowError} otherwise.
40
+ *
41
+ * @remarks
42
+ * The boundary-narrowing guard (AGENTS §14) for {@link restoreWorkflow}: a snapshot is
43
+ * untrusted JSON, so a status (or an override) outside
44
+ * {@link import('./constants.js').WORKFLOW_STATUSES} /
45
+ * {@link import('./constants.js').PHASE_STATUSES} / {@link import('./constants.js').TASK_STATUSES},
46
+ * or a non-boolean `bail` (the workflow's OR any phase's — both are REQUIRED persisted policy),
47
+ * is rejected loudly (naming the offending node) rather than silently producing a broken tree.
48
+ * The `override` is optional, so it is only checked WHEN present. Structural shape beyond these
49
+ * fields is the contract's concern; this guards exactly the fields the live state machine reads back.
50
+ *
51
+ * @param snapshot - The snapshot to validate
52
+ */
53
+ export declare function assertSnapshot(snapshot: WorkflowSnapshot): void;
54
+
55
+ /**
56
+ * Build a {@link PhaseContext} — a phase's own identity plus a back-reference to its
57
+ * workflow — from the parent {@link WorkflowContext} and the phase node's identity.
58
+ *
59
+ * @param workflow - The parent workflow context (the lineage pointer UP the tree)
60
+ * @param node - The phase's identity (`id` / `name` / optional `description`)
61
+ * @returns The {@link PhaseContext}
62
+ */
63
+ export declare function buildPhaseContext(workflow: WorkflowContext, node: WorkflowContext): PhaseContext;
64
+
65
+ /**
66
+ * Build a {@link TaskContext} — a task's own identity plus a back-reference to its phase
67
+ * (and, transitively, its workflow) — from the parent {@link PhaseContext} and the task
68
+ * node's identity.
69
+ *
70
+ * @param phase - The parent phase context (carrying the full lineage UP the tree)
71
+ * @param node - The task's identity (`id` / `name` / optional `description`)
72
+ * @returns The {@link TaskContext}
73
+ */
74
+ export declare function buildTaskContext(phase: PhaseContext, node: WorkflowContext): TaskContext;
75
+
76
+ /**
77
+ * Build a {@link WorkflowContext} — the identity every level inherits — from a node's
78
+ * `id` / `name` / optional `description`.
79
+ *
80
+ * @remarks
81
+ * The root of the context chain a live {@link import('./Workflow.js').Workflow} exposes;
82
+ * {@link buildPhaseContext} / {@link buildTaskContext} extend it down the tree. Accepts a
83
+ * structural node (a definition or a snapshot node — both carry the three identity fields).
84
+ *
85
+ * @param node - The node's identity (`id` / `name` / optional `description`)
86
+ * @returns The {@link WorkflowContext}
87
+ */
88
+ export declare function buildWorkflowContext(node: WorkflowContext): WorkflowContext;
89
+
90
+ /**
91
+ * Test whether the live W-b task state machine may move directly from one
92
+ * {@link TaskStatus} to another — the legal-transition guard.
93
+ *
94
+ * @remarks
95
+ * Reads the {@link import('./constants.js').TASK_TRANSITIONS} graph: `true` only when
96
+ * `to` is listed under `from`. A settled (terminal) `from` has no legal targets, so any
97
+ * transition off it is `false`. The W-b `Task` consults this before every transition and
98
+ * throws a `TRANSITION` {@link import('./errors.js').WorkflowError} when it returns `false`.
99
+ *
100
+ * @param from - The task's current status
101
+ * @param to - The status the transition would move it to
102
+ * @returns `true` when the move is legal
103
+ */
104
+ export declare function canTransitionTask(from: TaskStatus, to: TaskStatus): boolean;
105
+
106
+ /**
107
+ * Flatten a nested list of per-phase {@link TaskResult} lists into one positional list
108
+ * — the workflow tier of the result tree, built from each phase's `results()`.
109
+ *
110
+ * @remarks
111
+ * Pure and order-preserving: phases in order, each phase's task results in order. The
112
+ * W-b `Workflow.results()` calls this over its phases' `results()`; a phase's own
113
+ * `results()` is the per-phase list this consumes.
114
+ *
115
+ * @param phases - The per-phase result lists, in phase order
116
+ * @returns One flattened {@link TaskResult} list, in positional order
117
+ */
118
+ export declare function collectResults(phases: readonly (readonly TaskResult[])[]): readonly TaskResult[];
119
+
120
+ /**
121
+ * Complete a {@link WorkflowDraft} into a strict {@link WorkflowDefinition} — synthesize
122
+ * any MISSING `id` deterministically + positionally, and default any MISSING `name` to
123
+ * its (now-resolved) `id`.
124
+ *
125
+ * @remarks
126
+ * The positional id scheme is stable and human-legible: the workflow is `wf`, phase `i`
127
+ * is `phase-<i>`, and task `j` of that phase is `<phaseId>-task-<j>` (so a provided phase
128
+ * id flows into its tasks' synthesized ids). A PROVIDED `id` / `name` at any level is kept
129
+ * VERBATIM — synthesis touches only the omitted ones. A missing `name` defaults to the
130
+ * resolved `id` (never the other way round), so the result always has both. `run`,
131
+ * `description`, the per-phase `concurrency` / `bail`, the per-task `retries` / `timeout`, and
132
+ * the workflow `bail` carry over unchanged. The result is a complete
133
+ * {@link WorkflowDefinition}; the caller still validates it against the STRICT contract.
134
+ *
135
+ * @param draft - The draft workflow (id/name optional at all three levels)
136
+ * @returns A complete {@link WorkflowDefinition} with every id/name filled
137
+ */
138
+ export declare function completeDraft(draft: WorkflowDraft): WorkflowDefinition;
139
+
140
+ /**
141
+ * Complete one {@link PhaseDraft} into a strict {@link PhaseDefinition} — the per-phase
142
+ * step of {@link completeDraft} (phase `index` → `phase-<index>` when its id is omitted).
143
+ *
144
+ * @param phase - The draft phase
145
+ * @param index - The phase's positional index in the workflow
146
+ * @returns A complete {@link PhaseDefinition}
147
+ */
148
+ export declare function completePhaseDraft(phase: PhaseDraft, index: number): PhaseDefinition;
149
+
150
+ /**
151
+ * Complete one {@link TaskDraft} into a strict {@link TaskDefinition} — the per-task leaf
152
+ * step of {@link completeDraft} (task `index` of phase `<phaseId>` → `<phaseId>-task-<index>`
153
+ * when its id is omitted).
154
+ *
155
+ * @param task - The draft task
156
+ * @param phaseId - The (resolved) parent phase id, so the synthesized task id nests under it
157
+ * @param index - The task's positional index within its phase
158
+ * @returns A complete {@link TaskDefinition}
159
+ */
160
+ export declare function completeTaskDraft(task: TaskDraft, phaseId: string, index: number): TaskDefinition;
161
+
162
+ /**
163
+ * The per-unit handle a runner handler receives — wraps the unit's identity,
164
+ * input, cancellation, and the run controls (`wait` / `spawn` / `abort`).
165
+ *
166
+ * @remarks
167
+ * - **Built by the Runner per unit.** The runner constructs one `Controller` per
168
+ * unit it dispatches, handing it the unit's `id`, `input`, the unit's `Abort`
169
+ * handle, the queue attempt's `signal`, and a `spawn` callback that launches a
170
+ * sibling through the same queue.
171
+ * - **Signal.** `signal` is the queue attempt's signal, which ANY-combines the
172
+ * unit's own abort, the runner-level abort (the runner aborts every unit), and
173
+ * the per-attempt timeout — so it fires on any of the three. `aborted` and
174
+ * `abort(reason)` delegate to the unit's `Abort` (the cancellation source of
175
+ * truth); since the attempt signal ANY-includes that abort, `abort()` fires
176
+ * `signal` too.
177
+ * - **`wait` promise-parks (never a timer).** It resolves the instant the unit's
178
+ * `signal` fires (immediately if already aborted) via a one-shot listener — no
179
+ * `setTimeout`, no polling, no busy-yield — so a parked unit costs no CPU.
180
+ * - **`spawn` is fire-and-track.** It delegates to the runner's launch-a-sibling
181
+ * callback, which routes the sibling through the queue; the runner's `execute`
182
+ * awaits the spawn closure, so the sibling runs whether or not its promise is
183
+ * awaited. (Inline-awaiting a spawn from a slot-holding handler on a bounded
184
+ * runner can deadlock — fan out instead; see {@link ControllerInterface.spawn}.)
185
+ * - **Event-free by design.** The per-unit handle carries no Emitter; observe the
186
+ * {@link RunnerInterface.emitter} instead (`unit` / `spawn` / `settle` / `fail` carry the id).
187
+ */
188
+ export declare class Controller<TInput, TResult> implements ControllerInterface<TInput, TResult> {
189
+ #private;
190
+ readonly id: string;
191
+ readonly input: TInput;
192
+ readonly signal: AbortSignal;
193
+ constructor(id: string, input: TInput, abort: AbortInterface, signal: AbortSignal, spawn: (input: TInput) => Promise<TResult>);
194
+ get aborted(): boolean;
195
+ wait(): Promise<void>;
196
+ spawn(input: TInput): Promise<TResult>;
197
+ abort(reason?: unknown): void;
198
+ }
199
+
200
+ /**
201
+ * The per-unit handle a {@link RunnerHandler} receives — the running unit's
202
+ * identity, input, cancellation, and the controls to cooperate with the run.
203
+ *
204
+ * @remarks
205
+ * One `Controller` is built per unit the {@link RunnerInterface} runs (a declared
206
+ * input or a `spawn`ed sibling). It exposes:
207
+ * - `id` — the unit's identifier (a random UUID).
208
+ * - `input` — the unit's work payload.
209
+ * - `signal` — the unit's cancellation: fires on the unit's own `abort()`, a
210
+ * runner-level `abort` (the runner aborts every unit), or this attempt's timeout
211
+ * expiring (it reflects the underlying queue attempt's signal, which ANY-combines
212
+ * all three).
213
+ * - `aborted` — whether the unit's cancellation has fired.
214
+ *
215
+ * @typeParam TInput - The unit's work input
216
+ * @typeParam TResult - The value a unit resolves
217
+ */
218
+ export declare interface ControllerInterface<TInput, TResult> {
219
+ readonly id: string;
220
+ readonly input: TInput;
221
+ /** Fires on the unit's own `abort()`, a runner-level abort, or this attempt's timeout. */
222
+ readonly signal: AbortSignal;
223
+ readonly aborted: boolean;
224
+ /**
225
+ * Park until this unit's `signal` aborts — **promise-parked**, never a timer.
226
+ *
227
+ * @remarks
228
+ * Resolves the moment the unit's `signal` fires (unit abort, runner abort, or
229
+ * timeout) and resolves immediately if it has already fired. It registers a
230
+ * one-shot `'abort'` listener and never polls — no `setTimeout`, no `delay`, no
231
+ * busy-yield — so a parked unit consumes no CPU until it is actually cancelled.
232
+ *
233
+ * @returns A promise that resolves once the unit's `signal` aborts
234
+ */
235
+ wait(): Promise<void>;
236
+ /**
237
+ * Add a sibling unit to the run; returns its result promise.
238
+ *
239
+ * @remarks
240
+ * **Fire-and-track.** The spawned unit is routed through the same backing queue
241
+ * as every declared unit, so it actually runs (in FIFO wake order) and its result
242
+ * joins the run's ordered output after the declared units, in spawn order. The
243
+ * runner's `execute` awaits the full transitive spawn closure (it tracks an
244
+ * outstanding-unit count, not a one-time snapshot), so a caller does NOT need to
245
+ * await the returned promise to make the sibling run.
246
+ *
247
+ * **Deadlock caveat.** On a bounded-`concurrency` runner, do NOT `await` a
248
+ * `spawn`ed promise *inline* from within a handler — the handler holds a queue
249
+ * slot while it awaits, and if every slot is held by a handler awaiting its own
250
+ * spawn, no slot is free to run the spawns and the run deadlocks. The intended
251
+ * pattern is fan-out: `spawn` siblings and return, letting the runner drain them.
252
+ *
253
+ * @param input - The sibling unit's work payload
254
+ * @returns The sibling's result promise (it runs regardless of whether it's awaited)
255
+ */
256
+ spawn(input: TInput): Promise<TResult>;
257
+ /**
258
+ * Cancel this unit — fires its `signal` with the optional reason.
259
+ *
260
+ * @param reason - An optional cancellation reason carried on the signal
261
+ */
262
+ abort(reason?: unknown): void;
263
+ }
264
+
265
+ /**
266
+ * Create a {@link DatabaseWorkflowStore} over any {@link DriverInterface} — the durable,
267
+ * driver-pluggable backing for the W-d persistence seam, the opt-in twin of
268
+ * {@link createMemoryWorkflowStore}.
269
+ *
270
+ * @remarks
271
+ * Builds a one-table database (`snapshots`, keyed by `id`) over the supplied driver, the snapshot
272
+ * held as ONE OPAQUE JSON COLUMN — the column map is `{ id; snapshot }` where `snapshot` is a
273
+ * `rawShape` (a JSON blob), exactly as {@link createDatabaseQueueStore} stores its `input`. The
274
+ * snapshot is already a COMPLETE, self-contained, pure-JSON payload, so storing it whole is lossless
275
+ * AND keeps the row type FLAT — a structured multi-column snapshot table would force the contract to
276
+ * `Infer` the deeply-nested snapshot shape (workflow → phases → tasks → results) and trip TS2589;
277
+ * the opaque column sidesteps it (the column reads back as `unknown`, narrowed on `get` by
278
+ * {@link import('./helpers.js').isWorkflowSnapshot}). The `driver` DEFAULTS to
279
+ * {@link createMemoryDriver}, so the store ALSO works in memory out of the box; pass a server
280
+ * `createJSONDriver` / `createSQLiteDriver` (or a browser IndexedDB driver) for a persistent one —
281
+ * the durability is the driver's job, the store engine is shared. It swaps in behind
282
+ * {@link WorkflowStoreInterface} WITHOUT touching the runner or the entity tree.
283
+ *
284
+ * @param driver - The storage backend the snapshots persist to (defaults to {@link createMemoryDriver})
285
+ * @returns A {@link WorkflowStoreInterface} over the driver
286
+ *
287
+ * @example
288
+ * ```ts
289
+ * import { createDatabaseWorkflowStore, createMemoryDriver, createWorkflow, restoreWorkflow } from '@src/core'
290
+ *
291
+ * const store = createDatabaseWorkflowStore(createMemoryDriver()) // a durable driver swaps in here
292
+ * const workflow = createWorkflow(definition)
293
+ * await store.set(workflow.snapshot()) // persist the run state (one JSON column)
294
+ * const snapshot = await store.get(definition.id)
295
+ * const restored = snapshot && restoreWorkflow(snapshot) // an identical live tree
296
+ * ```
297
+ */
298
+ export declare function createDatabaseWorkflowStore(driver?: DriverInterface): WorkflowStoreInterface;
299
+
300
+ /**
301
+ * Create a {@link DeferredInterface} — a promise whose settlement is driven
302
+ * externally, so a caller can resolve/reject it from outside the executor.
303
+ *
304
+ * @typeParam T - The value the deferred promise resolves
305
+ * @returns A deferred `promise` plus its `resolve` / `reject`
306
+ */
307
+ export declare function createDeferred<T>(): DeferredInterface<T>;
308
+
309
+ /**
310
+ * Create the in-memory durable {@link WorkflowStoreInterface} — a process-lifetime
311
+ * {@link MemoryWorkflowStore} persisting {@link WorkflowSnapshot}s by workflow id, the DEFAULT
312
+ * backend behind the W-d persistence seam.
313
+ *
314
+ * @remarks
315
+ * The snapshot analogue of the server package's `createMemorySessionStore`
316
+ * (and the {@link createMemoryQueueStore} family), but LEANER — there is no idle-TTL, so no
317
+ * options bag (AGENTS §21 minimal): a persisted run-state lives until an explicit `delete`. This is
318
+ * the zero-plumbing DEFAULT (a plain `Map`); its driver-pluggable twin is
319
+ * {@link createDatabaseWorkflowStore} (the snapshot as one opaque JSON column over a `databases`
320
+ * table) — for a DURABLE store (run-state surviving a restart) pass it a JSON / SQLite / IndexedDB
321
+ * driver, and it swaps in WITHOUT touching the runner or the entity tree. Restore stays a caller
322
+ * concern: read a snapshot back and rebuild the live tree with {@link restoreWorkflow}.
323
+ *
324
+ * @returns A memory-backed {@link WorkflowStoreInterface}
325
+ *
326
+ * @example
327
+ * ```ts
328
+ * import { createMemoryWorkflowStore, createWorkflow, restoreWorkflow } from '@src/core'
329
+ *
330
+ * const store = createMemoryWorkflowStore()
331
+ * const workflow = createWorkflow(definition)
332
+ * await store.set(workflow.snapshot()) // persist the run state
333
+ * const snapshot = await store.get(definition.id)
334
+ * const restored = snapshot && restoreWorkflow(snapshot) // an identical live tree
335
+ * ```
336
+ */
337
+ export declare function createMemoryWorkflowStore(): WorkflowStoreInterface;
338
+
339
+ /**
340
+ * Create a thin generic orchestrator that drives declared units — and any they
341
+ * `spawn` — through a bounded-concurrency queue, collecting their results in order.
342
+ *
343
+ * @remarks
344
+ * The Runner composes the workers `Queue` for backpressure, FIFO ordering, bounded
345
+ * concurrency, retries, and the per-attempt timeout — it adds only orchestration, not
346
+ * a second concurrency engine. `execute(inputs)` runs the unit set ONCE (a second call
347
+ * throws) and resolves the units' results in order: the declared inputs first, then
348
+ * any `spawn`ed siblings in spawn order. Each unit's handler gets a `Controller` — its
349
+ * `id` / `input`, a `signal` that fires on the unit's `abort`, a runner-level `abort`,
350
+ * or the attempt's timeout, a promise-parked `wait()`, and `spawn(input)` to fan out
351
+ * sibling units. The run is **fail-fast**: the first unit failure (after retries)
352
+ * aborts every other unit and rejects `execute` with that error. **Observable (§13):** a
353
+ * typed `emitter` surfaces `start` / `unit` / `spawn` / `settle` / `fail` / `finish` / `abort`.
354
+ *
355
+ * Because `spawn` is fire-and-track (the runner awaits the whole spawn closure via an
356
+ * outstanding-unit count, not a one-time snapshot), a handler need NOT await its spawns
357
+ * for them to run — and on a bounded runner it should NOT `await` a spawn inline (a
358
+ * slot-holding handler awaiting its own spawn can deadlock); fan out and return instead.
359
+ *
360
+ * @typeParam TInput - The work input each unit carries
361
+ * @typeParam TResult - The value a unit's handler resolves
362
+ * @param options - The `handler` plus optional `concurrency` (default `1`), `retries`
363
+ * (default `0`), and a default per-attempt `timeout` in milliseconds
364
+ * @returns A working {@link RunnerInterface}
365
+ *
366
+ * @example
367
+ * ```ts
368
+ * import { createRunner } from '@src/core'
369
+ *
370
+ * // A handler that fans out one sibling per declared unit, then returns its own value.
371
+ * const runner = createRunner<number, number>({
372
+ * concurrency: 4,
373
+ * handler: (controller) => {
374
+ * if (controller.input < 10) controller.spawn(controller.input + 100) // fire-and-track
375
+ * return controller.input
376
+ * },
377
+ * })
378
+ *
379
+ * const results = await runner.execute([1, 2, 3])
380
+ * // [1, 2, 3, 101, 102, 103] — declared inputs first (in order), then spawns (in order)
381
+ * ```
382
+ */
383
+ export declare function createRunner<TInput, TResult>(options: RunnerOptions<TInput, TResult>): RunnerInterface<TInput, TResult>;
384
+
385
+ /**
386
+ * Create the safe cross-environment cooperative-yield default — a
387
+ * {@link SchedulerInterface} built on `setTimeout` / `clearTimeout` alone, so it
388
+ * runs unchanged in both the browser and Node.
389
+ *
390
+ * @remarks
391
+ * `yield()` gives the host a turn via a zero-delay macrotask (so pending I/O,
392
+ * timers, and rendering actually run — a microtask would not); `delay(ms)` resumes
393
+ * after at least `ms`. Pass `options.signal` to make a pending yield/delay reject
394
+ * with the signal's `reason` on abort (with full timer/listener cleanup).
395
+ * `options.priority` is accepted for contract compliance but treated uniformly by
396
+ * this default — environment backends honour it.
397
+ *
398
+ * @returns A working {@link SchedulerInterface}
399
+ *
400
+ * @example
401
+ * ```ts
402
+ * import { createAbort, createScheduler } from '@src/core'
403
+ *
404
+ * const abort = createAbort()
405
+ * const scheduler = createScheduler()
406
+ *
407
+ * // A cooperative loop: do a unit of work, then hand the host a turn.
408
+ * while (!abort.signal.aborted) {
409
+ * doSomeWork()
410
+ * await scheduler.yield({ signal: abort.signal })
411
+ * }
412
+ * ```
413
+ *
414
+ * @example
415
+ * ```ts
416
+ * import { createScheduler } from '@src/core'
417
+ *
418
+ * // A backoff: wait a growing interval between retries.
419
+ * const scheduler = createScheduler()
420
+ * for (let attempt = 0; attempt < 5; attempt += 1) {
421
+ * if (await tryOnce()) break
422
+ * await scheduler.delay(2 ** attempt * 100)
423
+ * }
424
+ * ```
425
+ */
426
+ export declare function createScheduler(): SchedulerInterface;
427
+
428
+ /**
429
+ * Build the live W-b entity tree from a {@link WorkflowDefinition} — the whole
430
+ * {@link WorkflowInterface} → {@link import('./types.js').PhaseInterface} →
431
+ * {@link import('./types.js').TaskInterface} tree, each level wired with its lineage
432
+ * context, its emitter, and the cascade.
433
+ *
434
+ * @remarks
435
+ * The definition is the DECLARATIVE blueprint; this seeds an initial all-`pending`
436
+ * {@link WorkflowSnapshot} from it ({@link definitionToSnapshot}) and constructs the live
437
+ * tree over that one path. The `bail` failure policy resolves to `options.bail`, else the
438
+ * definition's `bail`, else the graceful {@link import('./constants.js').DEFAULT_BAIL}; it
439
+ * feeds {@link import('./helpers.js').deriveWorkflowStatus}. Per-phase / per-task initial
440
+ * listeners + metadata travel through `options.phases[id].on` /
441
+ * `options.phases[id].tasks[id]` (the AGENTS §8 nested-by-id bag). The W-b tree is the
442
+ * state machine ONLY — it does not execute tasks (W-c drives the transitions).
443
+ *
444
+ * @param definition - The workflow definition to bring to life
445
+ * @param options - Runtime options (initial listeners, `bail` override, per-node options)
446
+ * @returns The live {@link WorkflowInterface} root
447
+ *
448
+ * @example
449
+ * ```ts
450
+ * import { createWorkflow } from '@src/core'
451
+ *
452
+ * const workflow = createWorkflow(definition, { on: { complete: () => done() } })
453
+ * const phase = workflow.phase('phase-build')
454
+ * phase?.task('task-compile')?.start() // pending → running (cascades up)
455
+ * ```
456
+ */
457
+ export declare function createWorkflow(definition: WorkflowDefinition, options?: WorkflowOptions): WorkflowInterface;
458
+
459
+ /**
460
+ * Compile the workflow definition contract — the JSON Schema, guard, parser, and
461
+ * seeded generator for a {@link WorkflowDefinition}, all derived from one shape and
462
+ * kept in lockstep.
463
+ *
464
+ * @remarks
465
+ * The returned {@link ContractInterface}:
466
+ * - `schema` — the emitted JSON Schema for a workflow definition.
467
+ * - `is` — a total guard that narrows `unknown` to a valid {@link WorkflowDefinition}
468
+ * (malformed input returns `false`, never throws).
469
+ * - `parse` — coerces `unknown` to a {@link WorkflowDefinition}, or `undefined` when
470
+ * it does not match.
471
+ * - `generate` — produces a deterministic valid {@link WorkflowDefinition} from an
472
+ * optional seeded random source.
473
+ *
474
+ * @returns The compiled {@link WorkflowDefinition} contract
475
+ *
476
+ * @example
477
+ * ```ts
478
+ * import { createWorkflowContract } from '@src/core'
479
+ *
480
+ * const contract = createWorkflowContract()
481
+ * const definition = contract.generate() // a valid WorkflowDefinition
482
+ * contract.is(definition) // true
483
+ * contract.parse({ id: '', phases: [] }) // undefined (malformed)
484
+ * ```
485
+ */
486
+ export declare function createWorkflowContract(): ContractInterface<WorkflowDefinition>;
487
+
488
+ /**
489
+ * Compile the LENIENT workflow DRAFT contract — identical to
490
+ * {@link createWorkflowContract} EXCEPT `id` and `name` are OPTIONAL at all three levels
491
+ * (workflow / phase / task), so a small model can omit the six identity strings.
492
+ *
493
+ * @remarks
494
+ * The widened authoring surface {@link createWorkflowTool} parses an authored blob through
495
+ * before {@link import('./helpers.js').completeDraft} fills the missing ids/names. It does
496
+ * NOT relax the canonical contract — {@link createWorkflowContract} stays byte-for-byte
497
+ * unchanged and STRICT, and the completed draft is re-validated against THAT strict gate
498
+ * before running (soundness preserved). A PROVIDED `id` / `name` still carries `minLength: 1`,
499
+ * so an explicitly-empty `id: ''` is REJECTED (parses to `undefined`), never auto-filled —
500
+ * keeping "garbage" distinct from "omitted". `run` stays required.
501
+ *
502
+ * @returns The compiled {@link WorkflowDraft} contract
503
+ *
504
+ * @example
505
+ * ```ts
506
+ * import { createWorkflowDraftContract, completeDraft } from '@src/core'
507
+ *
508
+ * const draft = createWorkflowDraftContract()
509
+ * const parsed = draft.parse({ phases: [{ tasks: [{ run: { via: 'function', name: 'f' } }] }] })
510
+ * const definition = parsed && completeDraft(parsed) // ids/names filled positionally
511
+ * draft.parse({ id: '', phases: [] }) // undefined — an explicit empty id is rejected
512
+ * ```
513
+ */
514
+ export declare function createWorkflowDraftContract(): ContractInterface<WorkflowDraft>;
515
+
516
+ /**
517
+ * Create a workflow runner — a {@link WorkflowRunnerInterface} that EXECUTES a live W-b
518
+ * workflow tree by COMPOSING the shipped substrate: phases sequential, tasks concurrent,
519
+ * each task dispatched BY NAME under the workflow's `bail` policy.
520
+ *
521
+ * @remarks
522
+ * The runner is THIN — it re-implements no concurrency / retry / abort logic. Per-phase
523
+ * bounded concurrency is one {@link createRunner} per phase;
524
+ * `bail` maps onto that Runner's fail-fast (`true` — the first failure aborts the in-flight
525
+ * siblings + skips the rest) vs settle-all (`false` — failures are recorded, the run
526
+ * finishes); the run-level abort / timeout / budget ({@link import('./types.js').WorkflowRunOptions})
527
+ * fold through `AbortSignal.any` (the agent runtime's pattern); pacing is the shipped
528
+ * scheduler. `execute(definition, options?)` BUILDS the live tree from the definition itself
529
+ * (via {@link createWorkflow} — one source of truth, returned in `WorkflowResult.workflow`),
530
+ * drives the live entity (`start` → `complete` / `fail`), and resolves a
531
+ * {@link import('./types.js').WorkflowResult}.
532
+ *
533
+ * A task is dispatched on its {@link import('./types.js').TaskForm}: `function` → the
534
+ * `functions` registry, `tool` → the `tools` {@link ToolManagerInterface}, `agent` → the
535
+ * `agents` {@link import('./types.js').WorkflowAgents} resolver (W-c2), behind a depth + cycle
536
+ * guard. A task whose handler is NOT found (an unregistered name for ANY form) AUTO-COMPLETES
537
+ * (the ROADMAP no-handler rule).
538
+ *
539
+ * The runner is constructed with a reference to {@link createWorkflowTool} (the workflow-tool
540
+ * binder) so it can BIND a depth/cycle-aware workflow tool onto a dispatched subagent's context
541
+ * — the propagation seam — WITHOUT this module's classes importing its own `factories.ts` (the
542
+ * factories→classes direction; the binder is injected as a value at construction).
543
+ *
544
+ * @param options - The behavior registries (`functions` / `tools` / `agents`) the runner
545
+ * dispatches a task by name through, plus an optional pacing `scheduler` (default the shipped
546
+ * cross-environment one). Omitting `functions` / `tools` / `agents` makes those task forms
547
+ * auto-complete (no handler). See {@link WorkflowRunnerOptions}.
548
+ * @returns A working {@link WorkflowRunnerInterface}
549
+ *
550
+ * @example
551
+ * ```ts
552
+ * import { createWorkflowRunner, createToolManager } from '@src/core'
553
+ *
554
+ * const tools = createToolManager()
555
+ * const runner = createWorkflowRunner({
556
+ * functions: { compile: async (controller) => `built ${controller.task.id}` },
557
+ * tools,
558
+ * })
559
+ * const definition = { id: 'w', name: 'W', phases: [{ id: 'p', name: 'P', tasks: [
560
+ * { id: 't', name: 'T', run: { via: 'function', name: 'compile' } },
561
+ * ] }] }
562
+ * const result = await runner.execute(definition) // builds + drives the tree
563
+ * result.status // 'completed'
564
+ * result.workflow.phase('p')?.task('t')?.status // 'completed'
565
+ * ```
566
+ */
567
+ export declare function createWorkflowRunner(options?: WorkflowRunnerOptions): WorkflowRunnerInterface;
568
+
569
+ /**
570
+ * Wrap a {@link WorkflowDefinition} as an LLM-callable {@link ToolInterface} — it ADVERTISES
571
+ * the SIMPLE flat authoring shape (`{ name?, steps: [{ name, via? }] }`) as its `parameters` so
572
+ * even a small model can author a complete tree, and its handler EXPANDS / COMPLETES the
573
+ * authored blob, validates it against the STRICT contract, runs it through `runner`, and
574
+ * returns the run SUMMARY (throwing a typed {@link WorkflowError} on failure).
575
+ *
576
+ * @remarks
577
+ * A plain {@link ToolManagerInterface}-compatible tool (so `createMCPServer` / `createMCPRoutes`
578
+ * expose it for free — nothing MCP is wired here). It is ALSO the propagation carrier the
579
+ * {@link WorkflowRunner} binds onto a dispatched subagent (W-c2): because a tool handler receives
580
+ * ONLY the model-supplied `args` (no ambient context, no signal), the run's depth + ancestry are
581
+ * CLOSED OVER at bind time via {@link WorkflowToolOptions}, and the handler runs the nested
582
+ * workflow at `depth + 1` with the extended ancestry.
583
+ *
584
+ * **Widened authoring surface (additive — the canonical contract + runner stay STRICT and
585
+ * unchanged).** A 2B model reliably CALLS the tool but cannot reliably emit the full four-level
586
+ * nested {@link WorkflowDefinition} (six required `id`/`name` strings, a nested tagged union,
587
+ * all-or-nothing). So the tool ACCEPTS three authoring forms and converges them on the SAME
588
+ * strict {@link createWorkflowContract} gate before running (soundness preserved):
589
+ * - the FLAT shape `{ name?, steps: [{ name, via? }] }` — the ADVERTISED `parameters` (the simplest
590
+ * form, {@link import('./helpers.js').expandSteps}'d into one one-task phase per step);
591
+ * - a nested DRAFT with any `id`/`name` OMITTED — {@link createWorkflowDraftContract}-parsed then
592
+ * {@link import('./helpers.js').completeDraft}'d (missing ids synthesized positionally);
593
+ * - the full nested {@link WorkflowDefinition} — the advanced escape-hatch (documented in the
594
+ * description), accepted as the draft super-set.
595
+ *
596
+ * The handler conforms to the universal tool-handler contract (AGENTS §14): it returns the PLAIN
597
+ * run-summary VALUE on success and THROWS a typed {@link WorkflowError} on every failure path. It
598
+ * does NOT build a {@link ToolResult} itself — the `@orkestrel/agent` package's `ToolManager`
599
+ * performs the ONE canonical wrap (`{ id, name, value }` on a return; `{ id, name, error }` on a
600
+ * throw, ISOLATED so nothing escapes the run), so the outcome appears EXACTLY ONCE, identically,
601
+ * over BOTH the agent loop and MCP (a throw → MCP `isError: true`):
602
+ * - **No authored args** (an empty `arguments`) ⇒ runs the WRAPPED `definition`.
603
+ * - **A `steps` array** ⇒ the FLAT form: parse it, {@link import('./helpers.js').expandSteps} it.
604
+ * - **Otherwise** ⇒ the nested form: {@link createWorkflowDraftContract}-parse it,
605
+ * {@link import('./helpers.js').completeDraft} it.
606
+ * - **Strict gate** ⇒ the expanded / completed result is validated against
607
+ * {@link createWorkflowContract}.`is`; a blob that can't expand, or whose result fails the strict
608
+ * gate (e.g. an explicit empty `id`, `concurrency: 0`) ⇒ THROW a `TOOL` {@link WorkflowError} (no run).
609
+ * - **Over-deep / cyclic** ⇒ THROW a `DEPTH` {@link WorkflowError} when the nested run would exceed
610
+ * {@link MAX_WORKFLOW_DEPTH}, or the target workflow id is already an ancestor (a cycle) — the
611
+ * same `code` the agent-task guard raises.
612
+ * - **Otherwise** ⇒ `runner.execute(target, { depth: depth + 1, ancestry: … })`, RETURNING the
613
+ * plain summary of the terminal run (`{ status, count }`, via {@link workflowToolSummary}).
614
+ *
615
+ * @param definition - The workflow the tool runs when called with no authored args
616
+ * @param runner - The {@link WorkflowRunnerInterface} that executes the (nested) workflow
617
+ * @param options - The depth + ancestry to run the nested workflow under (see
618
+ * {@link WorkflowToolOptions}); omitted ⇒ depth `0` / empty ancestry (a top-level wrap)
619
+ * @returns A {@link ToolInterface} (named {@link import('./constants.js').WORKFLOW_TOOL_NAME})
620
+ * whose `parameters` advertise the FLAT authoring schema (the nested form stays accepted)
621
+ *
622
+ * @example
623
+ * ```ts
624
+ * import { createWorkflowRunner, createWorkflowTool, createToolManager } from '@src/core'
625
+ *
626
+ * const runner = createWorkflowRunner()
627
+ * const tool = createWorkflowTool(definition, runner)
628
+ * const tools = createToolManager()
629
+ * tools.add(tool) // a model can now author + run a workflow in one call
630
+ * ```
631
+ */
632
+ export declare function createWorkflowTool(definition: WorkflowDefinition, runner: WorkflowRunnerInterface, options?: WorkflowToolOptions): ToolInterface;
633
+
634
+ /**
635
+ * A {@link WorkflowStoreInterface} backed by one table of the `databases` layer — a
636
+ * workflow's durable run-state IS a row, so persistence reduces to keyed point-access
637
+ * (`get` / `set` / `delete`) over a `TableInterface`, the driver-pluggable twin of the
638
+ * plain-`Map` {@link import('./MemoryWorkflowStore.js').MemoryWorkflowStore}.
639
+ *
640
+ * @remarks
641
+ * The store is driver-agnostic: it holds a single {@link TableInterface} whose backend
642
+ * (memory, JSON, SQLite, IndexedDB) is chosen by whoever builds it (the factories), so a
643
+ * JSON / SQLite / IndexedDB backend swaps in WITHOUT touching the runner or the entity tree
644
+ * — the same seam as `@orkestrel/queue`'s `DatabaseQueueStore`.
645
+ * The driver defaults to memory ({@link import('../factories.js').createDatabaseWorkflowStore}
646
+ * passes `createMemoryDriver()`), so it ALSO works in memory out of the box; you opt into the
647
+ * durable plumbing by passing a JSON / SQLite / IndexedDB driver.
648
+ *
649
+ * The {@link WorkflowSnapshot} is stored as ONE OPAQUE JSON COLUMN — the table is a row of
650
+ * `{ id; snapshot }` ({@link WorkflowSnapshotRow}), the snapshot the whole JSON blob (a `rawShape`
651
+ * column the factory builds) — exactly as `DatabaseQueueStore` stores its `input`. The snapshot is
652
+ * already a COMPLETE, self-contained, pure-JSON payload, so storing it whole is lossless AND
653
+ * sidesteps a TS2589 instantiation-depth blow-up: a structured multi-column table would force the
654
+ * contract to `Infer` the deeply-nested snapshot shape (workflow → phases → tasks → results),
655
+ * tripping the compiler — one JSON column keeps the row type flat (`snapshot` reads back as `unknown`).
656
+ *
657
+ * - **`set(snapshot)` upserts under the snapshot's OWN `id`** (no separate id param) — it writes
658
+ * the row `{ id: snapshot.id, snapshot }`.
659
+ * - **`get(id)` resolves the stored snapshot for an id**, narrowing the opaque JSON column back to
660
+ * a {@link WorkflowSnapshot} ({@link import('../helpers.js').isWorkflowSnapshot} — the AGENTS §14
661
+ * boundary narrow for an untrusted storage read), or `undefined` if none is stored.
662
+ * - **`delete(id)` drops a snapshot by id**; an absent id is a no-op (no throw).
663
+ *
664
+ * UNLIKE the server package's `SessionStoreInterface` there is NO
665
+ * idle-TTL / eviction — a persisted run-state is durable orchestration state that lives until an
666
+ * explicit `delete`. The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the
667
+ * §22 method bijection with {@link WorkflowStoreInterface}). Restore stays a caller concern: read a
668
+ * snapshot back and rebuild the live tree with {@link import('../factories.js').restoreWorkflow}.
669
+ *
670
+ * @example
671
+ * ```ts
672
+ * import { createDatabaseWorkflowStore, createMemoryDriver, createWorkflow, restoreWorkflow } from '@src/core'
673
+ *
674
+ * const store = createDatabaseWorkflowStore(createMemoryDriver()) // a durable driver swaps in here
675
+ * const workflow = createWorkflow(definition)
676
+ * await store.set(workflow.snapshot()) // persist the run state (one JSON column)
677
+ * const snapshot = await store.get(definition.id)
678
+ * const restored = snapshot && restoreWorkflow(snapshot) // an identical live tree
679
+ * await store.delete(definition.id) // drop it
680
+ * ```
681
+ */
682
+ export declare class DatabaseWorkflowStore implements WorkflowStoreInterface {
683
+ #private;
684
+ /**
685
+ * Wrap a table as a workflow store.
686
+ *
687
+ * @param table - The {@link TableInterface} holding the snapshots — its row is the
688
+ * {@link WorkflowSnapshotRow} `{ id; snapshot }` shape (the snapshot one opaque JSON column)
689
+ */
690
+ constructor(table: TableInterface<WorkflowSnapshotRow>);
691
+ /** Resolve the persisted snapshot for `id`, narrowing the opaque JSON column back to a `WorkflowSnapshot`. */
692
+ get(id: string): Promise<WorkflowSnapshot | undefined>;
693
+ /** Insert or replace under the snapshot's OWN `id` (no separate id param) — the row is `{ id, snapshot }`. */
694
+ set(snapshot: WorkflowSnapshot): Promise<void>;
695
+ /** Drop a snapshot by id; an absent id is a no-op (no throw). */
696
+ delete(id: string): Promise<void>;
697
+ }
698
+
699
+ /** The default {@link import('./types.js').WorkflowDefinition.bail} — graceful (continue on a leaf failure). */
700
+ export declare const DEFAULT_BAIL = false;
701
+
702
+ /**
703
+ * The default per-phase task concurrency the {@link import('./factories.js').createWorkflowRunner}
704
+ * runner applies when a {@link import('./types.js').PhaseDefinition} omits its `concurrency`
705
+ * throttle — a large cap that is effectively unbounded for any realistic phase.
706
+ *
707
+ * @remarks
708
+ * The determinism principle fixes that a phase's tasks run CONCURRENTLY; `concurrency` is
709
+ * only an optional resource throttle (max-in-flight). With none declared, the runner runs
710
+ * all of a phase's tasks at once — modelled as this large finite cap so the value flows
711
+ * straight into the substrate {@link import('./types.js').RunnerInterface}'s
712
+ * `concurrency` (which expects a positive integer) without a special unbounded branch. No
713
+ * realistic phase declares enough tasks to reach it, so it behaves as "run them all".
714
+ */
715
+ export declare const DEFAULT_PHASE_CONCURRENCY = 1000000;
716
+
717
+ /**
718
+ * A promise paired with its externally-callable `resolve`/`reject` — the settle path
719
+ * is exposed to the caller instead of being buried in an executor closure.
720
+ *
721
+ * @typeParam T - The value the deferred's `promise` resolves
722
+ */
723
+ export declare interface DeferredInterface<T> {
724
+ readonly promise: Promise<T>;
725
+ resolve(value: T): void;
726
+ reject(reason: unknown): void;
727
+ }
728
+
729
+ /**
730
+ * Convert a {@link WorkflowDefinition} into an INITIAL {@link WorkflowSnapshot} — every
731
+ * node `pending`, no results, empty metadata — so the live W-b tree has ONE construction
732
+ * path (snapshot-driven) for both a fresh build and a restore.
733
+ *
734
+ * @remarks
735
+ * The structural fields (`id` / `name` / `description` + the ordered phases / tasks)
736
+ * carry over verbatim; the W-b live tree is the DECLARATIVE state machine, so the
737
+ * execution-only definition fields (per-phase `run` / `concurrency`, per-task `retries` /
738
+ * `timeout`) are intentionally dropped (W-c reads them from the definition when it drives
739
+ * transitions). The `bail` policy carries over — at the workflow tier AND, per phase, the
740
+ * EFFECTIVE policy (`phase.bail ?? workflowBail`) on each {@link PhaseSnapshot} — so the seeded
741
+ * snapshot is self-contained; a fresh seed has no `override`. `created` / `updated` are stamped now.
742
+ * {@link import('./factories.js').createWorkflow} builds from this.
743
+ *
744
+ * The optional `bail` override is the EFFECTIVE workflow policy the tree will run under
745
+ * (`createWorkflow` / the runner resolve `options.bail ?? definition.bail ?? DEFAULT_BAIL` and
746
+ * pass it here), so an `options.bail` override reaches BOTH the workflow tier AND the
747
+ * inheritance default of every phase that declares no `bail` of its own — otherwise the
748
+ * per-phase seeds would silently ignore the override. Omitted ⇒ the definition's own `bail`
749
+ * (defaulting to the graceful {@link import('./constants.js').DEFAULT_BAIL}).
750
+ *
751
+ * @param definition - The workflow definition to seed from
752
+ * @param bail - The EFFECTIVE workflow bail to seed both tiers with (defaults to the definition's)
753
+ * @returns An initial, all-`pending` {@link WorkflowSnapshot}
754
+ */
755
+ export declare function definitionToSnapshot(definition: WorkflowDefinition, bail?: boolean): WorkflowSnapshot;
756
+
757
+ /**
758
+ * Derive a phase's status from its tasks' statuses (tasks are concurrent, so this
759
+ * is an order-insensitive reduction).
760
+ *
761
+ * @remarks
762
+ * The truth table (most-severe terminal wins; `bail`-agnostic — a phase surfaces a
763
+ * task failure as `failed` so the workflow's `bail` policy can decide):
764
+ * - no tasks ⇒ `pending`.
765
+ * - any task `running`, OR a mix of started-and-unsettled tasks (some non-`pending`
766
+ * but not all terminal) ⇒ `running`.
767
+ * - every task `pending` ⇒ `pending`.
768
+ * - all terminal: any `failed` ⇒ `failed`; else any `stopped` ⇒ `stopped`; else any
769
+ * `completed` ⇒ `completed`; else (all `skipped`) ⇒ `skipped`.
770
+ *
771
+ * So an all-`skipped` phase is `skipped`, an all-`stopped` phase is `stopped`, a
772
+ * phase with completed tasks and some skips is `completed`, and a single failed
773
+ * task makes the phase `failed`.
774
+ *
775
+ * @param tasks - The phase's task statuses, in any order
776
+ * @returns The derived {@link PhaseStatus}
777
+ */
778
+ export declare function derivePhaseStatus(tasks: readonly TaskStatus[]): PhaseStatus;
779
+
780
+ /**
781
+ * Derive a workflow's status from its phases' {@link PhaseDerivation}s — each phase's status
782
+ * paired with the EFFECTIVE `bail` it ran under (`phase.bail ?? workflow.bail`) — so the
783
+ * failure outcome is PER-PHASE-bail-aware (phases are sequential, but the derivation is an
784
+ * order-insensitive reduction over the settled set).
785
+ *
786
+ * @remarks
787
+ * `bail` is now a per-phase override (AGENTS §4.4), so it is carried on each
788
+ * {@link PhaseDerivation} rather than passed as one scalar. It is the ONLY axis that changes
789
+ * the failure outcome, decided per phase:
790
+ * - **A `failed` phase whose effective `bail` is `true` (halt)** propagates ⇒ the workflow is
791
+ * `failed` (the database-transaction halt) — even when the workflow default is graceful.
792
+ * - **A `failed` phase whose effective `bail` is `false` (graceful)** is DATA, not a workflow
793
+ * failure — it folds into completion like a settled phase. A graceful failed phase NEVER
794
+ * makes the workflow `failed` — even when the workflow default is strict.
795
+ *
796
+ * The rest of the table is shared:
797
+ * - no phases ⇒ `pending`.
798
+ * - any phase `running`, OR a mix of started-and-unsettled phases (some non-`pending`
799
+ * but not all terminal) ⇒ `running`.
800
+ * - every phase `pending` ⇒ `pending`.
801
+ * - all terminal (a `failed` phase counts as terminal here): any `stopped` ⇒ `stopped`; else
802
+ * any `completed` (or any graceful-bail `failed`, folded into completion) ⇒ `completed`;
803
+ * else (all `skipped`) ⇒ `skipped`.
804
+ *
805
+ * @param phases - The workflow's per-phase {@link PhaseDerivation}s (status + effective bail), in any order
806
+ * @returns The derived {@link WorkflowStatus}
807
+ */
808
+ export declare function deriveWorkflowStatus(phases: readonly PhaseDerivation[]): WorkflowStatus;
809
+
810
+ /**
811
+ * Expand a flat {@link WorkflowSteps} blob into a strict {@link WorkflowDefinition} — each
812
+ * step becomes a one-task phase, IN ORDER.
813
+ *
814
+ * @remarks
815
+ * The expansion of the tool's ADVERTISED surface (AGENTS §21 — the simplest form a small
816
+ * model can author). Each {@link WorkflowStep} maps to a phase holding exactly one task:
817
+ * the step's `name` becomes the task's `run.name`, and its `via` becomes the task's `run.via`
818
+ * (defaulting to `'function'` when omitted). Ids/names are auto-filled positionally — it
819
+ * builds an ids-omitted {@link WorkflowDraft} and delegates to {@link completeDraft}, so the
820
+ * two lenient surfaces share ONE synthesis path (step `i` → phase `phase-<i>`, its task
821
+ * `phase-<i>-task-0`). The optional `name` becomes the workflow's `name`. The result is a
822
+ * complete definition the caller validates against the STRICT contract before running.
823
+ *
824
+ * @param flat - The flat steps blob (`{ name?, steps: [{ name, via? }] }`)
825
+ * @returns A complete {@link WorkflowDefinition} (one one-task phase per step)
826
+ */
827
+ export declare function expandSteps(flat: WorkflowSteps): WorkflowDefinition;
828
+
829
+ /**
830
+ * Narrow a {@link TaskForm} to the `agent` form — a task that runs a registered
831
+ * agent (a subagent).
832
+ *
833
+ * @param form - The task form to test
834
+ * @returns `true` when `form.via` is `'agent'`
835
+ */
836
+ export declare function isAgentTask(form: TaskForm): form is {
837
+ readonly via: 'agent';
838
+ readonly name: string;
839
+ };
840
+
841
+ /**
842
+ * Narrow a {@link TaskForm} to the `function` form — a task that runs a registered
843
+ * function.
844
+ *
845
+ * @param form - The task form to test
846
+ * @returns `true` when `form.via` is `'function'`
847
+ */
848
+ export declare function isFunctionTask(form: TaskForm): form is {
849
+ readonly via: 'function';
850
+ readonly name: string;
851
+ };
852
+
853
+ /**
854
+ * Test whether a {@link LifecycleStatus} is TERMINAL — a node in this state will not
855
+ * transition further.
856
+ *
857
+ * @remarks
858
+ * The ONE terminal check across all three tiers (AGENTS §4.4 "one concept = one word"):
859
+ * a task, a phase, and a workflow share the same {@link LifecycleStatus} vocabulary, so a
860
+ * single predicate covers them — {@link derivePhaseStatus} and {@link deriveWorkflowStatus}
861
+ * both consult it to tell a settled node from an in-flight one. Terminal: `completed` /
862
+ * `failed` / `skipped` / `stopped`; the only non-terminal states are `pending` and
863
+ * `running`.
864
+ *
865
+ * @param status - The lifecycle status to test (a task / phase / workflow status)
866
+ * @returns `true` when the status is terminal
867
+ */
868
+ export declare function isTerminalStatus(status: LifecycleStatus): boolean;
869
+
870
+ /**
871
+ * Narrow a {@link TaskForm} to the `tool` form — a task that runs a registered tool.
872
+ *
873
+ * @param form - The task form to test
874
+ * @returns `true` when `form.via` is `'tool'`
875
+ */
876
+ export declare function isToolTask(form: TaskForm): form is {
877
+ readonly via: 'tool';
878
+ readonly name: string;
879
+ };
880
+
881
+ /**
882
+ * Narrow an unknown caught value to a {@link WorkflowError}.
883
+ *
884
+ * @param value - The value to test (typically a `catch` binding)
885
+ * @returns `true` when `value` is a {@link WorkflowError}
886
+ *
887
+ * @example
888
+ * ```ts
889
+ * try {
890
+ * task.complete('done')
891
+ * } catch (error) {
892
+ * if (isWorkflowError(error) && error.code === 'TRANSITION') retry()
893
+ * }
894
+ * ```
895
+ */
896
+ export declare function isWorkflowError(value: unknown): value is WorkflowError;
897
+
898
+ /**
899
+ * Narrow an `unknown` to a {@link WorkflowSnapshot} — the AGENTS §14 boundary guard for an
900
+ * UNTRUSTED snapshot read (a storage row a {@link import('./stores/DatabaseWorkflowStore.js').DatabaseWorkflowStore}
901
+ * reads back from its opaque JSON column, a snapshot loaded from disk).
902
+ *
903
+ * @remarks
904
+ * A total guard (it NEVER throws — adversarial input returns `false`, AGENTS §14). It checks the
905
+ * snapshot's SHAPE — `id` / `name` / `status` strings, a `boolean` `bail`, an array of `phases`,
906
+ * `created` / `updated` numbers — enough to safely impose the {@link WorkflowSnapshot} type at a
907
+ * storage boundary WITHOUT a cast. It is complementary to
908
+ * {@link import('./factories.js').assertSnapshot}, which validates the DEEPER invariant (every
909
+ * node's status / override drawn from the lifecycle vocabulary) and THROWS a `RESTORE`
910
+ * {@link import('./errors.js').WorkflowError} — the deep gate a {@link import('./factories.js').restoreWorkflow}
911
+ * applies. A boundary read narrows shape with this guard; a restore validates vocabulary with `assertSnapshot`.
912
+ *
913
+ * @param value - The value to test (an opaque storage read)
914
+ * @returns `true` when `value` has the structural shape of a {@link WorkflowSnapshot}
915
+ */
916
+ export declare function isWorkflowSnapshot(value: unknown): value is WorkflowSnapshot;
917
+
918
+ /**
919
+ * The shared lifecycle vocabulary every tier draws from — `pending` before it runs,
920
+ * `running` while in flight, then one of the terminal states `completed` / `failed` /
921
+ * `skipped` / `stopped`.
922
+ *
923
+ * @remarks
924
+ * The ONE literal set behind the three semantic tiers ({@link TaskStatus} /
925
+ * {@link PhaseStatus} / {@link WorkflowStatus}), which alias it so each keeps its own
926
+ * name + doc while the vocabulary lives in one place (AGENTS §4.4 "one concept = one
927
+ * word"). It also types the single runtime terminal check
928
+ * {@link import('./helpers.js').isTerminalStatus} — every tier's value is a
929
+ * `LifecycleStatus`, so the one predicate accepts them all. The tiers stay distinct
930
+ * types (a phase status is not a task status) even though they currently share a body.
931
+ */
932
+ export declare type LifecycleStatus = 'pending' | 'running' | 'completed' | 'failed' | 'skipped' | 'stopped';
933
+
934
+ /**
935
+ * The maximum nesting depth a workflow's `agent` task may spawn into (W-c) — the
936
+ * bound the runner's depth/cycle guard enforces.
937
+ *
938
+ * @remarks
939
+ * The limit lives in ONE place. The `agent` {@link import('./types.js').TaskForm} is
940
+ * bounded by it when the {@link import('./WorkflowRunner.js').WorkflowRunner} resolves a
941
+ * subagent: an agent running at this depth can no longer author + run a nested workflow
942
+ * (that would be depth `MAX_WORKFLOW_DEPTH + 1`), so the over-deep `agent` task is
943
+ * rejected (a typed `DEPTH` `task.fail`). The chain therefore nests workflows down to
944
+ * this depth, and the `agent` task in the depth-`MAX_WORKFLOW_DEPTH` workflow fails.
945
+ */
946
+ export declare const MAX_WORKFLOW_DEPTH = 8;
947
+
948
+ /**
949
+ * The in-memory {@link WorkflowStoreInterface} — a process-lifetime `Map` of
950
+ * {@link WorkflowSnapshot}s keyed by workflow id, the DEFAULT store
951
+ * {@link import('../factories.js').createMemoryWorkflowStore} builds.
952
+ *
953
+ * @remarks
954
+ * A plain `Map<string, WorkflowSnapshot>` (AGENTS §21 — the snapshot is already pure,
955
+ * self-contained JSON, so no encoding is needed for the memory tier). UNLIKE the server
956
+ * package's `SessionStoreInterface`'s memory store there is
957
+ * NO idle-TTL and NO eviction: a persisted workflow run-state is durable orchestration state
958
+ * that lives until an explicit `delete`, never silently aging out (a run that vanished
959
+ * mid-flight would be a silent data loss, not a freed session). A durable backend (JSON /
960
+ * SQLite / IndexedDB) swaps in through the SAME interface without touching the runner or the
961
+ * entity tree — its driver-pluggable twin is
962
+ * {@link import('./DatabaseWorkflowStore.js').DatabaseWorkflowStore} (the snapshot as one opaque
963
+ * JSON column), exactly as `@orkestrel/queue`'s `MemoryQueueStore`
964
+ * twins `DatabaseQueueStore`.
965
+ *
966
+ * - **`get` resolves the persisted snapshot for an id**, or `undefined` if none is stored.
967
+ * - **`set` inserts / replaces under the snapshot's OWN `id`** (no separate id param).
968
+ * - **`delete` drops a snapshot by id**; an absent id is a no-op (no throw).
969
+ *
970
+ * The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the §22 method
971
+ * bijection with {@link WorkflowStoreInterface}). Restore is a caller concern: read a snapshot
972
+ * back and rebuild the live tree with {@link import('../factories.js').restoreWorkflow}.
973
+ *
974
+ * @example
975
+ * ```ts
976
+ * import { createMemoryWorkflowStore, createWorkflow, restoreWorkflow } from '@src/core'
977
+ *
978
+ * const store = createMemoryWorkflowStore()
979
+ * const workflow = createWorkflow(definition)
980
+ * await store.set(workflow.snapshot()) // persist the run state
981
+ * const snapshot = await store.get(definition.id)
982
+ * const restored = snapshot && restoreWorkflow(snapshot) // an identical live tree
983
+ * await store.delete(definition.id) // drop it
984
+ * ```
985
+ */
986
+ export declare class MemoryWorkflowStore implements WorkflowStoreInterface {
987
+ #private;
988
+ get(id: string): Promise<WorkflowSnapshot | undefined>;
989
+ set(snapshot: WorkflowSnapshot): Promise<void>;
990
+ delete(id: string): Promise<void>;
991
+ }
992
+
993
+ /**
994
+ * The live DERIVED state machine (W-b) for one phase — an observable (AGENTS §13) whose
995
+ * {@link PhaseStatus} is computed from its tasks (never set directly) and recomputed
996
+ * reactively as a task transitions (the middle tier of the cascade).
997
+ *
998
+ * @remarks
999
+ * - **Derived status.** `status` is `#override` when one is in force, else
1000
+ * {@link derivePhaseStatus} over the live tasks' statuses. {@link #recompute} (passed to
1001
+ * each child {@link Task}) re-derives on every child transition; a CHANGE emits the matching
1002
+ * event AND escalates to the workflow ({@link #escalate}, the upward step of the cascade).
1003
+ * - **Override (AGENTS §10).** `skip` / `stop` FORCE the phase's status (e.g. skipping a whole
1004
+ * phase), overriding the derived value; the override is PERSISTED in the snapshot's own
1005
+ * `override` field and restored DIRECTLY (no divergence guess), so a forced phase round-trips.
1006
+ * - **Children (AGENTS §9).** `tasks` is the lean {@link TaskManager} (an accessor + `count`,
1007
+ * no batch matrix); built positionally from the snapshot so order survives an interior `skip`.
1008
+ * `results()` collects the settled tasks' {@link TaskResult}s (the phase tier of the result
1009
+ * tree); `workflow` navigates UP to the live parent.
1010
+ * - **Observable (AGENTS §13).** The owned {@link emitter} ({@link PhaseEventMap}) fires
1011
+ * `start` / `complete` / `fail` / `stop` on a derived-status CHANGE, strictly AFTER the
1012
+ * recompute + escalate; the emitter isolates a listener throw and routes it to its `error`
1013
+ * handler (the `error` option); `fail` carries the failing task's {@link TaskResult}.
1014
+ */
1015
+ export declare class Phase implements PhaseInterface {
1016
+ #private;
1017
+ constructor(snapshot: PhaseSnapshot, workflow: WorkflowInterface, escalate: () => void, options?: PhaseOptions, bail?: boolean);
1018
+ get emitter(): EmitterInterface<PhaseEventMap>;
1019
+ get id(): string;
1020
+ get name(): string;
1021
+ get description(): string | undefined;
1022
+ get context(): PhaseContext;
1023
+ get workflow(): WorkflowInterface;
1024
+ get bail(): boolean;
1025
+ get status(): PhaseStatus;
1026
+ get tasks(): TaskManagerInterface;
1027
+ task(id: string): TaskInterface | undefined;
1028
+ results(): readonly TaskResult[];
1029
+ skip(): void;
1030
+ stop(): void;
1031
+ snapshot(): PhaseSnapshot;
1032
+ }
1033
+
1034
+ /** Every {@link PhaseStatus} value, frozen — the lifecycle vocabulary of a phase. */
1035
+ export declare const PHASE_STATUSES: readonly PhaseStatus[];
1036
+
1037
+ /**
1038
+ * The ambient context of a phase — its own identity plus a back-reference to the
1039
+ * workflow it belongs to.
1040
+ *
1041
+ * @remarks
1042
+ * Extends {@link WorkflowContext} (so the phase carries its own `id` / `name`) and
1043
+ * adds `workflow`, the parent's context — the lineage pointer back UP the tree.
1044
+ */
1045
+ export declare interface PhaseContext extends WorkflowContext {
1046
+ readonly workflow: WorkflowContext;
1047
+ }
1048
+
1049
+ /**
1050
+ * The serializable definition of one phase — its identity, its ordered tasks, and
1051
+ * an optional resource throttle.
1052
+ *
1053
+ * @remarks
1054
+ * Pure JSON DATA. `tasks` are the phase's tasks, which run CONCURRENTLY (the fixed
1055
+ * determinism principle). `concurrency` is the optional per-phase resource throttle
1056
+ * — the maximum number of tasks in flight at once (a positive integer); omitted ⇒
1057
+ * unbounded. It is a throttle, NOT a sequencing control: phases are always
1058
+ * sequential, tasks within a phase always concurrent.
1059
+ */
1060
+ export declare interface PhaseDefinition {
1061
+ readonly id: string;
1062
+ readonly name: string;
1063
+ readonly description?: string;
1064
+ readonly tasks: readonly TaskDefinition[];
1065
+ /** Max tasks in flight at once (a resource throttle); omitted ⇒ unbounded. */
1066
+ readonly concurrency?: number;
1067
+ /**
1068
+ * @remarks
1069
+ * The per-phase failure-policy OVERRIDE (AGENTS §4.4). Omitted ⇒ the phase INHERITS the
1070
+ * workflow `bail`; supplied, it wins (`effectiveBail = phase.bail ?? workflow.bail`). A
1071
+ * `bail: true` phase HALTS the run on its first task failure even under a graceful workflow
1072
+ * default; a `bail: false` phase does NOT halt even under a strict workflow default.
1073
+ */
1074
+ readonly bail?: boolean;
1075
+ }
1076
+
1077
+ /**
1078
+ * Convert one {@link import('./types.js').PhaseDefinition} into an initial, all-`pending`
1079
+ * {@link PhaseSnapshot} — the per-phase step of {@link definitionToSnapshot}.
1080
+ *
1081
+ * @remarks
1082
+ * The snapshot persists the EFFECTIVE failure policy this phase runs under: the phase's own
1083
+ * `bail` when it declares one, else the `workflowBail` it inherits — so a restore reinstates
1084
+ * the same per-phase policy without a silent default (`effectiveBail = phase.bail ?? workflowBail`).
1085
+ *
1086
+ * @param phase - The phase definition to seed from
1087
+ * @param workflowBail - The workflow-level `bail` default the phase inherits when it declares none
1088
+ * @returns An initial {@link PhaseSnapshot}
1089
+ */
1090
+ export declare function phaseDefinitionToSnapshot(phase: WorkflowDefinition['phases'][number], workflowBail: boolean): PhaseSnapshot;
1091
+
1092
+ /**
1093
+ * One phase's contribution to the workflow-status derivation — its {@link PhaseStatus} paired
1094
+ * with the EFFECTIVE `bail` policy it ran under (`phase.bail ?? workflow.bail`, AGENTS §4.4).
1095
+ *
1096
+ * @remarks
1097
+ * The input shape of {@link import('./helpers.js').deriveWorkflowStatus}: since `bail` is now a
1098
+ * per-phase override, the workflow `failed` derivation is per-phase-bail-aware, so each phase
1099
+ * must carry its OWN effective policy rather than the derivation taking one scalar `bail`. A
1100
+ * `failed` phase propagates `failed` to the workflow only when ITS `bail` is `true`; a `failed`
1101
+ * phase whose `bail` is `false` folds into completion. {@link import('./Workflow.js').Workflow}
1102
+ * builds one per live phase (`{ status: phase.status, bail: phase.bail }`).
1103
+ */
1104
+ export declare interface PhaseDerivation {
1105
+ readonly status: PhaseStatus;
1106
+ readonly bail: boolean;
1107
+ }
1108
+
1109
+ /** A draft phase — a {@link PhaseDefinition} with OPTIONAL `id` / `name` and {@link TaskDraft} tasks. */
1110
+ export declare interface PhaseDraft {
1111
+ readonly id?: string;
1112
+ readonly name?: string;
1113
+ readonly description?: string;
1114
+ readonly tasks: readonly TaskDraft[];
1115
+ /** Max tasks in flight at once (a resource throttle); omitted ⇒ unbounded. */
1116
+ readonly concurrency?: number;
1117
+ /** The per-phase failure-policy OVERRIDE; omitted ⇒ inherits the workflow `bail` (`effectiveBail = phase.bail ?? workflow.bail`). */
1118
+ readonly bail?: boolean;
1119
+ }
1120
+
1121
+ /**
1122
+ * The shape of a PHASE in a draft workflow — identical to {@link phaseShape} EXCEPT
1123
+ * `id` and `name` are OPTIONAL, and its tasks are {@link taskDraftShape}s.
1124
+ */
1125
+ export declare const phaseDraftShape: ObjectShape<{
1126
+ id: OptionalShape<StringShape>;
1127
+ name: OptionalShape<StringShape>;
1128
+ description: OptionalShape<StringShape>;
1129
+ tasks: ArrayShape<ObjectShape<{
1130
+ id: OptionalShape<StringShape>;
1131
+ name: OptionalShape<StringShape>;
1132
+ description: OptionalShape<StringShape>;
1133
+ run: UnionShape<[ ObjectShape<{
1134
+ via: LiteralShape<readonly ["function"]>;
1135
+ name: StringShape;
1136
+ }>, ObjectShape<{
1137
+ via: LiteralShape<readonly ["tool"]>;
1138
+ name: StringShape;
1139
+ }>, ObjectShape<{
1140
+ via: LiteralShape<readonly ["agent"]>;
1141
+ name: StringShape;
1142
+ }>]>;
1143
+ retries: OptionalShape<NumberShape>;
1144
+ timeout: OptionalShape<NumberShape>;
1145
+ }>>;
1146
+ concurrency: OptionalShape<NumberShape>;
1147
+ bail: OptionalShape<LiteralShape<readonly [true, false]>>;
1148
+ }>;
1149
+
1150
+ /**
1151
+ * The push observation surface (AGENTS §13) of the phase entity (W-b) — analogous
1152
+ * to {@link WorkflowEventMap}, scoped to one phase.
1153
+ *
1154
+ * @remarks
1155
+ * `start` fires when the phase begins; `complete` when all its tasks settled
1156
+ * successfully; `fail` when a task failed under `bail` (carrying the
1157
+ * {@link TaskResult}); `stop` when the phase was ended. A throwing listener is
1158
+ * isolated by the emitter and routed to its `error` handler, not the domain surface
1159
+ * (AGENTS §13). A `type` alias (AGENTS §4.5) so it satisfies `EventMap`.
1160
+ */
1161
+ export declare type PhaseEventMap = {
1162
+ /** The phase began — its `id`. */
1163
+ readonly start: readonly [id: string];
1164
+ /** Every task in the phase settled successfully. */
1165
+ readonly complete: readonly [];
1166
+ /** A task failed under `bail` — the failing task's result. */
1167
+ readonly fail: readonly [result: TaskResult];
1168
+ /** The phase was permanently stopped. */
1169
+ readonly stop: readonly [];
1170
+ };
1171
+
1172
+ /** Initial {@link PhaseEventMap} listeners — the reserved `on` option (AGENTS §8). */
1173
+ export declare type PhaseHooks = EmitterHooks<PhaseEventMap>;
1174
+
1175
+ /** The minimal data to create a phase context — a partial {@link PhaseContext}. */
1176
+ export declare type PhaseInput = Partial<PhaseContext>;
1177
+
1178
+ /**
1179
+ * The live derived state machine (W-b) for one {@link PhaseDefinition} — an
1180
+ * observable (AGENTS §13) phase whose {@link PhaseStatus} is DERIVED from its tasks
1181
+ * (never set directly) and recomputed reactively as a task transitions (the cascade).
1182
+ *
1183
+ * @remarks
1184
+ * - **Derived status.** `status` is computed via
1185
+ * {@link import('./helpers.js').derivePhaseStatus} over the live tasks' statuses,
1186
+ * UNLESS an override is in force. It recomputes whenever a child task transitions; a
1187
+ * CHANGE emits.
1188
+ * - **Children.** `tasks` is the lean {@link TaskManagerInterface} (AGENTS §9 — an
1189
+ * accessor + `count`, no batch matrix); `task(id)` / `tasks().tasks()` read in positional
1190
+ * order. `results` collects the settled tasks' {@link TaskResult}s (the phase tier of the
1191
+ * result tree); `workflow` navigates UP to the live parent.
1192
+ * - **Override.** `skip` / `stop` (AGENTS §10) FORCE the phase's status, overriding the
1193
+ * derived value (e.g. skipping a whole phase); the override survives a snapshot.
1194
+ * - **Observable (AGENTS §13).** The owned {@link emitter} ({@link PhaseEventMap}) fires
1195
+ * `start` / `complete` / `fail` / `stop` on a derived-status change; the emitter isolates a
1196
+ * listener throw and routes it to its `error` handler (the `error` option).
1197
+ */
1198
+ export declare interface PhaseInterface {
1199
+ readonly emitter: EmitterInterface<PhaseEventMap>;
1200
+ readonly id: string;
1201
+ readonly name: string;
1202
+ readonly description?: string;
1203
+ readonly context: PhaseContext;
1204
+ readonly workflow: WorkflowInterface;
1205
+ readonly status: PhaseStatus;
1206
+ /** The RESOLVED effective failure policy this phase runs under (`phase.bail ?? workflow.bail`); mirrors {@link WorkflowInterface.bail}. */
1207
+ readonly bail: boolean;
1208
+ readonly tasks: TaskManagerInterface;
1209
+ /** Look up one live task by its `id`. */
1210
+ task(id: string): TaskInterface | undefined;
1211
+ /** The settled tasks' results, in positional order — the phase tier of the result tree. */
1212
+ results(): readonly TaskResult[];
1213
+ skip(): void;
1214
+ stop(): void;
1215
+ snapshot(): PhaseSnapshot;
1216
+ }
1217
+
1218
+ /**
1219
+ * The lean child manager (AGENTS §9) of a {@link import('../Workflow.js').Workflow}'s
1220
+ * live phases — an insertion-ordered registry keyed by phase `id`, the phase analogue
1221
+ * of {@link import('../tasks/TaskManager.js').TaskManager}.
1222
+ *
1223
+ * @remarks
1224
+ * - **Positional store.** Phases live in an insertion-ordered `Map` keyed by `id`;
1225
+ * `append` adds one at the end, `phase(id)` looks one up, `phases()` lists them in
1226
+ * positional order, `count` is the size. A snapshot RESTORE re-`append`s in the
1227
+ * snapshot's order, reproducing it exactly.
1228
+ * - **No batch matrix.** A workflow's phases are a fixed positional set, so AGENTS §9.2
1229
+ * is deliberately omitted.
1230
+ * - **Event-free.** A purely structural container — the live {@link PhaseInterface}s own
1231
+ * their own emitters.
1232
+ *
1233
+ * @example
1234
+ * ```ts
1235
+ * const phases = new PhaseManager()
1236
+ * phases.append(phase) // a live Phase
1237
+ * phases.phase(phase.id) // the same phase
1238
+ * phases.count // 1
1239
+ * ```
1240
+ */
1241
+ export declare class PhaseManager implements PhaseManagerInterface {
1242
+ #private;
1243
+ get count(): number;
1244
+ append(phase: PhaseInterface): void;
1245
+ phase(id: string): PhaseInterface | undefined;
1246
+ phases(): readonly PhaseInterface[];
1247
+ }
1248
+
1249
+ /**
1250
+ * The lean child manager (AGENTS §9) of a {@link WorkflowInterface}'s live phases —
1251
+ * positional accessors plus `count`, the phase analogue of {@link TaskManagerInterface}.
1252
+ *
1253
+ * @remarks
1254
+ * `append` adds one live {@link PhaseInterface} at the end; `phase(id)` looks one up;
1255
+ * `phases()` lists them in positional order; `count` is the tally. No batch matrix.
1256
+ */
1257
+ export declare interface PhaseManagerInterface {
1258
+ readonly count: number;
1259
+ append(phase: PhaseInterface): void;
1260
+ phase(id: string): PhaseInterface | undefined;
1261
+ phases(): readonly PhaseInterface[];
1262
+ }
1263
+
1264
+ /**
1265
+ * The runtime options for a {@link PhaseInterface} — the construction bag the live
1266
+ * derived phase state machine (W-b) carries.
1267
+ *
1268
+ * @remarks
1269
+ * The reserved `on` (AGENTS §8) wires initial {@link PhaseEventMap} listeners.
1270
+ * `tasks` keys per-task {@link TaskOptions} by task `id`, so {@link createWorkflow}
1271
+ * can thread a leaf's options (its `on` / `metadata`) down through the phase when it
1272
+ * builds the whole tree.
1273
+ */
1274
+ export declare interface PhaseOptions {
1275
+ readonly on?: PhaseHooks;
1276
+ /** The emitter's listener-error handler (AGENTS §13) — a listener throw routes here, not to a domain event. */
1277
+ readonly error?: EmitterErrorHandler;
1278
+ /** Per-task {@link TaskOptions}, keyed by the task's `id`. */
1279
+ readonly tasks?: Readonly<Record<string, TaskOptions>>;
1280
+ }
1281
+
1282
+ /**
1283
+ * The shape of a {@link import('./types.js').PhaseDefinition} — identity, its ordered
1284
+ * {@link taskShape} tasks, and an optional positive-integer `concurrency` throttle
1285
+ * (max tasks in flight; omitted ⇒ unbounded).
1286
+ */
1287
+ export declare const phaseShape: ObjectShape<{
1288
+ id: StringShape;
1289
+ name: StringShape;
1290
+ description: OptionalShape<StringShape>;
1291
+ tasks: ArrayShape<ObjectShape<{
1292
+ id: StringShape;
1293
+ name: StringShape;
1294
+ description: OptionalShape<StringShape>;
1295
+ run: UnionShape<[ ObjectShape<{
1296
+ via: LiteralShape<readonly ["function"]>;
1297
+ name: StringShape;
1298
+ }>, ObjectShape<{
1299
+ via: LiteralShape<readonly ["tool"]>;
1300
+ name: StringShape;
1301
+ }>, ObjectShape<{
1302
+ via: LiteralShape<readonly ["agent"]>;
1303
+ name: StringShape;
1304
+ }>]>;
1305
+ retries: OptionalShape<NumberShape>;
1306
+ timeout: OptionalShape<NumberShape>;
1307
+ }>>;
1308
+ concurrency: OptionalShape<NumberShape>;
1309
+ bail: OptionalShape<LiteralShape<readonly [true, false]>>;
1310
+ }>;
1311
+
1312
+ /**
1313
+ * A JSON-serializable snapshot of one phase's state — its identity, status, its forced
1314
+ * override (if any), and its nested task snapshots.
1315
+ *
1316
+ * @remarks
1317
+ * Pure JSON DATA. `status` is the EFFECTIVE status (override-or-derived) at snapshot time.
1318
+ * `override` is the forced status of a whole-phase `skip` / `stop` (AGENTS §10) — PRESENT only
1319
+ * when one is in force, so a restore reinstates it DIRECTLY (no fragile derivation comparison)
1320
+ * and a genuinely-derived phase carries none. A leaf {@link TaskSnapshot} needs no `override`
1321
+ * field — a task's terminal status IS its forced marker. `tasks` are the phase's
1322
+ * {@link TaskSnapshot}s in order.
1323
+ */
1324
+ export declare interface PhaseSnapshot {
1325
+ readonly id: string;
1326
+ readonly name: string;
1327
+ readonly description?: string;
1328
+ readonly status: PhaseStatus;
1329
+ /** The forced status of a whole-phase `skip` / `stop`; present only when an override is in force. */
1330
+ readonly override?: PhaseStatus;
1331
+ /**
1332
+ * The EFFECTIVE failure policy this phase ran under (`phase.bail ?? workflow.bail`, AGENTS §4.4)
1333
+ * — persisted (REQUIRED, like {@link WorkflowSnapshot.bail}) so a restore reinstates the same
1334
+ * per-phase policy identically without a silent default.
1335
+ */
1336
+ readonly bail: boolean;
1337
+ readonly tasks: readonly TaskSnapshot[];
1338
+ }
1339
+
1340
+ /**
1341
+ * The lifecycle status of a phase — the same vocabulary as {@link TaskStatus},
1342
+ * derived from its tasks' statuses.
1343
+ *
1344
+ * @remarks
1345
+ * A semantic tier of the shared {@link LifecycleStatus} vocabulary. A phase is
1346
+ * `failed` only when a task failed AND the workflow's `bail` policy is in force (a
1347
+ * failure under graceful mode is data, not a phase failure). `stopped` propagates
1348
+ * when every task was stopped. See {@link import('./helpers.js').derivePhaseStatus}.
1349
+ */
1350
+ export declare type PhaseStatus = LifecycleStatus;
1351
+
1352
+ /**
1353
+ * Rebuild an equivalent live W-b entity tree from a {@link WorkflowSnapshot} — the
1354
+ * inverse of {@link WorkflowInterface.snapshot}, restoring structure + each node's status
1355
+ * + recorded results + positional order + the persisted `#override`.
1356
+ *
1357
+ * @remarks
1358
+ * Round-trip fidelity is paramount: a `snapshot()` → `restoreWorkflow()` reproduces the
1359
+ * same status at every node (each `#override` restored DIRECTLY from the snapshot's own
1360
+ * `override` field, not guessed from a status divergence), the same recorded
1361
+ * {@link import('./types.js').TaskResult}s, and the same positional order (an interior
1362
+ * `skip` / `remove` survives). The snapshot is SELF-CONTAINED — it persists the `bail`
1363
+ * policy it ran under, so the restore re-derives status IDENTICALLY without a silent
1364
+ * default; the snapshot's `bail` is the source of truth, while an explicit `options.bail`
1365
+ * still wins when supplied (to deliberately re-run under a different policy). A structurally
1366
+ * invalid snapshot (a status — or override — outside the lifecycle vocabulary, or a
1367
+ * non-boolean `bail`) throws a `RESTORE` {@link WorkflowError}.
1368
+ *
1369
+ * @param snapshot - The snapshot to restore (carries its own `bail` + `override`)
1370
+ * @param options - Runtime options (initial listeners, an optional `bail` override, per-node options)
1371
+ * @returns The restored live {@link WorkflowInterface} root
1372
+ *
1373
+ * @example
1374
+ * ```ts
1375
+ * import { restoreWorkflow } from '@src/core'
1376
+ *
1377
+ * const restored = restoreWorkflow(workflow.snapshot()) // bail comes from the snapshot
1378
+ * restored.status === workflow.status // true
1379
+ * ```
1380
+ */
1381
+ export declare function restoreWorkflow(snapshot: WorkflowSnapshot, options?: WorkflowOptions): WorkflowInterface;
1382
+
1383
+ /**
1384
+ * A thin generic orchestrator that drives declared units — and any they `spawn` —
1385
+ * through a bounded-concurrency {@link createQueue}, collecting ordered results.
1386
+ *
1387
+ * @remarks
1388
+ * - **Drives the Queue (no reimplemented concurrency).** Every unit (declared or
1389
+ * spawned) is `enqueue`d on one internal `Queue`, so backpressure, FIFO ordering,
1390
+ * bounded concurrency, retries, and the per-attempt timeout are all the Queue's —
1391
+ * the Runner adds only orchestration (launching, ordering, draining, fail-fast).
1392
+ * - **Spawns actually run, results stay ordered (the B2 fix).** Declared inputs and
1393
+ * `spawn`ed siblings flow through the SAME `#launch`, which appends the unit's `id`
1394
+ * to an ordered `#order` list and records its settled value into `#values` by `id`.
1395
+ * Results are read back as `#order.map(id => #values.get(id))` — declared first (in
1396
+ * input order), then spawns (in spawn order). There is no one-time task snapshot,
1397
+ * so a unit spawned mid-handler is run and ordered like any other.
1398
+ * - **`execute` awaits the full spawn closure via a count gate.** `#launch` increments
1399
+ * an outstanding-unit `#count` BEFORE enqueuing and every settle decrements it,
1400
+ * resolving the `#drained` deferred at zero. Because `spawn` calls `#launch` (so
1401
+ * `#count += 1`) before the parent handler returns, the count never reaches zero
1402
+ * mid-run — `execute` parks on `#drained` and so awaits the entire transitive
1403
+ * closure, not just the declared units.
1404
+ * - **`spawn` is fire-and-track.** A spawned unit runs through the queue regardless of
1405
+ * whether its promise is awaited; the Runner never awaits a spawned promise from
1406
+ * within a handler's slot (it awaits the count gate instead), so a slot-holding
1407
+ * handler can fan out without the Runner deadlocking it. (An inline `await` of a
1408
+ * spawn by a bounded handler can still deadlock — that caveat is the caller's.)
1409
+ * - **Per-unit Controller + signal.** Each unit gets a `Controller` carrying its `id`,
1410
+ * `input`, the unit's `Abort` (so `aborted` / `abort` delegate to it), and the queue
1411
+ * attempt's `signal` (which ANY-combines the unit abort + runner abort + timeout). A
1412
+ * `spawn` callback is injected so `controller.spawn(input)` delegates to `#launch`.
1413
+ * - **One-shot + fail-fast.** `execute` runs once (a second call throws). The first
1414
+ * unit failure (after its retries) records the error and `abort()`s the run, so every
1415
+ * sibling's signal fires; later failures are ignored and `execute` rejects with the
1416
+ * first error. A user `abort(reason)` likewise rejects a running `execute`.
1417
+ * - **Observable (§13).** The owned {@link emitter} ({@link RunnerEventMap}) carries the run
1418
+ * lifecycle — `start` / `unit` / `spawn` / `settle` / `fail` / `finish` / `abort` — for
1419
+ * fire-and-forget observers. Every event is emitted directly, strictly AFTER the relevant
1420
+ * launch / settle / drain transition; the emitter isolates a listener throw and routes it
1421
+ * to its `error` handler (the `error` option), so a buggy observer can NEVER reorder, throw
1422
+ * into, or corrupt the one-shot / fail-fast / spawn-tracking engine: the outstanding-unit
1423
+ * count gate stays balanced and fail-fast still fires regardless of what a listener does.
1424
+ * Observation is purely a side-channel.
1425
+ */
1426
+ export declare class Runner<TInput, TResult> implements RunnerInterface<TInput, TResult> {
1427
+ #private;
1428
+ constructor(options: RunnerOptions<TInput, TResult>);
1429
+ get emitter(): EmitterInterface<RunnerEventMap<TResult>>;
1430
+ get active(): number;
1431
+ get stopped(): boolean;
1432
+ execute(inputs: readonly TInput[]): Promise<readonly TResult[]>;
1433
+ abort(reason?: unknown): void;
1434
+ destroy(): void;
1435
+ }
1436
+
1437
+ /**
1438
+ * The per-entry reliability OVERRIDES for one unit — its extra attempts on failure and its
1439
+ * per-attempt deadline, resolved from the unit's input via {@link RunnerOptions.entries}.
1440
+ *
1441
+ * @remarks
1442
+ * The unit's `id` and `signal` stay Runner-managed (it mints the id and owns the per-unit
1443
+ * abort), so only the two reliability knobs are exposed here. Each field OVERRIDES the
1444
+ * runner-level `retries` / `timeout` default for that one unit; an omitted field falls back
1445
+ * to the default. This is the per-unit slice of the backing Queue's
1446
+ * `@orkestrel/queue` `QueueEntryOptions` surfaced cleanly — the Queue already
1447
+ * resolves default→override.
1448
+ */
1449
+ export declare interface RunnerEntryOptions {
1450
+ readonly retries?: number;
1451
+ readonly timeout?: number;
1452
+ }
1453
+
1454
+ /**
1455
+ * The push observation surface of a {@link RunnerInterface} (AGENTS §13) — the run
1456
+ * lifecycle a fire-and-forget observer (logging, metrics, tracing) subscribes to,
1457
+ * ALONGSIDE the eventual `execute` result.
1458
+ *
1459
+ * @typeParam TResult - The value a unit resolves; the `finish` payload is the run's ordered
1460
+ * `readonly TResult[]`, so the map is `RunnerEventMap<TResult>` — mirroring how the
1461
+ * {@link RunnerInterface} is generic.
1462
+ *
1463
+ * @remarks
1464
+ * Listener isolation is the emitter's (AGENTS §13): every event is emitted directly and a
1465
+ * listener throw is routed to the emitter's OWN `error` handler (the `error` option), never
1466
+ * onto this domain map and never into the one-shot / fail-fast / spawn-tracking engine — so a
1467
+ * buggy observer can never reorder, throw into, or corrupt the run. Every emit sits AFTER the
1468
+ * relevant unit-launch / settle / drain transition, so a throwing observer cannot unbalance
1469
+ * the outstanding-unit count gate or break fail-fast. Subscribe via `runner.emitter.on(...)`.
1470
+ *
1471
+ * Declared as a `type` alias (not `interface extends EventMap`, §4.5 — `EventMap` is a
1472
+ * `type` kind): a type-literal satisfies the `EventMap` constraint
1473
+ * (`Record<string, readonly unknown[]>`) structurally, whereas an interface lacks the
1474
+ * required index signature.
1475
+ */
1476
+ export declare type RunnerEventMap<TResult> = {
1477
+ /** `execute` began — emitted once at the top of a non-empty run. */
1478
+ readonly start: readonly [];
1479
+ /** A unit's handler began running — the unit's id (declared or spawned). */
1480
+ readonly unit: readonly [id: string];
1481
+ /** A sub-unit was spawned — its id + the spawning parent's id (when known). */
1482
+ readonly spawn: readonly [id: string, parent: string | undefined];
1483
+ /** A unit completed successfully — its id (after its outcome was recorded). */
1484
+ readonly settle: readonly [id: string];
1485
+ /** A unit failed — its id + the error (always `unknown`). */
1486
+ readonly fail: readonly [id: string, error: unknown];
1487
+ /** The batch settled — the run's ordered results (the same array `execute` resolves). */
1488
+ readonly finish: readonly [results: readonly TResult[]];
1489
+ /** The run was aborted (fail-fast, a user `abort`, or `destroy`) — the cancel reason. */
1490
+ readonly abort: readonly [reason: unknown];
1491
+ };
1492
+
1493
+ /**
1494
+ * Runs one unit's work, given its {@link ControllerInterface}.
1495
+ *
1496
+ * @typeParam TInput - The unit's work input
1497
+ * @typeParam TResult - The value the handler resolves for a unit
1498
+ */
1499
+ export declare type RunnerHandler<TInput, TResult> = (controller: ControllerInterface<TInput, TResult>) => Promise<TResult> | TResult;
1500
+
1501
+ /**
1502
+ * A thin generic orchestrator that drives declared units — plus any they `spawn` —
1503
+ * through a bounded-concurrency queue, collecting their results in order.
1504
+ *
1505
+ * @remarks
1506
+ * One-shot: `execute` runs the unit set once and resolves their results. A `Runner`
1507
+ * does not reimplement concurrency or retries — it composes the workers `Queue`
1508
+ * (the backpressure + retry + timeout engine), routing every unit (declared and
1509
+ * spawned) through it so spawned work actually runs.
1510
+ *
1511
+ * Exposes a typed {@link emitter} (AGENTS §13) carrying its run lifecycle moments
1512
+ * ({@link RunnerEventMap}) for fire-and-forget observers, ALONGSIDE the eventual `execute`
1513
+ * result. Emitting is observation-only — every event fires AFTER the relevant unit-launch /
1514
+ * settle / drain transition, so a buggy observer can never reorder or corrupt the one-shot /
1515
+ * fail-fast / spawn-tracking engine: the emitter isolates a listener throw and routes it to
1516
+ * its `error` handler (the `error` option), never the run. Subscribe via
1517
+ * `runner.emitter.on(...)`.
1518
+ *
1519
+ * @typeParam TInput - The unit's work input
1520
+ * @typeParam TResult - The value a unit resolves
1521
+ */
1522
+ export declare interface RunnerInterface<TInput, TResult> {
1523
+ readonly emitter: EmitterInterface<RunnerEventMap<TResult>>;
1524
+ readonly active: number;
1525
+ readonly stopped: boolean;
1526
+ /**
1527
+ * Run all `inputs` — and anything they `spawn` — to completion; resolve their
1528
+ * results in order: the declared inputs first (in input order), then the spawned
1529
+ * units (in spawn order).
1530
+ *
1531
+ * @remarks
1532
+ * One-shot — a second call throws. **Fail-fast** — the first unit failure (after
1533
+ * its retries) aborts every other in-flight + pending unit and rejects the run
1534
+ * with that error; later failures are ignored. An empty `inputs` resolves to `[]`.
1535
+ *
1536
+ * @param inputs - The declared units to run
1537
+ * @returns The units' results, in order (declared first, then spawns)
1538
+ */
1539
+ execute(inputs: readonly TInput[]): Promise<readonly TResult[]>;
1540
+ /**
1541
+ * Cancel every in-flight + pending unit (and the backing queue), making a running
1542
+ * `execute` reject.
1543
+ *
1544
+ * @param reason - An optional cancellation reason propagated to every unit's signal
1545
+ */
1546
+ abort(reason?: unknown): void;
1547
+ /** Tear the runner down — `abort` plus stop the backing queue; idempotent. */
1548
+ destroy(): void;
1549
+ }
1550
+
1551
+ /**
1552
+ * Options for `createRunner`.
1553
+ *
1554
+ * @remarks
1555
+ * - `handler` — runs each unit's work against its {@link ControllerInterface};
1556
+ * rejecting fails the unit (and, after retries are exhausted, fails the run).
1557
+ * - `concurrency` — the maximum units in flight at once; defaults to `1` (ordered,
1558
+ * one-at-a-time). Floored at `1`.
1559
+ * - `retries` — the default extra attempts per unit on failure (or a per-attempt
1560
+ * timeout); defaults to `0`.
1561
+ * - `timeout` — the per-attempt deadline in milliseconds; defaults to none (a
1562
+ * non-positive value means no deadline).
1563
+ * - `entries` — per-entry `retries` / `timeout` overrides, resolved from each
1564
+ * input; falls back to the runner-level `retries` / `timeout` defaults.
1565
+ * - `on` — the reserved {@link EmitterHooks} key (§8): initial listeners for the runner's
1566
+ * {@link RunnerEventMap}, wired at construction (e.g. `{ finish: (r) => log(r) }`).
1567
+ */
1568
+ export declare interface RunnerOptions<TInput, TResult> {
1569
+ readonly on?: EmitterHooks<RunnerEventMap<TResult>>;
1570
+ /** The emitter's listener-error handler (AGENTS §13) — a listener throw routes here, not to a domain event. */
1571
+ readonly error?: EmitterErrorHandler;
1572
+ readonly handler: RunnerHandler<TInput, TResult>;
1573
+ readonly concurrency?: number;
1574
+ readonly retries?: number;
1575
+ readonly timeout?: number;
1576
+ /** Per-entry `retries` / `timeout` overrides, resolved from each input; falls back to the runner-level defaults. */
1577
+ readonly entries?: (input: TInput) => RunnerEntryOptions;
1578
+ }
1579
+
1580
+ /**
1581
+ * One unit the {@link RunnerInterface} is tracking: the queue payload it was enqueued
1582
+ * with — its `id` (a random UUID) keys it in the runner's ordered launch list and value
1583
+ * map, and `input` is the unit's work payload handed to the handler's `Controller`.
1584
+ *
1585
+ * @remarks
1586
+ * The runner's internal bookkeeping shape, published through the barrel because §5
1587
+ * centralizes every file-local type — declared or spawned, every unit flows through the
1588
+ * one queue as a `RunnerUnit`, so backpressure / ordering / retries / timeout stay the
1589
+ * Queue's behavior and the runner adds only orchestration.
1590
+ *
1591
+ * @typeParam TInput - The unit's work input
1592
+ */
1593
+ export declare interface RunnerUnit<TInput> {
1594
+ readonly id: string;
1595
+ readonly input: TInput;
1596
+ }
1597
+
1598
+ /**
1599
+ * The safe cross-environment cooperative-yield default — a {@link SchedulerInterface}
1600
+ * built on `setTimeout` / `clearTimeout` alone, so it runs unchanged in both the
1601
+ * browser and Node.
1602
+ *
1603
+ * @remarks
1604
+ * - **Cross-environment.** Uses ONLY `setTimeout` / `clearTimeout` — universally
1605
+ * available. It deliberately avoids env-specific fast paths (`setImmediate`,
1606
+ * `scheduler.yield`, `requestAnimationFrame`, `node:timers/promises`,
1607
+ * `MessageChannel`); those belong to the environment backends, built with the
1608
+ * agent loop that consumes them.
1609
+ * - **`yield` is a macrotask host-turn, not a microtask.** `yield()` waits on a
1610
+ * `setTimeout(0)`, NOT `queueMicrotask`. A microtask drains before the host
1611
+ * regains control, so it would not actually let pending I/O, timers, or
1612
+ * rendering run — it only defers within the current task. A zero-delay timer is
1613
+ * the correct cross-environment "give the host a turn".
1614
+ * - **Abort-aware.** A pending `yield` / `delay` rejects with `signal.reason` when
1615
+ * the signal aborts (the standard `AbortSignal` convention). An already-aborted
1616
+ * signal rejects immediately without arming a timer. Either settle path clears
1617
+ * the timer and removes the abort listener — no leaked timer, no leaked
1618
+ * listener, and no double-settle.
1619
+ * - **Priority is accepted but uniform.** `options.priority` is part of the
1620
+ * contract, but a `setTimeout`-based default cannot act on urgency, so it treats
1621
+ * every priority the same. Environment backends honour it.
1622
+ * - **Event-free.** A pure functional primitive — no Emitter, no events.
1623
+ *
1624
+ * @example
1625
+ * ```ts
1626
+ * const scheduler = new Scheduler()
1627
+ * while (!signal.aborted) {
1628
+ * doSomeWork()
1629
+ * await scheduler.yield({ signal }) // let the host run between work units
1630
+ * }
1631
+ * ```
1632
+ */
1633
+ export declare class Scheduler implements SchedulerInterface {
1634
+ #private;
1635
+ /**
1636
+ * Yield control back to the host so other tasks (I/O, timers, rendering) can
1637
+ * run, then resume — a macrotask turn via `setTimeout(0)` (NOT a microtask,
1638
+ * which would resume before the host regains control).
1639
+ */
1640
+ yield(options?: SchedulerOptions): Promise<void>;
1641
+ /**
1642
+ * Resume after at least `ms` milliseconds; abort rejects with `signal.reason`.
1643
+ *
1644
+ * @remarks
1645
+ * `ms` should be a non-negative finite number. The primitive stays minimal and
1646
+ * does no validation: it passes `ms` straight to the host `setTimeout`, which
1647
+ * clamps a negative value or `NaN` to ~0 — so an out-of-domain `ms` resolves on
1648
+ * the next host turn rather than throwing.
1649
+ */
1650
+ delay(ms: number, options?: SchedulerOptions): Promise<void>;
1651
+ }
1652
+
1653
+ /**
1654
+ * A cooperative host-yield primitive: a loop decides WHAT to do; the scheduler
1655
+ * decides WHEN the host regains control. Abort-aware — a pending yield/delay
1656
+ * rejects with the signal's reason when aborted.
1657
+ */
1658
+ export declare interface SchedulerInterface {
1659
+ /**
1660
+ * Yield control back to the host so other tasks (I/O, timers, rendering) can
1661
+ * run, then resume.
1662
+ */
1663
+ yield(options?: SchedulerOptions): Promise<void>;
1664
+ /** Resume after at least `ms` milliseconds. */
1665
+ delay(ms: number, options?: SchedulerOptions): Promise<void>;
1666
+ }
1667
+
1668
+ /** Options for a single cooperative yield/delay. */
1669
+ export declare interface SchedulerOptions {
1670
+ /**
1671
+ * A relative urgency hint. Honoured by environment backends; the
1672
+ * cross-environment default treats all priorities the same.
1673
+ */
1674
+ readonly priority?: SchedulerPriority;
1675
+ /** A signal whose abort rejects a pending yield/delay with its `reason`. */
1676
+ readonly signal?: AbortSignal;
1677
+ }
1678
+
1679
+ /**
1680
+ * Relative urgency hint for cooperative scheduling. Honoured by environment
1681
+ * backends; the cross-environment default treats all priorities uniformly.
1682
+ */
1683
+ export declare type SchedulerPriority = 'user' | 'normal' | 'background';
1684
+
1685
+ /**
1686
+ * The shape of ONE flat step — `{ name, via? }` — the building block of
1687
+ * {@link workflowStepsShape}.
1688
+ *
1689
+ * @remarks
1690
+ * `name` is the REGISTERED behavior name the step runs (it becomes the task's `run.name`);
1691
+ * `via` is the optional execution mechanism (defaults to `'function'` when omitted). The
1692
+ * tool expands each step into a one-task phase, in order
1693
+ * ({@link import('./helpers.js').expandSteps}).
1694
+ */
1695
+ export declare const stepShape: ObjectShape<{
1696
+ name: StringShape;
1697
+ via: OptionalShape<LiteralShape<readonly ["function", "tool", "agent"]>>;
1698
+ }>;
1699
+
1700
+ /**
1701
+ * Convert one flat {@link WorkflowStep} into a {@link TaskForm} — `name` → the form's `name`,
1702
+ * `via` → the form's discriminant (defaulting to `'function'`).
1703
+ *
1704
+ * @param step - The flat step
1705
+ * @returns The {@link TaskForm} the step's task runs
1706
+ */
1707
+ export declare function stepToForm(step: WorkflowStep): TaskForm;
1708
+
1709
+ /**
1710
+ * The live leaf state machine (W-b) for one task — an observable (AGENTS §13), guarded
1711
+ * synchronous task whose explicit {@link TaskStatus} advances through the AGENTS §10
1712
+ * transitions, recording a {@link TaskResult} on a terminal outcome.
1713
+ *
1714
+ * @remarks
1715
+ * - **Guarded transitions (AGENTS §10).** `start` (→ `running`), then `complete(value)`
1716
+ * (→ `completed`, records a {@link import('@orkestrel/contract').Success}), `fail(error)`
1717
+ * (→ `failed`, records a {@link import('@orkestrel/contract').Failure}), `skip` (→ `skipped`),
1718
+ * `stop` (→ `stopped`). Each consults {@link canTransitionTask} FIRST and throws a
1719
+ * `TRANSITION` {@link WorkflowError} on an illegal move (e.g. completing a non-`running`
1720
+ * task) — the legal graph is the single source of truth, so the leaf can never reach an
1721
+ * impossible state.
1722
+ * - **Override (snapshot fidelity).** `skip` / `stop` set `#override` to the forced terminal
1723
+ * status, so a RESTORE can tell a forced leaf (`skipped` / `stopped`) from a run-produced
1724
+ * one and reinstate it AS an override — preserving the round-trip.
1725
+ * - **The cascade.** Every status change records its boxed result (when any), fires the leaf's
1726
+ * OWN event, THEN calls the parent phase's `#recompute` (injected at construction) so the
1727
+ * transition propagates UP (Task → Phase → Workflow re-derive). The own-event-before-cascade
1728
+ * order means an observer sees the CAUSE (this leaf changed) before the EFFECT (the parents
1729
+ * re-derive) — the project precedent (`Runner.#settle` emits its own `fail` before propagating).
1730
+ * - **Observable (AGENTS §13).** The owned {@link emitter} ({@link TaskEventMap}) fires the
1731
+ * matching event strictly AFTER the state change, BEFORE the cascade; the emitter isolates
1732
+ * a listener throw and routes it to its `error` handler (the `error` option), so a buggy
1733
+ * observer can never corrupt a transition.
1734
+ */
1735
+ export declare class Task implements TaskInterface {
1736
+ #private;
1737
+ constructor(context: TaskContext, phase: PhaseInterface, workflow: WorkflowInterface, recompute: () => void, options?: TaskOptions, status?: TaskStatus, result?: TaskResult);
1738
+ get emitter(): EmitterInterface<TaskEventMap>;
1739
+ get id(): string;
1740
+ get name(): string;
1741
+ get description(): string | undefined;
1742
+ get context(): TaskContext;
1743
+ get phase(): PhaseInterface;
1744
+ get workflow(): WorkflowInterface;
1745
+ get status(): TaskStatus;
1746
+ get result(): TaskResult | undefined;
1747
+ start(): void;
1748
+ complete(value: unknown): void;
1749
+ fail(error: unknown): void;
1750
+ skip(): void;
1751
+ stop(): void;
1752
+ snapshot(): TaskSnapshot;
1753
+ }
1754
+
1755
+ /**
1756
+ * Every {@link TaskStatus} value, frozen — the lifecycle vocabulary of a task.
1757
+ *
1758
+ * @remarks
1759
+ * Ordered pending → running → terminal (`completed` / `failed` / `skipped` /
1760
+ * `stopped`). The source of truth for the union; compose guards / shapes from it.
1761
+ */
1762
+ export declare const TASK_STATUSES: readonly TaskStatus[];
1763
+
1764
+ /**
1765
+ * The legal {@link TaskStatus} transition graph of the live W-b task state machine —
1766
+ * each current status mapped to the statuses it may move to directly, frozen.
1767
+ *
1768
+ * @remarks
1769
+ * The source of truth behind {@link import('./helpers.js').canTransitionTask} and the
1770
+ * `TRANSITION` guard ({@link import('./errors.js').WorkflowError}). A `pending` task may
1771
+ * `start` (→ `running`), `skip` (→ `skipped`), or `stop` (→ `stopped`); a `running` task
1772
+ * may `complete` (→ `completed`), `fail` (→ `failed`), `skip` (→ `skipped`), or `stop`
1773
+ * (→ `stopped`). Every terminal status maps to an empty list — a settled task never
1774
+ * transitions again. So completing a non-`running` task, or starting a settled one, is
1775
+ * rejected.
1776
+ */
1777
+ export declare const TASK_TRANSITIONS: Readonly<Record<TaskStatus, readonly TaskStatus[]>>;
1778
+
1779
+ /**
1780
+ * The three task-form mechanisms (the {@link TaskVia} discriminant), frozen.
1781
+ *
1782
+ * @remarks
1783
+ * The runtime source of truth for the `via` axis — drive the contract's literal
1784
+ * shape and any guard from this array rather than repeating the literals.
1785
+ */
1786
+ export declare const TASK_VIAS: readonly TaskVia[];
1787
+
1788
+ /**
1789
+ * The ambient context of a task — its own identity plus a back-reference to the
1790
+ * phase (and, transitively, the workflow) it belongs to.
1791
+ *
1792
+ * @remarks
1793
+ * Extends {@link WorkflowContext} and adds `phase`, the parent {@link PhaseContext}
1794
+ * — so a task carries its FULL lineage (workflow → phase → task) for a
1795
+ * {@link TaskResult} or a runner.
1796
+ */
1797
+ export declare interface TaskContext extends WorkflowContext {
1798
+ readonly phase: PhaseContext;
1799
+ }
1800
+
1801
+ /**
1802
+ * The lean per-task handle a {@link import('./types.js').WorkflowFunction} receives — the
1803
+ * running task's folded cancellation, its input, its lineage, and read-UP access to the
1804
+ * result tree.
1805
+ *
1806
+ * @remarks
1807
+ * - **A leaf handle, NOT the runner `Controller`.** A workflow task is a leaf of the
1808
+ * declarative W-b tree, not a fan-out unit, so this carries none of the runner
1809
+ * `Controller`'s `spawn` / `wait` — only what a leaf needs.
1810
+ * - **Folded signal.** `signal` is the cancellation the runner folds for THIS run: it fires
1811
+ * on a workflow-level abort / timeout / budget ceiling, or — under `bail: true` — when a
1812
+ * sibling task fails (the runner aborts the in-flight siblings via the substrate's
1813
+ * fail-fast). A handler races its work against it; `aborted` reads it.
1814
+ * - **Input + lineage.** `input` is the task's open `metadata` bag (its
1815
+ * {@link import('./types.js').TaskInput} payload, `{}` when none); `task` is the full
1816
+ * {@link TaskContext}, so `task.phase` / `task.phase.workflow` navigate UP the lineage.
1817
+ * - **Read-up results.** `results()` returns every settled task's {@link TaskResult} across
1818
+ * the phases that have already finished (a closure over the live
1819
+ * {@link import('./types.js').WorkflowInterface}), so a `function` task can read an earlier
1820
+ * phase's output. Read-only — a task records its OWN outcome by returning / throwing, not
1821
+ * by mutating the tree.
1822
+ * - **Event-free.** Like the runner `Controller`, the per-task handle carries no Emitter;
1823
+ * observe the W-b entities' own emitters (`task.emitter` / `phase.emitter`) instead.
1824
+ */
1825
+ export declare class TaskController implements TaskControllerInterface {
1826
+ #private;
1827
+ readonly signal: AbortSignal;
1828
+ readonly input: Readonly<Record<string, unknown>>;
1829
+ readonly task: TaskContext;
1830
+ constructor(signal: AbortSignal, input: Readonly<Record<string, unknown>>, task: TaskContext, results: () => readonly TaskResult[]);
1831
+ get aborted(): boolean;
1832
+ results(): readonly TaskResult[];
1833
+ }
1834
+
1835
+ /**
1836
+ * The per-task handle a {@link WorkflowFunction} receives — the running task's
1837
+ * cancellation, its input, its lineage, and read-UP access to the result tree.
1838
+ *
1839
+ * @remarks
1840
+ * A NEW, lean handle (NOT the runner `Controller` — it carries no `spawn` / `wait`; a
1841
+ * workflow task is a leaf of the declarative tree, not a fan-out unit). It exposes:
1842
+ * - `signal` — the task's folded cancellation: fires on a workflow-level `abort` /
1843
+ * `timeout` / `budget` ceiling, or — under `bail: true` — when a sibling task fails (the
1844
+ * runner aborts the in-flight siblings). A handler races its work against it.
1845
+ * - `aborted` — whether `signal` has fired.
1846
+ * - `input` — the task's `metadata` bag (the open consumer payload from its
1847
+ * {@link TaskInput}); `{}` when none.
1848
+ * - `task` — the task's full {@link TaskContext} (so `task.phase` / `task.phase.workflow`
1849
+ * navigate UP the lineage).
1850
+ * - `results()` — every settled task's {@link TaskResult} across already-finished phases,
1851
+ * so a `function` task can read an earlier phase's output (the W-b result tree, read-only).
1852
+ */
1853
+ export declare interface TaskControllerInterface {
1854
+ /** Fires on a workflow-level abort / timeout / budget, or a sibling failure under `bail: true`. */
1855
+ readonly signal: AbortSignal;
1856
+ readonly aborted: boolean;
1857
+ /** The task's open `metadata` bag (its {@link TaskInput} payload); `{}` when none. */
1858
+ readonly input: Readonly<Record<string, unknown>>;
1859
+ readonly task: TaskContext;
1860
+ /** Every settled task's result across already-finished phases — the result tree, read-only. */
1861
+ results(): readonly TaskResult[];
1862
+ }
1863
+
1864
+ /**
1865
+ * The serializable definition of one task — its identity plus the behavior it runs
1866
+ * (a {@link TaskForm}, referenced by name).
1867
+ *
1868
+ * @remarks
1869
+ * Pure JSON DATA: a UI or an LLM authors it, it round-trips through the contract
1870
+ * (factories.ts), and it carries NO functions. `id` is the positional identity
1871
+ * within its phase; `name` is the human label; `description` is optional prose;
1872
+ * `run` is the {@link TaskForm} naming the registered behavior.
1873
+ */
1874
+ export declare interface TaskDefinition {
1875
+ readonly id: string;
1876
+ readonly name: string;
1877
+ readonly description?: string;
1878
+ readonly run: TaskForm;
1879
+ /**
1880
+ * @remarks
1881
+ * Extra attempts after the first on failure (a non-negative integer); the runner threads it
1882
+ * to this task's substrate unit, OVERRIDING the phase Runner's `retries` default. Omitted ⇒
1883
+ * the default (no extra attempts). Execution-only: it is NOT persisted in a snapshot.
1884
+ */
1885
+ readonly retries?: number;
1886
+ /**
1887
+ * @remarks
1888
+ * The per-attempt deadline in milliseconds (a non-negative integer); the runner threads it to
1889
+ * this task's substrate unit, OVERRIDING the phase Runner's `timeout` default. Omitted (or a
1890
+ * non-positive value) ⇒ no deadline. Execution-only: it is NOT persisted in a snapshot.
1891
+ */
1892
+ readonly timeout?: number;
1893
+ }
1894
+
1895
+ /**
1896
+ * Convert one {@link import('./types.js').TaskDefinition} into an initial, `pending`
1897
+ * {@link TaskSnapshot} — the per-task leaf step of {@link definitionToSnapshot} (no
1898
+ * result yet, empty metadata).
1899
+ *
1900
+ * @param task - The task definition to seed from
1901
+ * @returns An initial {@link TaskSnapshot}
1902
+ */
1903
+ export declare function taskDefinitionToSnapshot(task: WorkflowDefinition['phases'][number]['tasks'][number]): TaskSnapshot;
1904
+
1905
+ /**
1906
+ * A draft task — a {@link TaskDefinition} with OPTIONAL `id` / `name`.
1907
+ *
1908
+ * @remarks
1909
+ * The tool synthesizes a missing `id` positionally and defaults a missing `name` to
1910
+ * its `id` ({@link import('./helpers.js').completeDraft}). A PROVIDED `id` / `name` is
1911
+ * preserved verbatim (and must be non-empty — the draft contract's `minLength: 1`).
1912
+ */
1913
+ export declare interface TaskDraft {
1914
+ readonly id?: string;
1915
+ readonly name?: string;
1916
+ readonly description?: string;
1917
+ readonly run: TaskForm;
1918
+ /** Extra attempts after the first on failure (a non-negative integer); overrides the phase Runner default. Execution-only. */
1919
+ readonly retries?: number;
1920
+ /** The per-attempt deadline in milliseconds (a non-negative integer); overrides the phase Runner default. Execution-only. */
1921
+ readonly timeout?: number;
1922
+ }
1923
+
1924
+ /**
1925
+ * The shape of a TASK in a draft workflow — identical to {@link taskShape} EXCEPT `id`
1926
+ * and `name` are OPTIONAL (the tool synthesizes any missing one positionally).
1927
+ *
1928
+ * @remarks
1929
+ * A PROVIDED `id` / `name` still carries `minLength: 1`, so an explicitly-empty `id: ''`
1930
+ * is INVALID (rejected by the draft contract), never auto-filled — keeping "garbage"
1931
+ * distinct from "omitted". `run` stays required.
1932
+ */
1933
+ export declare const taskDraftShape: ObjectShape<{
1934
+ id: OptionalShape<StringShape>;
1935
+ name: OptionalShape<StringShape>;
1936
+ description: OptionalShape<StringShape>;
1937
+ run: UnionShape<[ ObjectShape<{
1938
+ via: LiteralShape<readonly ["function"]>;
1939
+ name: StringShape;
1940
+ }>, ObjectShape<{
1941
+ via: LiteralShape<readonly ["tool"]>;
1942
+ name: StringShape;
1943
+ }>, ObjectShape<{
1944
+ via: LiteralShape<readonly ["agent"]>;
1945
+ name: StringShape;
1946
+ }>]>;
1947
+ retries: OptionalShape<NumberShape>;
1948
+ timeout: OptionalShape<NumberShape>;
1949
+ }>;
1950
+
1951
+ /**
1952
+ * The push observation surface (AGENTS §13) of the task entity (W-b) — the
1953
+ * lifecycle moments of one task.
1954
+ *
1955
+ * @remarks
1956
+ * `start` fires when the task begins; `complete` when it finishes successfully
1957
+ * (carrying its {@link TaskResult}); `fail` when it errors (carrying the result);
1958
+ * `skip` when it is intentionally not executed; `stop` when it is ended early. A
1959
+ * throwing listener is isolated by the emitter and routed to its `error` handler,
1960
+ * not the domain surface (AGENTS §13). A `type` alias (AGENTS §4.5) so it satisfies
1961
+ * `EventMap`.
1962
+ */
1963
+ export declare type TaskEventMap = {
1964
+ /** The task began — its `id`. */
1965
+ readonly start: readonly [id: string];
1966
+ /** The task finished successfully — its result. */
1967
+ readonly complete: readonly [result: TaskResult];
1968
+ /** The task failed — its result. */
1969
+ readonly fail: readonly [result: TaskResult];
1970
+ /** The task was intentionally skipped. */
1971
+ readonly skip: readonly [];
1972
+ /** The task was permanently stopped. */
1973
+ readonly stop: readonly [];
1974
+ };
1975
+
1976
+ /**
1977
+ * A {@link TaskDefinition}'s behavior reference — a descriptive tagged union over
1978
+ * the three execution forms a task can take, discriminated by `via` (the axis is
1979
+ * the execution MECHANISM, never a bare `kind`; AGENTS §4.4). Each form references
1980
+ * its behavior BY NAME through a registry (the runner resolves the name at W-b);
1981
+ * a definition NEVER inlines a function, so the whole tree stays JSON-serializable.
1982
+ *
1983
+ * @remarks
1984
+ * - `function` — a registered function the runner invokes directly.
1985
+ * - `tool` — a registered {@link ToolInterface} the
1986
+ * runner executes as a tool call.
1987
+ * - `agent` — a registered agent (a subagent). It will later carry a depth/cycle
1988
+ * guard (W-c, bounded by {@link import('./constants.js').MAX_WORKFLOW_DEPTH}); in
1989
+ * W-a it is purely the typed reference.
1990
+ *
1991
+ * `name` is the registry key (it identifies the behavior the form runs). A
1992
+ * descriptive `via` literal (not `kind`) names the axis that varies, and the
1993
+ * `is*` guards narrow on `run.via` cleanly.
1994
+ */
1995
+ export declare type TaskForm = {
1996
+ readonly via: 'function';
1997
+ readonly name: string;
1998
+ } | {
1999
+ readonly via: 'tool';
2000
+ readonly name: string;
2001
+ } | {
2002
+ readonly via: 'agent';
2003
+ readonly name: string;
2004
+ };
2005
+
2006
+ /**
2007
+ * The shape of a {@link import('./types.js').TaskForm} — a descriptive tagged union
2008
+ * over the three execution mechanisms, discriminated by the `via` literal (never a
2009
+ * bare `kind`; AGENTS §4.4). Each variant pairs the `via` discriminant with a `name`
2010
+ * (the registry key for the behavior).
2011
+ *
2012
+ * @remarks
2013
+ * The union and each `via` literal + `name` carry a `description` so the emitted JSON
2014
+ * Schema spells out what the discriminant means and that `name` is a REGISTERED key
2015
+ * (not a human label) — the field-level guidance a small model needs to fill `run`.
2016
+ */
2017
+ export declare const taskFormShape: UnionShape<[ ObjectShape<{
2018
+ via: LiteralShape<readonly ["function"]>;
2019
+ name: StringShape;
2020
+ }>, ObjectShape<{
2021
+ via: LiteralShape<readonly ["tool"]>;
2022
+ name: StringShape;
2023
+ }>, ObjectShape<{
2024
+ via: LiteralShape<readonly ["agent"]>;
2025
+ name: StringShape;
2026
+ }>]>;
2027
+
2028
+ /** Initial {@link TaskEventMap} listeners — the reserved `on` option (AGENTS §8). */
2029
+ export declare type TaskHooks = EmitterHooks<TaskEventMap>;
2030
+
2031
+ /**
2032
+ * The minimal data to create a task context — a partial {@link TaskContext} plus
2033
+ * any creation-only fields.
2034
+ *
2035
+ * @remarks
2036
+ * `metadata` is an open consumer bag the workflow system stores and carries into a
2037
+ * {@link TaskSnapshot} but never interprets. All members are optional (the storing
2038
+ * layer fills identity / lineage).
2039
+ */
2040
+ export declare interface TaskInput extends Partial<TaskContext> {
2041
+ /** An open consumer bag — stored and snapshotted, never interpreted by the workflow. */
2042
+ readonly metadata?: Readonly<Record<string, unknown>>;
2043
+ }
2044
+
2045
+ /**
2046
+ * The live leaf state machine (W-b) for one {@link TaskDefinition} — an observable
2047
+ * (AGENTS §13), guarded synchronous task whose explicit {@link TaskStatus} advances
2048
+ * through the AGENTS §10 transitions.
2049
+ *
2050
+ * @remarks
2051
+ * - **Identity + lineage.** `id` / `name` / `description` mirror the definition;
2052
+ * `context` is the task's full {@link TaskContext} (so `context.phase` /
2053
+ * `context.phase.workflow` navigate UP the tree), and `phase` / `workflow` are the
2054
+ * live parent entities for direct lineage navigation.
2055
+ * - **State machine (AGENTS §10).** `status` is the explicit current state. `start`
2056
+ * moves `pending → running`; the terminal transitions are `complete(value)` (records
2057
+ * a {@link import('@orkestrel/contract').Success}), `fail(error)` (records a
2058
+ * {@link import('@orkestrel/contract').Failure}), `skip` (AGENTS §10 — intentionally not run),
2059
+ * and `stop` (AGENTS §10 — ended early). Each is GUARDED: an illegal transition (e.g.
2060
+ * completing a non-`running` task) throws a {@link import('./errors.js').WorkflowError}.
2061
+ * `skip` / `stop` set the override so the leaf's terminal state survives a snapshot.
2062
+ * - **Result.** `result` is the recorded {@link TaskResult} once the task settled with an
2063
+ * outcome (`completed` / `failed`), else `undefined` — the lineage-navigable leaf of the
2064
+ * result tree.
2065
+ * - **Observable (AGENTS §13).** The owned {@link emitter} ({@link TaskEventMap}) fires
2066
+ * `start` / `complete` / `fail` / `skip` / `stop` strictly AFTER each transition; the
2067
+ * emitter isolates a listener throw and routes it to its `error` handler (the `error` option).
2068
+ */
2069
+ export declare interface TaskInterface {
2070
+ readonly emitter: EmitterInterface<TaskEventMap>;
2071
+ readonly id: string;
2072
+ readonly name: string;
2073
+ readonly description?: string;
2074
+ readonly context: TaskContext;
2075
+ readonly phase: PhaseInterface;
2076
+ readonly workflow: WorkflowInterface;
2077
+ readonly status: TaskStatus;
2078
+ /** The recorded outcome once the task settled with one (`completed` / `failed`), else `undefined`. */
2079
+ readonly result: TaskResult | undefined;
2080
+ start(): void;
2081
+ complete(value: unknown): void;
2082
+ fail(error: unknown): void;
2083
+ skip(): void;
2084
+ stop(): void;
2085
+ snapshot(): TaskSnapshot;
2086
+ }
2087
+
2088
+ /**
2089
+ * The lean child manager (AGENTS §9) of a {@link import('../phases/Phase.js').Phase}'s live
2090
+ * tasks — an insertion-ordered registry keyed by task `id`, so positional order is
2091
+ * preserved across an interior `skip` / `remove`.
2092
+ *
2093
+ * @remarks
2094
+ * - **Positional store.** Tasks live in an insertion-ordered `Map` keyed by `id`;
2095
+ * `append` adds one at the end (the build-time wiring path), `task(id)` looks one up,
2096
+ * `tasks()` lists them in positional order, `count` is the size. A `skip` is a STATUS
2097
+ * change on a stored task (never a removal), so order survives it; a snapshot RESTORE
2098
+ * re-`append`s in the snapshot's order, reproducing it exactly.
2099
+ * - **No batch matrix.** A phase's tasks are a fixed positional set, so AGENTS §9.2 (the
2100
+ * bulk verb overloads) is deliberately omitted — there is no `remove` family here.
2101
+ * - **Event-free.** A purely structural container — the live {@link TaskInterface}s own
2102
+ * their own emitters; the manager observes nothing.
2103
+ *
2104
+ * @example
2105
+ * ```ts
2106
+ * const tasks = new TaskManager()
2107
+ * tasks.append(task) // a live Task
2108
+ * tasks.task(task.id) // the same task
2109
+ * tasks.count // 1
2110
+ * ```
2111
+ */
2112
+ export declare class TaskManager implements TaskManagerInterface {
2113
+ #private;
2114
+ get count(): number;
2115
+ append(task: TaskInterface): void;
2116
+ task(id: string): TaskInterface | undefined;
2117
+ tasks(): readonly TaskInterface[];
2118
+ }
2119
+
2120
+ /**
2121
+ * The lean child manager (AGENTS §9) of a {@link PhaseInterface}'s live tasks —
2122
+ * positional accessors plus `count`, backed by an insertion-ordered store so order
2123
+ * is preserved across an interior `skip` / `remove`.
2124
+ *
2125
+ * @remarks
2126
+ * `append` adds one live {@link TaskInterface} at the end (the build-time wiring path);
2127
+ * `task(id)` looks one up; `tasks()` lists them in positional order; `count` is the
2128
+ * tally. No batch matrix (AGENTS §9.2 is deliberately omitted — a phase's tasks are a
2129
+ * fixed positional set, not a bulk-mutated collection).
2130
+ */
2131
+ export declare interface TaskManagerInterface {
2132
+ readonly count: number;
2133
+ append(task: TaskInterface): void;
2134
+ task(id: string): TaskInterface | undefined;
2135
+ tasks(): readonly TaskInterface[];
2136
+ }
2137
+
2138
+ /**
2139
+ * The runtime options for a {@link TaskInterface} — the construction bag the live
2140
+ * leaf state machine (W-b) carries that the W-a {@link TaskDefinition} did not.
2141
+ *
2142
+ * @remarks
2143
+ * The reserved `on` (AGENTS §8) wires initial {@link TaskEventMap} listeners; a
2144
+ * {@link createTask}-built tree threads each level's `on` from its parent options.
2145
+ * `metadata` is the open consumer bag carried verbatim into a {@link TaskSnapshot}
2146
+ * (mirrors {@link TaskInput.metadata}), never interpreted by the workflow.
2147
+ */
2148
+ export declare interface TaskOptions {
2149
+ readonly on?: TaskHooks;
2150
+ /** The emitter's listener-error handler (AGENTS §13) — a listener throw routes here, not to a domain event. */
2151
+ readonly error?: EmitterErrorHandler;
2152
+ /** An open consumer bag — stored and snapshotted, never interpreted by the workflow. */
2153
+ readonly metadata?: Readonly<Record<string, unknown>>;
2154
+ }
2155
+
2156
+ /**
2157
+ * The structured outcome of a task execution — its full lineage, its terminal
2158
+ * status, the moment it settled, and its boxed produced outcome.
2159
+ *
2160
+ * @remarks
2161
+ * Carries the complete lineage (`task` / `phase` / `workflow` contexts) so a result
2162
+ * is self-describing wherever it travels. `status` is the terminal state this
2163
+ * result records. `result` BOXES the produced outcome in a {@link Result}: it is
2164
+ * PRESENT exactly when `status` is `completed` (a {@link import('@orkestrel/contract').Success})
2165
+ * or `failed` (a {@link import('@orkestrel/contract').Failure}), and ABSENT when `status` is
2166
+ * `skipped` or `stopped` (terminal, but produced no outcome) — a pending/running
2167
+ * task has no result at all (a non-terminal status, per
2168
+ * {@link import('./helpers.js').isTerminalStatus}). This boxed `result` REPLACES separate
2169
+ * `value?` / `error?` fields: a success's payload is `result.value`, a failure's reason is `result.error`.
2170
+ * `timestamp` is when the result was created (ms since epoch).
2171
+ */
2172
+ export declare interface TaskResult {
2173
+ readonly task: TaskContext;
2174
+ readonly phase: PhaseContext;
2175
+ readonly workflow: WorkflowContext;
2176
+ readonly status: TaskStatus;
2177
+ /** The boxed outcome — present for `completed` (Success) / `failed` (Failure), absent otherwise. */
2178
+ readonly result?: Result<unknown>;
2179
+ readonly timestamp: number;
2180
+ }
2181
+
2182
+ /**
2183
+ * The shape of a {@link import('./types.js').TaskDefinition} — identity plus the
2184
+ * behavior reference ({@link taskFormShape}). `description` is optional prose.
2185
+ */
2186
+ export declare const taskShape: ObjectShape<{
2187
+ id: StringShape;
2188
+ name: StringShape;
2189
+ description: OptionalShape<StringShape>;
2190
+ run: UnionShape<[ ObjectShape<{
2191
+ via: LiteralShape<readonly ["function"]>;
2192
+ name: StringShape;
2193
+ }>, ObjectShape<{
2194
+ via: LiteralShape<readonly ["tool"]>;
2195
+ name: StringShape;
2196
+ }>, ObjectShape<{
2197
+ via: LiteralShape<readonly ["agent"]>;
2198
+ name: StringShape;
2199
+ }>]>;
2200
+ retries: OptionalShape<NumberShape>;
2201
+ timeout: OptionalShape<NumberShape>;
2202
+ }>;
2203
+
2204
+ /**
2205
+ * A JSON-serializable snapshot of one task's state — the leaf of the snapshot tree
2206
+ * the durable store (W-d) persists.
2207
+ *
2208
+ * @remarks
2209
+ * Pure JSON DATA (no class instances, no functions). `result` is the task's
2210
+ * {@link TaskResult} when it has settled with an outcome, else `undefined`.
2211
+ * `metadata` is the open consumer bag carried from the task's {@link TaskInput}.
2212
+ */
2213
+ export declare interface TaskSnapshot {
2214
+ readonly id: string;
2215
+ readonly name: string;
2216
+ readonly description?: string;
2217
+ readonly status: TaskStatus;
2218
+ readonly result?: TaskResult;
2219
+ readonly metadata: Readonly<Record<string, unknown>>;
2220
+ }
2221
+
2222
+ /**
2223
+ * The lifecycle status of a task — `pending` before it runs, `running` while in
2224
+ * flight, then one of the terminal states: `completed` (a success), `failed` (a
2225
+ * genuine error), `skipped` (intentionally not executed, AGENTS §10 `skip`), or
2226
+ * `stopped` (permanently ended, AGENTS §10 `stop`).
2227
+ *
2228
+ * @remarks
2229
+ * A semantic tier of the shared {@link LifecycleStatus} vocabulary. Uses `running` /
2230
+ * `failed` (the project vocabulary), and keeps `skipped` and `stopped` DISTINCT — a
2231
+ * skip is "deliberately not run", a stop is "ended early". The terminal members are
2232
+ * exactly those for which a {@link TaskResult} is meaningful: `completed` / `failed`
2233
+ * box a {@link Result}, while `skipped` / `stopped` are terminal WITHOUT a boxed
2234
+ * outcome. See {@link import('./helpers.js').isTerminalStatus}.
2235
+ */
2236
+ export declare type TaskStatus = LifecycleStatus;
2237
+
2238
+ /** The discriminant literal of a {@link TaskForm} — the execution mechanism axis. */
2239
+ export declare type TaskVia = TaskForm['via'];
2240
+
2241
+ /**
2242
+ * The {@link TaskStatus} values that are TERMINAL — a task in one of these will
2243
+ * not transition further, frozen.
2244
+ *
2245
+ * @remarks
2246
+ * The source of truth behind {@link import('./helpers.js').isTerminalStatus}.
2247
+ * `pending` and `running` are the only non-terminal members.
2248
+ */
2249
+ export declare const TERMINAL_TASK_STATUSES: readonly TaskStatus[];
2250
+
2251
+ /**
2252
+ * One unit's settled outcome — a discriminated union so a value of `undefined` is still
2253
+ * a success (`{ ok: true, value: undefined }`), never mistaken for a failure or an
2254
+ * absent result.
2255
+ *
2256
+ * @remarks
2257
+ * The runner records each settled unit's outcome through this shape: a success boxes the
2258
+ * resolved `value` (presence tracked by the union tag, so `undefined` is a valid result),
2259
+ * a failure carries the `error` (always `unknown`). The FIRST failure is fail-fast.
2260
+ *
2261
+ * @typeParam TResult - The value a unit resolves
2262
+ */
2263
+ export declare type UnitOutcome<TResult> = {
2264
+ readonly ok: true;
2265
+ readonly value: TResult;
2266
+ } | {
2267
+ readonly ok: false;
2268
+ readonly error: unknown;
2269
+ };
2270
+
2271
+ /**
2272
+ * The live DERIVED state machine (W-b) for a whole workflow — the observable (AGENTS §13)
2273
+ * ROOT whose {@link WorkflowStatus} is computed from its phases under the `bail` policy and
2274
+ * recomputed reactively as the cascade propagates up from a task transition.
2275
+ *
2276
+ * @remarks
2277
+ * - **Construction.** Built from a {@link WorkflowSnapshot} (the unified input —
2278
+ * {@link import('./factories.js').createWorkflow} seeds an initial snapshot from a
2279
+ * {@link import('./types.js').WorkflowDefinition}, {@link import('./factories.js').restoreWorkflow}
2280
+ * passes a persisted one). Each child {@link Phase} is wired to escalate to {@link #recompute}.
2281
+ * - **Derived status.** `status` is `#override` when forced, else
2282
+ * {@link deriveWorkflowStatus} over the live phases' statuses feeding `bail`. `failed` is
2283
+ * reachable ONLY under `bail: true` (a single failed task halts the workflow); under
2284
+ * `bail: false` a failed phase folds into `completed`. {@link #recompute} diffs on each phase
2285
+ * change; a CHANGE emits.
2286
+ * - **Override (AGENTS §10).** `skip` / `stop` FORCE the status; the override is PERSISTED in the
2287
+ * snapshot's own `override` field and restored DIRECTLY (no divergence guess). The snapshot also
2288
+ * persists `bail`, so a restore re-derives status identically without a silent policy default.
2289
+ * - **Result tree.** `results()` flattens every phase's `results()` ({@link collectResults}) — the
2290
+ * workflow tier; `phase(id)` + each `phase.task(id)` navigate DOWN, a task's `phase` / `workflow`
2291
+ * navigate UP.
2292
+ * - **Snapshot.** `snapshot()` serializes the whole live tree to a {@link WorkflowSnapshot} (pure
2293
+ * JSON); {@link import('./factories.js').restoreWorkflow} rebuilds an equivalent live tree.
2294
+ * - **Observable (AGENTS §13).** The owned {@link emitter} ({@link WorkflowEventMap}) fires
2295
+ * `start` / `complete` / `fail` / `stop` on a derived-status CHANGE; the emitter isolates a
2296
+ * listener throw and routes it to its `error` handler (the `error` option); `fail` carries
2297
+ * the failing task's {@link TaskResult}.
2298
+ */
2299
+ export declare class Workflow implements WorkflowInterface {
2300
+ #private;
2301
+ constructor(snapshot: WorkflowSnapshot, options?: WorkflowOptions);
2302
+ get emitter(): EmitterInterface<WorkflowEventMap>;
2303
+ get id(): string;
2304
+ get name(): string;
2305
+ get description(): string | undefined;
2306
+ get context(): WorkflowContext;
2307
+ get bail(): boolean;
2308
+ get status(): WorkflowStatus;
2309
+ get phases(): PhaseManagerInterface;
2310
+ phase(id: string): PhaseInterface | undefined;
2311
+ results(): readonly TaskResult[];
2312
+ skip(): void;
2313
+ stop(): void;
2314
+ complete(): void;
2315
+ snapshot(): WorkflowSnapshot;
2316
+ }
2317
+
2318
+ /** Every {@link WorkflowStatus} value, frozen — the lifecycle vocabulary of a workflow. */
2319
+ export declare const WORKFLOW_STATUSES: readonly WorkflowStatus[];
2320
+
2321
+ /**
2322
+ * The DESCRIPTION {@link import('./factories.js').createWorkflowTool} advertises — a
2323
+ * multi-line guide that teaches a small model how to author a complete workflow tree.
2324
+ *
2325
+ * @remarks
2326
+ * Presents the SIMPLE flat shape (`{ name, steps: [{ name, via }] }`) as the PRIMARY way with
2327
+ * one complete worked example ({@link WORKFLOW_TOOL_FLAT_EXAMPLE}), names the three `via`
2328
+ * values + that a step's `name` is a REGISTERED name (not a human label), and documents the full nested
2329
+ * {@link WorkflowDefinition} as the ADVANCED form with a minimal example
2330
+ * ({@link WORKFLOW_TOOL_NESTED_EXAMPLE}). Both examples are interpolated VERBATIM from the
2331
+ * validated constants, so a parity test pins them — the description can never drift from a
2332
+ * real, contract-valid example. The `parameters` the tool advertises are the FLAT shape's
2333
+ * schema; the nested form is the documented escape-hatch (the tool accepts both).
2334
+ */
2335
+ export declare const WORKFLOW_TOOL_DESCRIPTION: string;
2336
+
2337
+ /**
2338
+ * A complete FLAT authoring example — the PRIMARY way a small model authors a workflow
2339
+ * through {@link import('./factories.js').createWorkflowTool}: `{ name, steps: [{ name, via }] }`.
2340
+ *
2341
+ * @remarks
2342
+ * Each step becomes a one-task phase, in order; a step's `name` is a REGISTERED behavior name
2343
+ * (not a label) and `via` is the execution mechanism. The tool expands this
2344
+ * ({@link import('./helpers.js').expandSteps}) into a valid {@link WorkflowDefinition}. It
2345
+ * is embedded VERBATIM in {@link WORKFLOW_TOOL_DESCRIPTION} and guarded by a parity test
2346
+ * (it must expand to a tree the STRICT contract accepts), so the doc example can never drift.
2347
+ */
2348
+ export declare const WORKFLOW_TOOL_FLAT_EXAMPLE: WorkflowSteps;
2349
+
2350
+ /**
2351
+ * The name under which the {@link import('./WorkflowRunner.js').WorkflowRunner} BINDS the
2352
+ * depth/cycle-aware workflow tool onto a dispatched `agent` task's
2353
+ * `AgentContextInterface` (the future `@orkestrel/agent` package, W-c2).
2354
+ *
2355
+ * @remarks
2356
+ * The propagation seam's well-known key: before running an `agent` task, the runner adds a
2357
+ * {@link import('./factories.js').createWorkflowTool}-built tool under this name to the
2358
+ * resolved agent's `context.tools`, so the subagent can author + run a NESTED workflow
2359
+ * (bounded by {@link MAX_WORKFLOW_DEPTH}). A subagent that wants to fan out into a workflow
2360
+ * calls this tool by this name; the bound handler runs the nested workflow at depth + 1.
2361
+ */
2362
+ export declare const WORKFLOW_TOOL_NAME = "workflow";
2363
+
2364
+ /**
2365
+ * A minimal NESTED authoring example — the ADVANCED escape-hatch form a model may use
2366
+ * instead of the flat shape: a full {@link WorkflowDefinition}.
2367
+ *
2368
+ * @remarks
2369
+ * The full four-level form, documented in {@link WORKFLOW_TOOL_DESCRIPTION} as the advanced
2370
+ * alternative. It is embedded VERBATIM and guarded by a parity test (`createWorkflowContract().is`
2371
+ * must accept it), so the doc example can never drift from a valid definition.
2372
+ */
2373
+ export declare const WORKFLOW_TOOL_NESTED_EXAMPLE: WorkflowDefinition;
2374
+
2375
+ /**
2376
+ * The `agent`-task behavior resolver (W-c2) — resolves a registered agent BY NAME to a
2377
+ * live {@link AgentInterface} the runner runs as a subagent.
2378
+ *
2379
+ * @remarks
2380
+ * The `agent` analogue of the {@link WorkflowFunctions} registry / the
2381
+ * {@link ToolManagerInterface} the other two forms dispatch through: the runner resolves
2382
+ * an `agent`-form {@link TaskForm}'s `name` here. A name absent from the resolver is the
2383
+ * no-handler case — the task AUTO-COMPLETES (the ROADMAP rule), exactly like an
2384
+ * unregistered `function` / `tool`.
2385
+ *
2386
+ * **Resolve a FRESH agent per call.** A phase's tasks run CONCURRENTLY, so two `agent`
2387
+ * tasks naming the same agent are resolved concurrently — and the runner BINDS a
2388
+ * depth/cycle-aware workflow tool onto each resolved agent's `context.tools` (the
2389
+ * propagation seam — see {@link WorkflowToolOptions}). An implementation that returns the
2390
+ * SAME instance for both would have them race on that mutation, so it must mint a fresh
2391
+ * agent each call (exactly as `AgentRegistry.build` does). A function resolver
2392
+ * (`(name) => …`) is the minimal shape; the agents module's `AgentRegistry` is not a
2393
+ * direct fit (its `build` rehydrates from a serializable `AgentJobInput`, not a bare
2394
+ * name), so a small adapter `(name) => registry.build({ provider, ... })` bridges it.
2395
+ *
2396
+ * @param name - The agent's registry key (the `agent`-form's `name`)
2397
+ * @returns The resolved live agent, or `undefined` when the name is unregistered
2398
+ */
2399
+ export declare type WorkflowAgents = (name: string) => AgentInterface | undefined;
2400
+
2401
+ /**
2402
+ * The ambient context of a workflow — the identity every level inherits.
2403
+ *
2404
+ * @remarks
2405
+ * The root of the context chain: a {@link PhaseContext} and {@link TaskContext}
2406
+ * both extend it, so a task at the leaf still sees the workflow's `id` / `name`.
2407
+ * `description` is optional (it mirrors the optional definition field).
2408
+ */
2409
+ export declare interface WorkflowContext {
2410
+ readonly id: string;
2411
+ readonly name: string;
2412
+ readonly description?: string;
2413
+ }
2414
+
2415
+ /**
2416
+ * The serializable definition of a whole workflow — its identity, its ordered
2417
+ * phases, and the `bail` failure policy.
2418
+ *
2419
+ * @remarks
2420
+ * Pure JSON DATA — the root a UI/LLM authors and the contract validates. `phases`
2421
+ * are the workflow's phases, which run SEQUENTIALLY. `bail` is the failure policy
2422
+ * (a boolean behavioral toggle, AGENTS §4.4): `false` (the default) is GRACEFUL —
2423
+ * a failed leaf task is recorded as data and the workflow still completes; `true`
2424
+ * is a database-transaction HALT — a single failed task propagates `failed` to the
2425
+ * whole workflow. See {@link import('./helpers.js').deriveWorkflowStatus}.
2426
+ */
2427
+ export declare interface WorkflowDefinition {
2428
+ readonly id: string;
2429
+ readonly name: string;
2430
+ readonly description?: string;
2431
+ readonly phases: readonly PhaseDefinition[];
2432
+ /** Failure policy: `false` (default) continues gracefully, `true` halts on the first failure. */
2433
+ readonly bail?: boolean;
2434
+ }
2435
+
2436
+ /**
2437
+ * A draft workflow — a {@link WorkflowDefinition} with OPTIONAL `id` / `name` at all
2438
+ * three levels (workflow / phase / task).
2439
+ *
2440
+ * @remarks
2441
+ * The lenient authoring form `createWorkflowDraftContract` validates and
2442
+ * {@link import('./helpers.js').completeDraft} completes into a strict
2443
+ * {@link WorkflowDefinition}. `run` stays required; the `bail` policy carries over.
2444
+ */
2445
+ export declare interface WorkflowDraft {
2446
+ readonly id?: string;
2447
+ readonly name?: string;
2448
+ readonly description?: string;
2449
+ readonly phases: readonly PhaseDraft[];
2450
+ /** Failure policy: `false` (default) continues gracefully, `true` halts on the first failure. */
2451
+ readonly bail?: boolean;
2452
+ }
2453
+
2454
+ /**
2455
+ * The shape of a DRAFT workflow — identical to {@link workflowShape} EXCEPT `id` and
2456
+ * `name` are OPTIONAL at all three levels (workflow / phase / task), so a small model
2457
+ * can omit the six identity strings and let the tool synthesize them positionally.
2458
+ *
2459
+ * @remarks
2460
+ * The lenient counterpart {@link import('./factories.js').createWorkflowDraftContract}
2461
+ * compiles. `run` stays required; a provided `id` / `name` still has `minLength: 1` (so an
2462
+ * explicitly-empty `id: ''` is REJECTED, not auto-filled). After
2463
+ * {@link import('./helpers.js').completeDraft} fills the missing ids/names, the result is
2464
+ * validated against the STRICT {@link import('./factories.js').createWorkflowContract} gate
2465
+ * before running.
2466
+ */
2467
+ export declare const workflowDraftShape: ObjectShape<{
2468
+ id: OptionalShape<StringShape>;
2469
+ name: OptionalShape<StringShape>;
2470
+ description: OptionalShape<StringShape>;
2471
+ phases: ArrayShape<ObjectShape<{
2472
+ id: OptionalShape<StringShape>;
2473
+ name: OptionalShape<StringShape>;
2474
+ description: OptionalShape<StringShape>;
2475
+ tasks: ArrayShape<ObjectShape<{
2476
+ id: OptionalShape<StringShape>;
2477
+ name: OptionalShape<StringShape>;
2478
+ description: OptionalShape<StringShape>;
2479
+ run: UnionShape<[ ObjectShape<{
2480
+ via: LiteralShape<readonly ["function"]>;
2481
+ name: StringShape;
2482
+ }>, ObjectShape<{
2483
+ via: LiteralShape<readonly ["tool"]>;
2484
+ name: StringShape;
2485
+ }>, ObjectShape<{
2486
+ via: LiteralShape<readonly ["agent"]>;
2487
+ name: StringShape;
2488
+ }>]>;
2489
+ retries: OptionalShape<NumberShape>;
2490
+ timeout: OptionalShape<NumberShape>;
2491
+ }>>;
2492
+ concurrency: OptionalShape<NumberShape>;
2493
+ bail: OptionalShape<LiteralShape<readonly [true, false]>>;
2494
+ }>>;
2495
+ bail: OptionalShape<LiteralShape<readonly [true, false]>>;
2496
+ }>;
2497
+
2498
+ /**
2499
+ * An error thrown by the workflow entity + W-c2 recursion layer.
2500
+ *
2501
+ * @remarks
2502
+ * Carries a {@link WorkflowErrorCode} and an optional `context` bag naming the
2503
+ * offending node id / status. Thrown for an illegal lifecycle transition
2504
+ * (`TRANSITION`), a structurally invalid {@link import('./types.js').WorkflowSnapshot}
2505
+ * passed to {@link import('./factories.js').restoreWorkflow} (`RESTORE`), an over-deep /
2506
+ * cyclic nested-workflow dispatch (`DEPTH`), and a malformed
2507
+ * {@link import('./factories.js').createWorkflowTool} args blob (`TOOL`). On the
2508
+ * workflow-tool seam the `DEPTH` / `TOOL` throw is ISOLATED by the
2509
+ * `@orkestrel/agent` package's `ToolManager` into the tool result's
2510
+ * top-level `error` (AGENTS §14 — the universal tool-handler contract).
2511
+ */
2512
+ export declare class WorkflowError extends Error {
2513
+ readonly code: WorkflowErrorCode;
2514
+ readonly context?: Readonly<Record<string, unknown>>;
2515
+ constructor(code: WorkflowErrorCode, message: string, context?: Readonly<Record<string, unknown>>);
2516
+ }
2517
+
2518
+ /**
2519
+ * The machine-readable code of a {@link import('./errors.js').WorkflowError} — the
2520
+ * fault the live W-b state machine raises (AGENTS §12).
2521
+ *
2522
+ * @remarks
2523
+ * - `TRANSITION` — an illegal state-machine transition (e.g. `start`ing a task that is
2524
+ * not `pending`, or `complete`/`fail`ing one that is not `running`); the guard names
2525
+ * the offending current status + requested transition in the error `context`.
2526
+ * - `RESTORE` — a {@link import('./factories.js').restoreWorkflow} given a structurally
2527
+ * invalid {@link WorkflowSnapshot} (a status outside the lifecycle vocabulary).
2528
+ * - `DEPTH` — a nested-workflow dispatch (W-c2) that the runner's depth / cycle guard
2529
+ * rejected: running it would push the nested-workflow chain past
2530
+ * {@link import('./constants.js').MAX_WORKFLOW_DEPTH}, OR its target agent (or a
2531
+ * workflow it would author) is already an ancestor of the current run (a re-entry
2532
+ * cycle). Raised on BOTH seams of the W-c2 recursion — an `agent`-task dispatch
2533
+ * (`fail`ed with this code; it never runs) AND the
2534
+ * {@link import('./factories.js').createWorkflowTool} handler (thrown, then ISOLATED
2535
+ * by the `@orkestrel/agent` package's `ToolManager` into the tool
2536
+ * result's `error`). The error `context` names the offending agent / workflow id + the depth.
2537
+ * - `TOOL` — the {@link import('./factories.js').createWorkflowTool} handler was handed
2538
+ * a MALFORMED / over-constraint authored args blob (e.g. an empty `id`, `concurrency: 0`)
2539
+ * that the contract rejected, so no workflow ran. The handler THROWS it (rather than
2540
+ * returning a failure result), and the `@orkestrel/agent` package's `ToolManager`
2541
+ * ISOLATES the throw into the canonical tool result's top-level `error` (AGENTS §14 — the
2542
+ * universal tool-handler contract); the error `context` names the wrapped workflow id.
2543
+ */
2544
+ export declare type WorkflowErrorCode = 'TRANSITION' | 'RESTORE' | 'DEPTH' | 'TOOL';
2545
+
2546
+ /**
2547
+ * The push observation surface (AGENTS §13) of the workflow entity (W-b) — the
2548
+ * lifecycle moments a fire-and-forget observer subscribes to via
2549
+ * `workflow.emitter.on`.
2550
+ *
2551
+ * @remarks
2552
+ * Present-tense events with arg tuples. `start` fires when the workflow begins;
2553
+ * `complete` when every phase settled successfully; `fail` when a phase failed
2554
+ * under `bail` (carrying the failing {@link TaskResult}); `stop` when the workflow
2555
+ * was permanently ended. A throwing listener never reaches the domain surface — the
2556
+ * emitter isolates it and routes it to its OWN `error` handler (the `error` option,
2557
+ * AGENTS §13). Declared as a `type` alias (not `interface extends EventMap`, AGENTS
2558
+ * §4.5) so the type-literal satisfies `EventMap` structurally.
2559
+ */
2560
+ export declare type WorkflowEventMap = {
2561
+ /** The workflow began — its `id`. */
2562
+ readonly start: readonly [id: string];
2563
+ /** Every phase settled successfully. */
2564
+ readonly complete: readonly [];
2565
+ /** A phase failed under `bail` — the failing task's result. */
2566
+ readonly fail: readonly [result: TaskResult];
2567
+ /** The workflow was permanently stopped. */
2568
+ readonly stop: readonly [];
2569
+ };
2570
+
2571
+ /**
2572
+ * A registered workflow function — the behavior a `function`-form
2573
+ * {@link TaskDefinition} runs, resolved BY NAME through the {@link WorkflowFunctions}
2574
+ * registry (AGENTS §4.5 — a `Handler` function type the framework invokes).
2575
+ *
2576
+ * @remarks
2577
+ * Receives a {@link TaskControllerInterface} — the running task's folded `signal`, its
2578
+ * `input` (the task's `metadata` bag), its lineage {@link TaskContext}, and read-UP access
2579
+ * to earlier phases' {@link TaskResult}s. A returned value becomes the task's
2580
+ * {@link import('@orkestrel/contract').Success} ({@link TaskInterface.complete}); a throw / rejection
2581
+ * becomes its {@link import('@orkestrel/contract').Failure} ({@link TaskInterface.fail}). Long work
2582
+ * should honour `controller.signal` (a workflow-level abort / timeout / budget, or — under
2583
+ * `bail: true` — a sibling's failure, fires it) so a cancel stops it promptly.
2584
+ */
2585
+ export declare type WorkflowFunction = (controller: TaskControllerInterface) => Promise<unknown> | unknown;
2586
+
2587
+ /**
2588
+ * The `function`-task behavior registry — workflow function names mapped to their
2589
+ * {@link WorkflowFunction} handlers.
2590
+ *
2591
+ * @remarks
2592
+ * The runner resolves a `function`-form {@link TaskForm}'s `name` here. A name absent
2593
+ * from the registry is the no-handler case — the task AUTO-COMPLETES (the ROADMAP rule),
2594
+ * exactly like an unsupported form. A plain record (not a manager) — the registry is a
2595
+ * lookup, with no lifecycle of its own.
2596
+ */
2597
+ export declare type WorkflowFunctions = Readonly<Record<string, WorkflowFunction>>;
2598
+
2599
+ /** Initial {@link WorkflowEventMap} listeners — the reserved `on` option (AGENTS §8). */
2600
+ export declare type WorkflowHooks = EmitterHooks<WorkflowEventMap>;
2601
+
2602
+ /** The minimal data to create a workflow context — a partial {@link WorkflowContext}. */
2603
+ export declare type WorkflowInput = Partial<WorkflowContext>;
2604
+
2605
+ /**
2606
+ * The live derived state machine (W-b) for a whole {@link WorkflowDefinition} — the
2607
+ * observable (AGENTS §13) root whose {@link WorkflowStatus} is DERIVED from its phases
2608
+ * under the `bail` policy and recomputed reactively as the cascade propagates up.
2609
+ *
2610
+ * @remarks
2611
+ * - **Derived status.** `status` is computed via
2612
+ * {@link import('./helpers.js').deriveWorkflowStatus} over the live phases' statuses,
2613
+ * feeding the definition's `bail`, UNLESS an override is in force. It recomputes when a
2614
+ * phase's status changes (the top of the cascade); a CHANGE emits — `fail` carries the
2615
+ * failing {@link TaskResult} (under `bail: true`).
2616
+ * - **Children.** `phases` is the lean {@link PhaseManagerInterface} (AGENTS §9);
2617
+ * `phase(id)` / `phases().phases()` read in positional order. `results` collects ALL
2618
+ * tasks' results across every phase (the workflow tier of the result tree).
2619
+ * - **Override.** `skip` / `stop` (AGENTS §10) FORCE the workflow's status; the override
2620
+ * survives a snapshot.
2621
+ * - **Snapshot.** `snapshot()` serializes the whole live tree to a {@link WorkflowSnapshot}
2622
+ * (pure JSON — structure + each node's status + recorded results + positional order);
2623
+ * {@link restoreWorkflow} rebuilds an equivalent live tree.
2624
+ * - **Observable (AGENTS §13).** The owned {@link emitter} ({@link WorkflowEventMap}) fires
2625
+ * `start` / `complete` / `fail` / `stop` on a derived-status change; the emitter isolates a
2626
+ * listener throw and routes it to its `error` handler (the `error` option).
2627
+ */
2628
+ export declare interface WorkflowInterface {
2629
+ readonly emitter: EmitterInterface<WorkflowEventMap>;
2630
+ readonly id: string;
2631
+ readonly name: string;
2632
+ readonly description?: string;
2633
+ readonly context: WorkflowContext;
2634
+ readonly bail: boolean;
2635
+ readonly status: WorkflowStatus;
2636
+ readonly phases: PhaseManagerInterface;
2637
+ /** Look up one live phase by its `id`. */
2638
+ phase(id: string): PhaseInterface | undefined;
2639
+ /** Every settled task's result across all phases, in positional order — the workflow tier of the result tree. */
2640
+ results(): readonly TaskResult[];
2641
+ skip(): void;
2642
+ stop(): void;
2643
+ complete(): void;
2644
+ snapshot(): WorkflowSnapshot;
2645
+ }
2646
+
2647
+ /**
2648
+ * The runtime options for a {@link WorkflowInterface} — the construction bag the
2649
+ * live derived workflow state machine (W-b) carries, the root {@link createWorkflow}
2650
+ * accepts.
2651
+ *
2652
+ * @remarks
2653
+ * The reserved `on` (AGENTS §8) wires initial {@link WorkflowEventMap} listeners.
2654
+ * `phases` keys per-phase {@link PhaseOptions} by phase `id`, so the whole tree's
2655
+ * initial listeners + per-task metadata can be supplied in one nested bag (the
2656
+ * AGENTS §8 "entity is the key" grouping), each leaf reachable by its lineage of ids.
2657
+ */
2658
+ export declare interface WorkflowOptions {
2659
+ readonly on?: WorkflowHooks;
2660
+ /**
2661
+ * The failure policy (AGENTS §4.4) the live tree applies — the same boolean toggle as
2662
+ * {@link WorkflowDefinition.bail}, fed to {@link import('./helpers.js').deriveWorkflowStatus}.
2663
+ * {@link import('./factories.js').createWorkflow} defaults it to the definition's `bail`. A
2664
+ * {@link WorkflowSnapshot} PERSISTS the policy, so {@link import('./factories.js').restoreWorkflow}
2665
+ * takes it from the snapshot (the source of truth); an explicit `options.bail` on restore still
2666
+ * wins when supplied. Omitted on a fresh build ⇒ the graceful {@link import('./constants.js').DEFAULT_BAIL}.
2667
+ */
2668
+ readonly bail?: boolean;
2669
+ /** The emitter's listener-error handler (AGENTS §13) — a listener throw routes here, not to a domain event. */
2670
+ readonly error?: EmitterErrorHandler;
2671
+ /** Per-phase {@link PhaseOptions}, keyed by the phase's `id`. */
2672
+ readonly phases?: Readonly<Record<string, PhaseOptions>>;
2673
+ }
2674
+
2675
+ /**
2676
+ * The structured outcome of a {@link WorkflowRunnerInterface.execute} run — the settled
2677
+ * live workflow, its final status, and the flattened result tree.
2678
+ *
2679
+ * @remarks
2680
+ * Boxes the settled {@link WorkflowInterface} itself (so a caller can navigate the whole
2681
+ * live tree — every phase / task's final `status`, its recorded {@link TaskResult}, its
2682
+ * lineage) ALONGSIDE the two read-throughs the run produced: `status` is the workflow's
2683
+ * derived {@link WorkflowStatus} at settle (`completed` under graceful mode even with
2684
+ * failed leaves; `failed` under `bail: true`; `stopped` on a workflow-level abort /
2685
+ * timeout / budget), and `results` is the workflow-tier {@link TaskResult} list (every
2686
+ * settled task across all phases, in positional order — the same array `workflow.results()`
2687
+ * yields). Returning the live `workflow` (not just a snapshot) keeps the entity tree the
2688
+ * source of truth — the runner adds only the convenience `status` / `results` projections.
2689
+ */
2690
+ export declare interface WorkflowResult {
2691
+ readonly workflow: WorkflowInterface;
2692
+ readonly status: WorkflowStatus;
2693
+ readonly results: readonly TaskResult[];
2694
+ }
2695
+
2696
+ /**
2697
+ * The thin orchestrator that EXECUTES a live W-b workflow tree by COMPOSING the shipped
2698
+ * substrate — phases sequential, tasks concurrent — dispatching each task BY NAME under the
2699
+ * `bail` policy, including the W-c2 `agent` form behind a depth + cycle guard.
2700
+ *
2701
+ * @remarks
2702
+ * - **Composes, never re-implements.** Per-phase bounded concurrency is one
2703
+ * {@link createRunner} per phase (the substrate {@link RunnerInterface} over the workers
2704
+ * `Queue`); `bail` maps onto that Runner's fail-fast vs settle-all; the run-level abort /
2705
+ * timeout / budget fold through {@link createAbort} / {@link createTimeout} +
2706
+ * `AbortSignal.any` (exactly as the agent runtime folds its bounds); pacing is the shipped
2707
+ * {@link SchedulerInterface}. The runner writes ZERO concurrency / retry / abort logic of
2708
+ * its own — it only sequences phases, dispatches a task, and drives the live entity.
2709
+ * - **Phases sequential, tasks concurrent.** `#execute` awaits the phases in order (phase
2710
+ * N+1 starts only once phase N has fully settled). Within a phase, ALL its tasks are the
2711
+ * one Runner's `inputs`, run at `concurrency` = the phase's
2712
+ * {@link PhaseDefinition.concurrency} (default {@link DEFAULT_PHASE_CONCURRENCY}).
2713
+ * - **Dispatch by name.** `#dispatch` branches on the task's
2714
+ * {@link import('./types.js').TaskForm} (read from the `definition`, correlated by `id`):
2715
+ * `function` → the {@link WorkflowFunctions} registry, `tool` → the
2716
+ * {@link ToolManagerInterface}, `agent` → the {@link WorkflowAgents} resolver (W-c2). A
2717
+ * handler that is NOT found (an unregistered name for ANY form) AUTO-COMPLETES — the
2718
+ * ROADMAP no-handler rule.
2719
+ * - **`agent` form + depth/cycle guard (W-c2).** An `agent` task resolves its subagent via
2720
+ * `agents`, BINDS a depth/cycle-aware workflow tool onto the subagent's `context.tools`
2721
+ * (the propagation seam), folds the task's cancellation into the agent run (a workflow
2722
+ * cancel `abort`s the subagent), and drives it: success → `complete(result)`, throw →
2723
+ * `fail(error)`. Before running, the guard REJECTS the task into a typed `DEPTH`
2724
+ * {@link WorkflowError} (`fail`) when running it would push the nested chain past
2725
+ * {@link MAX_WORKFLOW_DEPTH}, OR when its target agent is already an ancestor (a cycle).
2726
+ * The rejected task never runs the agent.
2727
+ * - **`bail` → substrate.** Under `bail: true` (halt) a genuine task failure `fail`s the leaf
2728
+ * THEN re-throws, so the substrate Runner fail-fasts — it aborts the in-flight siblings
2729
+ * (their `controller.signal` fires; a mid-flight sibling `skip`s) and rejects the phase run;
2730
+ * `#execute` then `skip`s the remaining tasks / phases (the workflow derives `failed`).
2731
+ * Under `bail: false` (graceful) a failure `fail`s the leaf and RESOLVES (never throws), so
2732
+ * the Runner settles every unit (allSettled) and the run finishes (the workflow derives
2733
+ * `completed`, the failure recorded in the result tree).
2734
+ * - **Abort / Timeout / Budget fold.** `#execute` folds the run's external `signal`, a
2735
+ * {@link TimeoutInterface}, and the `@orkestrel/budget` package's `BudgetInterface`'s
2736
+ * `signal` into one `runSignal` (`AbortSignal.any`); a fire aborts the active phase's Runner
2737
+ * (cancelling every in-flight task) and HALTS the run — the remaining tasks / phases `skip`
2738
+ * and the workflow is force-`stop`ped (settles `stopped`). Each task's
2739
+ * {@link TaskController} signal `AbortSignal.any`-combines the substrate per-unit signal with
2740
+ * `runSignal`, so a handler observes either cause directly.
2741
+ * - **Re-entrant-safe.** No shared per-run mutable field: the active-Runner holder is LOCAL to
2742
+ * each `#execute`, so a nested `execute` (the bound workflow tool re-entering this instance
2743
+ * while the outer run is suspended on an `agent` task) cannot clobber the outer run's state.
2744
+ */
2745
+ export declare class WorkflowRunner implements WorkflowRunnerInterface {
2746
+ #private;
2747
+ constructor(functions: WorkflowFunctions, tools: ToolManagerInterface | undefined, agents: WorkflowAgents | undefined, scheduler: SchedulerInterface, workflowTool: WorkflowToolBinder | undefined);
2748
+ execute(definition: WorkflowDefinition, options?: WorkflowRunOptions): Promise<WorkflowResult>;
2749
+ }
2750
+
2751
+ /**
2752
+ * A thin orchestrator that EXECUTES a live {@link WorkflowInterface} tree by composing the
2753
+ * shipped substrate — phases sequential, tasks concurrent, dispatched by name under the
2754
+ * `bail` policy.
2755
+ *
2756
+ * @remarks
2757
+ * `execute(definition, options?)` BUILDS the live W-b entity tree from the definition itself
2758
+ * (via {@link import('./factories.js').createWorkflow}) and drives it to a terminal
2759
+ * {@link WorkflowResult} — phases SEQUENTIALLY and, within each phase, the tasks CONCURRENTLY
2760
+ * through ONE substrate {@link RunnerInterface} (concurrency =
2761
+ * the phase's {@link PhaseDefinition.concurrency}). The definition is the SINGLE source of
2762
+ * truth: the runner owns both the declarative state (the live tree it constructs) and the
2763
+ * EXECUTION-ONLY fields the snapshot deliberately dropped — each task's {@link TaskForm}
2764
+ * (`run`) and each phase's `concurrency` (so there is no separately-supplied workflow to drift
2765
+ * from the definition). The freshly-built live tree is returned in {@link WorkflowResult.workflow}.
2766
+ * Each task is dispatched by its {@link TaskForm} — a `function` through the
2767
+ * {@link WorkflowFunctions} registry, a `tool` through the {@link ToolManagerInterface}; a
2768
+ * task whose handler is not found AUTO-COMPLETES. The runner DRIVES the live entity (`start`
2769
+ * → `complete` / `fail`), never re-implementing status. The `bail` policy maps onto the
2770
+ * substrate's fail-fast (`bail: true` — the first failure aborts in-flight siblings and skips
2771
+ * the rest) vs settle-all (`bail: false` — failures are recorded and the run finishes). The
2772
+ * {@link WorkflowOptions} half of the options is forwarded to `createWorkflow` (initial
2773
+ * listeners, a `bail` override, per-node options); the Abort / Timeout / Budget bounds fold
2774
+ * per run via `AbortSignal.any`, halting the run and `stop`ping the workflow.
2775
+ */
2776
+ export declare interface WorkflowRunnerInterface {
2777
+ /**
2778
+ * Execute a workflow definition to completion — BUILD its live tree, run the phases
2779
+ * sequentially with each phase's tasks concurrent — resolving its terminal
2780
+ * {@link WorkflowResult} (whose `workflow` is the freshly-built live tree).
2781
+ *
2782
+ * @remarks
2783
+ * One-shot. The runner BUILDS the live tree from `definition` internally (one source of
2784
+ * truth — the per-task {@link TaskForm} (`run`) and per-phase `concurrency` come from the
2785
+ * same definition the tree is constructed from, so the executed tree can never drift from
2786
+ * the form/throttle metadata). The {@link WorkflowOptions} part of `options` (initial `on`
2787
+ * listeners, a `bail` override, the per-node `phases` bag) is forwarded to the build.
2788
+ * Under `bail: false` (graceful) every task settles (a failure is recorded on its
2789
+ * {@link TaskInterface}) and the workflow reaches `completed`; under `bail: true` (halt)
2790
+ * the first failure aborts the in-flight sibling tasks AND `skip`s the remaining tasks /
2791
+ * phases, settling the workflow `failed`. A {@link WorkflowRunOptions} abort / timeout /
2792
+ * budget fires every in-flight task's signal and `stop`s the run. `execute` resolves
2793
+ * (never rejects) on a cancel — the partial outcome is read from the returned
2794
+ * {@link WorkflowResult} (its `workflow` / `status` / `results`). A run-level cancel
2795
+ * (abort / timeout / budget) that fires on the SAME tick as a genuine task failure resolves
2796
+ * the run as `stopped` — the cancel supersedes the same-tick failure, and that task's error
2797
+ * is not recorded.
2798
+ *
2799
+ * @param definition - The {@link WorkflowDefinition} to build the live tree from and drive
2800
+ * @param options - The construction options ({@link WorkflowOptions}: `on` / `bail` /
2801
+ * `phases`) PLUS the per-run bounds (`signal` / `timeout` / `budget`)
2802
+ * @returns The run's terminal {@link WorkflowResult} (its `workflow` is the built tree)
2803
+ */
2804
+ execute(definition: WorkflowDefinition, options?: WorkflowRunOptions): Promise<WorkflowResult>;
2805
+ }
2806
+
2807
+ /**
2808
+ * The options for `createWorkflowRunner` — the behavior registries the runner dispatches
2809
+ * a task BY NAME through, plus the optional pacing scheduler.
2810
+ *
2811
+ * @remarks
2812
+ * - `functions` — the {@link WorkflowFunctions} registry for `function`-form tasks. A name
2813
+ * absent here is the no-handler case (the task auto-completes). Omitted ⇒ an empty
2814
+ * registry (every `function` task auto-completes).
2815
+ * - `tools` — the {@link ToolManagerInterface} (the shipped tool registry) a `tool`-form
2816
+ * task is dispatched through: the runner resolves `run.name` via `tools.tool(name)` and
2817
+ * invokes it with the task's input. An unregistered tool name is the no-handler case
2818
+ * (auto-completes). Omitted ⇒ every `tool` task auto-completes.
2819
+ * - `agents` — the {@link WorkflowAgents} resolver (W-c2) an `agent`-form task is dispatched
2820
+ * through: the runner resolves `run.name` to a live
2821
+ * {@link AgentInterface}, BINDS a depth/cycle-aware workflow
2822
+ * tool onto its `context.tools` (the propagation seam), folds the task's cancellation into
2823
+ * the agent run, and drives it (success → `complete`, throw → `fail`), all behind the
2824
+ * depth + cycle guard. An unregistered agent name is the no-handler case (auto-completes).
2825
+ * Omitted ⇒ every `agent` task auto-completes.
2826
+ * - `scheduler` — the {@link SchedulerInterface} that paces the tree (a cooperative
2827
+ * `yield` between phases). Omitted ⇒ the shipped cross-environment default
2828
+ * ({@link createScheduler}).
2829
+ *
2830
+ * The reserved `on` key (AGENTS §8) is intentionally ABSENT: the runner is THIN and drives
2831
+ * the W-b entities' OWN emitters (subscribe via `workflow.emitter` / `phase.emitter` /
2832
+ * `task.emitter`), so it owns no event map of its own — there is nothing for an `on` to
2833
+ * wire. A future runner-level emitter would introduce its own `EmitterHooks` here.
2834
+ */
2835
+ export declare interface WorkflowRunnerOptions {
2836
+ readonly functions?: WorkflowFunctions;
2837
+ readonly tools?: ToolManagerInterface;
2838
+ /** The {@link WorkflowAgents} resolver for `agent`-form tasks (W-c2); omitted ⇒ every `agent` task auto-completes. */
2839
+ readonly agents?: WorkflowAgents;
2840
+ readonly scheduler?: SchedulerInterface;
2841
+ }
2842
+
2843
+ /**
2844
+ * The options for one {@link WorkflowRunnerInterface.execute} call — the live tree's
2845
+ * CONSTRUCTION options ({@link WorkflowOptions}) PLUS the per-run BOUNDS (an external abort,
2846
+ * a deadline, and a cost ceiling), each bound folded into every task's cancellation.
2847
+ *
2848
+ * @remarks
2849
+ * `execute` is single-source: it BUILDS the live tree from the definition internally (via
2850
+ * {@link import('./factories.js').createWorkflow}), so these options carry BOTH halves of
2851
+ * that one call —
2852
+ * - the **construction** half is {@link WorkflowOptions} (`on` initial listeners, the `bail`
2853
+ * override, the per-node `phases` bag); `execute` forwards it straight to `createWorkflow`,
2854
+ * so construction-time emitter listeners, a `bail` override, and per-node options all apply
2855
+ * to the tree it builds (`createWorkflow` resolves `bail` as `options.bail ?? definition.bail
2856
+ * ?? DEFAULT_BAIL`); and
2857
+ * - the **run-control** half is the three bounds below, used only for the run-level fold.
2858
+ *
2859
+ * The three bounds compose via `AbortSignal.any` (exactly as the agent runtime folds its
2860
+ * own): a fire of ANY of them cancels every in-flight task (its
2861
+ * {@link TaskControllerInterface.signal} fires) and HALTS the run — the remaining tasks
2862
+ * and phases are `skip`ped and the workflow settles `stopped`.
2863
+ * - `signal` — an external cancellation (a caller `AbortController`).
2864
+ * - `timeout` — a whole-run deadline in milliseconds. A non-positive value (`0` or negative)
2865
+ * ⇒ NO deadline (the runner arms an `@orkestrel/timeout` `TimeoutInterface`
2866
+ * only when `timeout > 0`).
2867
+ * - `budget` — a whole-run cost ceiling (a {@link BudgetInterface} over {@link TokenUsage}
2868
+ * — its `signal` fires when a task-reported usage crosses `max`); the runner folds its
2869
+ * `signal` and `start`s it. (A `max: 0` budget is exhausted from its first `start`, so it
2870
+ * cancels the run at entry — a DIFFERENT primitive from the `timeout: 0` "no deadline" case.)
2871
+ *
2872
+ * The last two are the W-c2 DEPTH / CYCLE bookkeeping — the run's position in a nested
2873
+ * workflow→agent→workflow chain, threaded across the
2874
+ * `execute → agent-task → createWorkflowTool → nested execute` boundary so the guard can
2875
+ * bound recursion. A TOP-LEVEL `execute` omits both (depth `0`, empty ancestry); only the
2876
+ * runner-bound workflow tool ({@link import('./factories.js').createWorkflowTool}) supplies
2877
+ * them, incrementing the depth and extending the ancestry for each nested run.
2878
+ * - `depth` — the run's nesting depth (default `0`). An `agent` task is REJECTED (a typed
2879
+ * `DEPTH` `task.fail`) when running it would push the chain past
2880
+ * {@link import('./constants.js').MAX_WORKFLOW_DEPTH}.
2881
+ * - `ancestry` — the identifiers of the workflows + agents already in this run chain
2882
+ * (e.g. `workflow:<id>` / `agent:<name>`). An `agent` task whose target agent — or the
2883
+ * workflow it would author — is already present is a CYCLE and is likewise rejected.
2884
+ * Default empty.
2885
+ */
2886
+ export declare type WorkflowRunOptions = WorkflowOptions & {
2887
+ readonly signal?: AbortSignal;
2888
+ readonly timeout?: number;
2889
+ readonly budget?: BudgetInterface<TokenUsage>;
2890
+ /** The run's nesting depth (W-c2); default `0`. Threaded by the bound workflow tool, never by a top-level caller. */
2891
+ readonly depth?: number;
2892
+ /** The workflow / agent identifiers already in this run chain (W-c2 cycle guard); default empty. */
2893
+ readonly ancestry?: readonly string[];
2894
+ };
2895
+
2896
+ /**
2897
+ * The shape of a {@link import('./types.js').WorkflowDefinition} — the contract root:
2898
+ * identity, its ordered {@link phaseShape} phases, and the optional `bail` boolean
2899
+ * failure policy (the literal pair `true`/`false`, the runtime mirror of the boolean
2900
+ * toggle; omitted ⇒ the graceful default).
2901
+ */
2902
+ export declare const workflowShape: ObjectShape<{
2903
+ id: StringShape;
2904
+ name: StringShape;
2905
+ description: OptionalShape<StringShape>;
2906
+ phases: ArrayShape<ObjectShape<{
2907
+ id: StringShape;
2908
+ name: StringShape;
2909
+ description: OptionalShape<StringShape>;
2910
+ tasks: ArrayShape<ObjectShape<{
2911
+ id: StringShape;
2912
+ name: StringShape;
2913
+ description: OptionalShape<StringShape>;
2914
+ run: UnionShape<[ ObjectShape<{
2915
+ via: LiteralShape<readonly ["function"]>;
2916
+ name: StringShape;
2917
+ }>, ObjectShape<{
2918
+ via: LiteralShape<readonly ["tool"]>;
2919
+ name: StringShape;
2920
+ }>, ObjectShape<{
2921
+ via: LiteralShape<readonly ["agent"]>;
2922
+ name: StringShape;
2923
+ }>]>;
2924
+ retries: OptionalShape<NumberShape>;
2925
+ timeout: OptionalShape<NumberShape>;
2926
+ }>>;
2927
+ concurrency: OptionalShape<NumberShape>;
2928
+ bail: OptionalShape<LiteralShape<readonly [true, false]>>;
2929
+ }>>;
2930
+ bail: OptionalShape<LiteralShape<readonly [true, false]>>;
2931
+ }>;
2932
+
2933
+ /**
2934
+ * A JSON-serializable snapshot of a whole workflow's state — its identity, status, its
2935
+ * forced override (if any), the `bail` policy it ran under, its nested phase snapshots,
2936
+ * and creation / update timestamps.
2937
+ *
2938
+ * @remarks
2939
+ * Pure JSON DATA — the COMPLETE, SELF-CONTAINED payload the durable store (W-d) persists,
2940
+ * designed in full at W-a so its shape is fixed from the start. It can be written to disk,
2941
+ * sent to a prompt companion, loaded across conversations, or reviewed by an agent. Because
2942
+ * it is self-contained, it carries the policy it ran under: `bail` (AGENTS §4.4) is the
2943
+ * failure policy, so {@link import('./factories.js').restoreWorkflow} re-derives status
2944
+ * IDENTICALLY without a silent default. `status` is the EFFECTIVE status (override-or-derived)
2945
+ * at snapshot time; `override` is the forced status of a whole-workflow `skip` / `stop`,
2946
+ * PRESENT only when one is in force (so a restore reinstates it DIRECTLY rather than guessing
2947
+ * from a status divergence). `phases` are the workflow's {@link PhaseSnapshot}s in order;
2948
+ * `created` / `updated` are ms since epoch.
2949
+ */
2950
+ export declare interface WorkflowSnapshot {
2951
+ readonly id: string;
2952
+ readonly name: string;
2953
+ readonly description?: string;
2954
+ readonly status: WorkflowStatus;
2955
+ /** The forced status of a whole-workflow `skip` / `stop`; present only when an override is in force. */
2956
+ readonly override?: WorkflowStatus;
2957
+ /** The failure policy the workflow ran under (AGENTS §4.4) — persisted so a restore re-derives identically. */
2958
+ readonly bail: boolean;
2959
+ readonly phases: readonly PhaseSnapshot[];
2960
+ readonly created: number;
2961
+ readonly updated: number;
2962
+ }
2963
+
2964
+ /**
2965
+ * One row of the table a {@link import('./stores/DatabaseWorkflowStore.js').DatabaseWorkflowStore}
2966
+ * persists — a workflow `id` plus its {@link WorkflowSnapshot} held as ONE OPAQUE JSON column.
2967
+ *
2968
+ * @remarks
2969
+ * The Database twin of {@link WorkflowStoreInterface} stores the snapshot whole (the `snapshot`
2970
+ * column is a `rawShape`, an opaque JSON blob — exactly as
2971
+ * `@orkestrel/queue`'s `StoredEntry` stores a queue entry's `input`), so the row
2972
+ * type stays FLAT and the deeply-nested snapshot shape (workflow → phases → tasks → results) never
2973
+ * forces the contract to `Infer` it — sidestepping a TS2589 instantiation-depth blow-up. The column
2974
+ * therefore reads back as the broad `unknown`; the store narrows it to a {@link WorkflowSnapshot} on
2975
+ * `get` ({@link import('./helpers.js').isWorkflowSnapshot}, the AGENTS §14 boundary narrow). `id`
2976
+ * mirrors {@link WorkflowSnapshot.id} (the primary key), so a `set` writes `{ id: snapshot.id, snapshot }`.
2977
+ */
2978
+ export declare interface WorkflowSnapshotRow {
2979
+ readonly id: string;
2980
+ /** The whole {@link WorkflowSnapshot} as one opaque JSON blob — read back as `unknown`, narrowed on `get`. */
2981
+ readonly snapshot: unknown;
2982
+ }
2983
+
2984
+ /**
2985
+ * The lifecycle status of a workflow — the same vocabulary as {@link TaskStatus},
2986
+ * derived from its phases' statuses under the `bail` policy.
2987
+ *
2988
+ * @remarks
2989
+ * A semantic tier of the shared {@link LifecycleStatus} vocabulary. `failed` is
2990
+ * reachable ONLY under `bail: true` (a single failed task halts the whole workflow);
2991
+ * under `bail: false` a workflow `completed`s even with failed leaf tasks. See
2992
+ * {@link import('./helpers.js').deriveWorkflowStatus}.
2993
+ */
2994
+ export declare type WorkflowStatus = LifecycleStatus;
2995
+
2996
+ /**
2997
+ * One flat step — `{ name, via? }` — the building block of a {@link WorkflowSteps} blob.
2998
+ *
2999
+ * @remarks
3000
+ * `name` is the REGISTERED behavior name the step runs (it becomes the task's `run.name`,
3001
+ * NOT a human label). `via` is the optional execution mechanism — `'function'` (the
3002
+ * default when omitted), `'tool'`, or `'agent'`.
3003
+ */
3004
+ export declare interface WorkflowStep {
3005
+ /** The registered behavior name this step runs (becomes the task's `run.name`). */
3006
+ readonly name: string;
3007
+ /** How to run it — `'function'` (default), `'tool'`, or `'agent'`. */
3008
+ readonly via?: TaskVia;
3009
+ }
3010
+
3011
+ /**
3012
+ * The FLAT authoring blob `createWorkflowTool` advertises — `{ name?, steps }` — the
3013
+ * simplest surface a small model can fill.
3014
+ *
3015
+ * @remarks
3016
+ * Each {@link WorkflowStep} becomes a one-task phase, in order
3017
+ * ({@link import('./helpers.js').expandSteps}); `name` is the optional workflow name
3018
+ * (defaulted when omitted). The expanded tree is validated against the STRICT
3019
+ * {@link import('./factories.js').createWorkflowContract} gate before running.
3020
+ */
3021
+ export declare interface WorkflowSteps {
3022
+ readonly name?: string;
3023
+ readonly steps: readonly WorkflowStep[];
3024
+ }
3025
+
3026
+ /**
3027
+ * The FLAT authoring shape `createWorkflowTool` advertises as its `parameters` — the
3028
+ * simplest surface a small model can fill: `{ name?, steps: [{ name, via? }] }`.
3029
+ *
3030
+ * @remarks
3031
+ * The deliberately-reduced surface (AGENTS §21): a flat ordered list of steps, each a
3032
+ * `{ name, via? }`. The tool EXPANDS it ({@link import('./helpers.js').expandSteps}) into a
3033
+ * full {@link import('./types.js').WorkflowDefinition} — one one-task phase per step, in
3034
+ * order — then validates against the STRICT
3035
+ * {@link import('./factories.js').createWorkflowContract} gate. The full nested form is
3036
+ * STILL accepted by the tool (it branches on the args' shape) and is documented as the
3037
+ * advanced escape-hatch in the tool's description — but THIS is what `parameters` advertises.
3038
+ */
3039
+ export declare const workflowStepsShape: ObjectShape<{
3040
+ name: OptionalShape<StringShape>;
3041
+ steps: ArrayShape<ObjectShape<{
3042
+ name: StringShape;
3043
+ via: OptionalShape<LiteralShape<readonly ["function", "tool", "agent"]>>;
3044
+ }>>;
3045
+ }>;
3046
+
3047
+ /**
3048
+ * The durable persistence seam for a {@link WorkflowSnapshot} — three async primitives
3049
+ * (`get` / `set` / `delete`) keyed by a workflow id, the snapshot analogue of
3050
+ * the server package's `SessionStoreInterface` (and the
3051
+ * {@link QueueStoreInterface} driver-swap pattern).
3052
+ *
3053
+ * @remarks
3054
+ * The store persists the W-a {@link WorkflowSnapshot} — the COMPLETE, self-contained,
3055
+ * pure-JSON run state — so a JSON / SQLite / IndexedDB backend swaps in WITHOUT touching the
3056
+ * runner or the entity tree: the in-memory default
3057
+ * {@link import('./stores/MemoryWorkflowStore.js').MemoryWorkflowStore} and its driver-pluggable
3058
+ * twin {@link import('./stores/DatabaseWorkflowStore.js').DatabaseWorkflowStore} (the snapshot as
3059
+ * one opaque JSON column) share THIS one interface. Restore is NOT a store concern — a caller reads
3060
+ * a snapshot back and rebuilds the live tree with the shipped {@link import('./factories.js').restoreWorkflow}.
3061
+ *
3062
+ * Every primitive is async (a `Promise`), so a durable backend (a database round-trip) fits the
3063
+ * same shape as the memory one. The snapshot carries its OWN id, so `set` takes no separate id
3064
+ * param (mirroring {@link QueueStoreInterface.save} / the server package's
3065
+ * `SessionStoreInterface.set`, which key off the value's own
3066
+ * `id`). UNLIKE a session store there is NO idle-TTL / eviction — a persisted workflow run-state
3067
+ * lives until an explicit `delete`, never silently expiring (it is durable orchestration state,
3068
+ * not an ephemeral session). It is concrete over {@link WorkflowSnapshot} — no generic parameter
3069
+ * (AGENTS §21 minimal-interface), since the snapshot is the ONE payload a workflow store persists.
3070
+ */
3071
+ export declare interface WorkflowStoreInterface {
3072
+ /**
3073
+ * Resolve the persisted snapshot for `id`, or `undefined` if none is stored.
3074
+ *
3075
+ * @param id - The workflow id to resolve (a {@link WorkflowSnapshot.id})
3076
+ * @returns The persisted snapshot, or `undefined` if absent
3077
+ */
3078
+ get(id: string): Promise<WorkflowSnapshot | undefined>;
3079
+ /**
3080
+ * Insert or replace a snapshot under its own `snapshot.id` (no separate id param —
3081
+ * mirroring {@link QueueStoreInterface.save}).
3082
+ *
3083
+ * @param snapshot - The snapshot to store (keyed by its `id`)
3084
+ */
3085
+ set(snapshot: WorkflowSnapshot): Promise<void>;
3086
+ /**
3087
+ * Drop a snapshot by id; an absent id is a no-op (no throw).
3088
+ *
3089
+ * @param id - The workflow id to drop
3090
+ */
3091
+ delete(id: string): Promise<void>;
3092
+ }
3093
+
3094
+ /**
3095
+ * The ancestry identifier of a workflow run — `workflow:<id>`.
3096
+ *
3097
+ * @remarks
3098
+ * The {@link import('./WorkflowRunner.js').WorkflowRunner}'s cycle guard records one of
3099
+ * these per workflow in the current nested run chain (carried on
3100
+ * {@link import('./types.js').WorkflowRunOptions.ancestry}). Tagging the bare id keeps a
3101
+ * workflow id and an {@link agentTag} agent name in ONE namespaced set without collision,
3102
+ * so re-entering a workflow OR an agent already in the chain is a single `includes` check.
3103
+ *
3104
+ * @param id - The workflow definition's `id`
3105
+ * @returns The namespaced ancestry tag (`workflow:<id>`)
3106
+ */
3107
+ export declare function workflowTag(id: string): string;
3108
+
3109
+ /**
3110
+ * The workflow-tool binder — the signature of {@link import('./factories.js').createWorkflowTool},
3111
+ * threaded into the {@link WorkflowRunnerInterface} at construction (W-c2) so the runner can BIND a
3112
+ * depth/cycle-aware workflow tool onto a dispatched subagent.
3113
+ *
3114
+ * @remarks
3115
+ * The runner receives a REFERENCE to `createWorkflowTool` rather than importing it, because
3116
+ * `createWorkflowTool` lives in `factories.ts` which imports the runner CLASS (the
3117
+ * factories→classes direction); importing the factory back into the class would be a cycle. The
3118
+ * factory (which legitimately owns `createWorkflowContract`) is passed as a value at construction,
3119
+ * and the runner invokes it with `this` as the `runner` argument — keeping the cycle-free seam an
3120
+ * explicit, typed contract rather than a hidden dependency.
3121
+ *
3122
+ * @param definition - The workflow the bound tool runs when called with no authored args
3123
+ * @param runner - The runner that executes the (nested) workflow (the runner passes `this`)
3124
+ * @param options - The depth + ancestry the nested workflow runs under (see {@link WorkflowToolOptions})
3125
+ * @returns The bound {@link ToolInterface}
3126
+ */
3127
+ export declare type WorkflowToolBinder = (definition: WorkflowDefinition, runner: WorkflowRunnerInterface, options?: WorkflowToolOptions) => ToolInterface;
3128
+
3129
+ /**
3130
+ * Options for {@link import('./factories.js').createWorkflowTool} — the depth + ancestry the
3131
+ * wrapped {@link WorkflowDefinition} runs the NESTED workflow at when an LLM invokes the tool.
3132
+ *
3133
+ * @remarks
3134
+ * This is the PROPAGATION carrier across the agent/tool boundary. A `Tool`'s handler receives
3135
+ * ONLY the model-supplied `args` (no ambient context, no signal — see
3136
+ * the `@orkestrel/agent` package's `ToolOptions`), so the run's position in the
3137
+ * workflow→agent→workflow chain CANNOT be threaded through a tool call at runtime. Instead the
3138
+ * runner CLOSES it over the tool at BIND time: when it dispatches an `agent` task at depth `D`
3139
+ * with ancestry `A`, it builds the agent's workflow tool with `{ depth: D, ancestry: A }`, so
3140
+ * the handler's closure carries them. On invocation the handler runs the nested workflow at
3141
+ * `depth: D + 1` with `ancestry: A ∪ { workflow:<id> }` — bounded by
3142
+ * {@link import('./constants.js').MAX_WORKFLOW_DEPTH} (an over-deep / cyclic nested run THROWS a
3143
+ * typed `DEPTH` {@link import('./errors.js').WorkflowError}, which the `ToolManager` isolates into
3144
+ * the tool result's top-level `error`, AGENTS §14).
3145
+ *
3146
+ * Both fields are OPTIONAL: a workflow tool built for a TOP-LEVEL caller (not by the runner's
3147
+ * agent-task binding) omits them — its nested run starts the chain at depth `1` with the bare
3148
+ * `workflow:<id>` ancestry.
3149
+ */
3150
+ export declare interface WorkflowToolOptions {
3151
+ /** The depth the INVOKING agent runs at; the nested workflow runs at `depth + 1`. Default `0`. */
3152
+ readonly depth?: number;
3153
+ /** The ancestry of the invoking run; the nested run extends it with its own `workflow:<id>`. Default empty. */
3154
+ readonly ancestry?: readonly string[];
3155
+ }
3156
+
3157
+ /**
3158
+ * Summarize a terminal {@link WorkflowResult} into the PLAIN value a
3159
+ * {@link import('./factories.js').createWorkflowTool} handler returns on success.
3160
+ *
3161
+ * @remarks
3162
+ * This is the run summary the handler returns DIRECTLY — NOT a `ToolResult` (the future `@orkestrel/agent` package).
3163
+ * The handler conforms to the universal tool-handler contract (AGENTS §14): it returns the plain value
3164
+ * (and throws on failure), so the `@orkestrel/agent` package's `ToolManager` performs
3165
+ * the ONE canonical wrap (`{ id, name, value }`) and the model reads exactly this summary — once,
3166
+ * identically — over BOTH the agent loop and MCP. The summary is LEAN: the workflow's terminal `status`
3167
+ * and the COUNT of settled task results — enough for a caller / model to react without serializing the
3168
+ * whole live tree. (It carries no synthetic `id` / `name`: a tool handler has no call id; the manager
3169
+ * supplies the canonical envelope's identity.)
3170
+ *
3171
+ * @param result - The terminal {@link WorkflowResult} the run produced
3172
+ * @returns The plain success summary — `{ status, count }`
3173
+ */
3174
+ export declare function workflowToolSummary(result: WorkflowResult): Readonly<{
3175
+ status: WorkflowStatus;
3176
+ count: number;
3177
+ }>;
3178
+
3179
+ export { }