@particle-academy/fancy-flow 0.14.0 → 0.15.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.
Files changed (42) hide show
  1. package/README.md +48 -0
  2. package/dist/{capabilities-D-V9Rxv1.d.cts → capabilities-BEbLqnJU.d.cts} +1 -1
  3. package/dist/{capabilities-B6r1Snfj.d.ts → capabilities-CI3gw0C7.d.ts} +1 -1
  4. package/dist/chunk-UEOE6B52.js +39 -0
  5. package/dist/chunk-UEOE6B52.js.map +1 -0
  6. package/dist/{chunk-7U3EP4Q5.js → chunk-ZQBWPYTI.js} +5 -2
  7. package/dist/chunk-ZQBWPYTI.js.map +1 -0
  8. package/dist/engine.cjs +299 -0
  9. package/dist/engine.cjs.map +1 -1
  10. package/dist/engine.d.cts +205 -27
  11. package/dist/engine.d.ts +205 -27
  12. package/dist/engine.js +258 -2
  13. package/dist/engine.js.map +1 -1
  14. package/dist/index.cjs +45 -0
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +7 -6
  17. package/dist/index.d.ts +7 -6
  18. package/dist/index.js +3 -2
  19. package/dist/index.js.map +1 -1
  20. package/dist/llm/vercel-ai.d.cts +2 -2
  21. package/dist/llm/vercel-ai.d.ts +2 -2
  22. package/dist/pause-9iT4tCEV.d.cts +96 -0
  23. package/dist/pause-9iT4tCEV.d.ts +96 -0
  24. package/dist/registry/index.d.cts +6 -5
  25. package/dist/registry/index.d.ts +6 -5
  26. package/dist/registry.cjs +45 -0
  27. package/dist/registry.cjs.map +1 -1
  28. package/dist/registry.js +2 -1
  29. package/dist/run-flow-ChBi6q-W.d.ts +35 -0
  30. package/dist/run-flow-VKm57Hcj.d.cts +35 -0
  31. package/dist/runtime/index.d.cts +3 -3
  32. package/dist/runtime/index.d.ts +3 -3
  33. package/dist/schema/index.d.cts +1 -1
  34. package/dist/schema/index.d.ts +1 -1
  35. package/dist/{types-H60tQAxr.d.cts → types-D_jOR3Z2.d.cts} +12 -1
  36. package/dist/{types-CnnKPnpt.d.ts → types-NerkPtHS.d.ts} +12 -1
  37. package/dist/{types-fc0fFKkf.d.cts → types-sOmpCitB.d.cts} +1 -1
  38. package/dist/{types-fc0fFKkf.d.ts → types-sOmpCitB.d.ts} +1 -1
  39. package/dist/ux.d.cts +3 -2
  40. package/dist/ux.d.ts +3 -2
  41. package/package.json +1 -1
  42. package/dist/chunk-7U3EP4Q5.js.map +0 -1
package/dist/engine.d.cts CHANGED
@@ -1,37 +1,215 @@
1
- import { F as FlowGraph, E as ExecutorRegistry, R as RunEvent } from './types-fc0fFKkf.cjs';
2
- export { A as ActionNodeData, B as BaseNodeData, D as DecisionNodeData, c as FlowEdge, a as FlowNode, d as FlowNodeData, e as FlowNodeKind, N as NodeExecutor, b as NodeRunStatus, f as NoteNodeData, O as OutputNodeData, P as PortDescriptor, S as SubgraphNodeData, T as TriggerNodeData } from './types-fc0fFKkf.cjs';
1
+ export { R as RunOptions, a as RunResult, r as runFlow } from './run-flow-VKm57Hcj.cjs';
2
+ import { N as NodeExecutor } from './types-sOmpCitB.cjs';
3
+ export { A as ActionNodeData, B as BaseNodeData, D as DecisionNodeData, E as ExecutorRegistry, a as FlowEdge, F as FlowGraph, b as FlowNode, c as FlowNodeData, d as FlowNodeKind, e as NodeRunStatus, f as NoteNodeData, O as OutputNodeData, P as PortDescriptor, R as RunEvent, S as SubgraphNodeData, T as TriggerNodeData } from './types-sOmpCitB.cjs';
4
+ import { P as PauseAwaiting } from './pause-9iT4tCEV.cjs';
5
+ export { L as LEGACY_PAUSE_PREFIXES, a as PAUSE_PREFIX, b as PauseSignal, d as decodePause, e as encodePause, i as isPause, p as pauseForHuman } from './pause-9iT4tCEV.cjs';
3
6
  import '@xyflow/react';
4
7
 
5
- type RunOptions = {
6
- /** Stop the run after this many ms. Default: no timeout. */
7
- timeoutMs?: number;
8
- /** Abort signal host can cancel the run. */
9
- signal?: AbortSignal;
10
- /** Initial inputs supplied to entry-point nodes (no incoming edges). */
11
- initialInputs?: Record<string, Record<string, unknown>>;
12
- /** Nesting depth — set by `subflow` when it runs a child graph. */
13
- depth?: number;
14
- };
15
- type RunResult = {
8
+ /**
9
+ * The node package manifest what a marketplace node declares about itself.
10
+ *
11
+ * A node is not one artifact. It is a kind definition (palette entry, config
12
+ * schema, ports, canvas renderer) plus an executor for EACH runtime the
13
+ * consumer actually runs. A package shipping only a TS executor is unusable to
14
+ * anyone executing on PHP, and today that is invisible until a run fails.
15
+ *
16
+ * So the manifest states which runtimes it implements, and the CLI checks that
17
+ * against the host before installing rather than after. Requested by the MOIC
18
+ * Suite consumer (fancy-flow#2 §2), who runs the editor in TS and executes in
19
+ * PHP and hit exactly this.
20
+ *
21
+ * The manifest is data, not code: the registry, the CLI, and the MCP all read
22
+ * it without executing anything a package author wrote.
23
+ */
24
+
25
+ /** The current manifest schema version. Bump only on a breaking shape change. */
26
+ declare const NODE_MANIFEST_SCHEMA_VERSION = 1;
27
+ /**
28
+ * A runtime a node can implement.
29
+ *
30
+ * Open rather than a closed union — the PHP and Node twins are what exist
31
+ * today, but the point of a manifest is that a runtime we haven't written can
32
+ * declare itself without a release here.
33
+ */
34
+ type NodeRuntimeId = "ts" | "php" | (string & {});
35
+ type NodePackageManifest = {
36
+ /** Must equal `NODE_MANIFEST_SCHEMA_VERSION`. */
37
+ schemaVersion: number;
38
+ /** Package name, as installed (`@acme/fancy-flow-salesforce`). */
39
+ name: string;
40
+ /**
41
+ * The canonical kind id this package provides — namespaced, and the string
42
+ * that gets persisted into every document using it.
43
+ */
44
+ kind: string;
45
+ /** Semver range of fancy-flow this node's contract targets. */
46
+ fancyFlow: string;
47
+ /**
48
+ * Per-runtime entrypoints. TS is a module path within the package; PHP is a
49
+ * Composer requirement, because the two ecosystems install differently and
50
+ * pretending otherwise just moves the problem into the CLI.
51
+ */
52
+ runtimes: Partial<Record<NodeRuntimeId, string>>;
53
+ /**
54
+ * Host capabilities this node needs wired before it can run — `llm`,
55
+ * `workflow_resolver`, `document`, or a host-specific one.
56
+ *
57
+ * Declared so the CLI can tell an author what to wire BEFORE install, rather
58
+ * than the node silently no-opping or crashing mid-run.
59
+ */
60
+ capabilities?: string[];
61
+ /**
62
+ * Path to this node's golden fixtures, relative to the package root.
63
+ *
64
+ * REQUIRED. Every runtime the package claims runs these same cases, which is
65
+ * what makes "behaves identically on both runtimes" verified rather than
66
+ * asserted. See `./fixtures`.
67
+ */
68
+ fixtures: string;
69
+ /** Declares the node halts for a person. Mirrors `NodeKindDefinition`. */
70
+ pausesForHuman?: PauseAwaiting;
71
+ /** One-line summary — what `search_nodes` matches against. */
72
+ description?: string;
73
+ /**
74
+ * Assigned by the registry, never by the author. Present in a manifest being
75
+ * submitted for publication, it is a claim to a trust signal the author does
76
+ * not get to make.
77
+ */
78
+ verified?: boolean;
79
+ };
80
+ type ManifestProblem = {
81
+ level: "error" | "warning";
82
+ field: string;
83
+ message: string;
84
+ };
85
+ type ManifestValidation = {
86
+ /** True when there are no `error`-level problems. Warnings do not block. */
16
87
  ok: boolean;
17
- /** Outputs collected per node, keyed by node id. */
18
- outputs: Record<string, unknown>;
19
- /** Error captured if any node threw. */
20
- error?: string;
88
+ manifest?: NodePackageManifest;
89
+ problems: ManifestProblem[];
21
90
  };
22
91
  /**
23
- * runFlow topological execution of a FlowGraph against an ExecutorRegistry.
92
+ * Validate a manifest read from disk or a registry.
93
+ *
94
+ * Returns every problem rather than throwing on the first, because an author
95
+ * fixing a package wants the whole list — a validator that reveals one error
96
+ * per run turns a five-minute fix into five round trips.
97
+ */
98
+ declare function validateNodeManifest(input: unknown): ManifestValidation;
99
+ /**
100
+ * Check a node against the runtimes a host actually executes on.
101
+ *
102
+ * This is what makes a TS-only package visible to someone running PHP BEFORE
103
+ * they install it rather than at the first run. A missing runtime is an error,
104
+ * not a warning: the node genuinely cannot execute there.
105
+ */
106
+ declare function checkRuntimeSupport(manifest: Pick<NodePackageManifest, "kind" | "runtimes">, hostRuntimes: readonly string[]): ManifestProblem[];
107
+ /**
108
+ * Check that every capability a node needs is actually wired.
109
+ *
110
+ * Pass `capabilityStatus()` from the host. Unwired capabilities are a warning
111
+ * rather than an error — install is the right time to learn what to wire, not
112
+ * a reason to refuse, since wiring usually happens after install.
113
+ */
114
+ declare function checkCapabilities(manifest: Pick<NodePackageManifest, "kind" | "capabilities">, available: Readonly<Record<string, boolean>>): ManifestProblem[];
115
+
116
+ /**
117
+ * Golden fixtures — the parity guarantee, and a publishing requirement.
118
+ *
119
+ * Every runtime a node package claims runs these same JSON cases. That is what
120
+ * makes "this node behaves identically on TS and PHP" verified rather than
121
+ * asserted, and it is the one thing a loose collection of repos can never
122
+ * offer.
123
+ *
124
+ * WHY IT IS REQUIRED RATHER THAN ENCOURAGED: cross-runtime drift does not fail
125
+ * loudly. The 0.9.0 port-resolution divergence produced flows that routed
126
+ * correctly in the editor and silently down one path on the server — status
127
+ * `completed`, no error, no exception, nothing to alert on. A guarantee that
128
+ * only holds when an author opts in is not a guarantee.
24
129
  *
25
- * Each node runs once, when all upstream nodes have produced outputs on the
26
- * connected ports. Decision nodes (or any executor that returns `{ branch:
27
- * 'true' }`) can short-circuit specific output ports — only edges leaving
28
- * an "active" port propagate to downstream nodes.
130
+ * WHAT A CASE ASSERTS, and why it matters more than it looks:
29
131
  *
30
- * Cycles are detected and abort the run with an error.
132
+ * A fixture asserts THE DOWNSTREAM NODE EXECUTED — not the port the node
133
+ * recorded. The distinction is the whole lesson of that incident. A test
134
+ * reading back `outputs.router.__port` stays green while no edge fires and
135
+ * the run halts at the branch: the node faithfully recorded its choice, and
136
+ * nothing downstream ever ran. So the runner wires a real probe to every
137
+ * declared port and reports which probes actually executed.
138
+ *
139
+ * The format is plain JSON with no expressions or callbacks, so the PHP runner
140
+ * executes byte-identical cases without an embedded JS engine.
141
+ */
142
+
143
+ /** What a case expects to have happened. */
144
+ type FixtureExpectation = {
145
+ /**
146
+ * Output ports whose downstream node must have executed — the assertion that
147
+ * catches routing drift. Order-insensitive; the set must match exactly, so a
148
+ * node that fires an extra port fails just as loudly as one that fires none.
149
+ */
150
+ ports?: string[];
151
+ /** The value carried downstream, deep-compared when present. */
152
+ value?: unknown;
153
+ /** The run halted for a person. */
154
+ pause?: {
155
+ awaiting: PauseAwaiting;
156
+ detail?: unknown;
157
+ };
158
+ /** The run failed, and the message contains this substring. */
159
+ error?: string;
160
+ };
161
+ type FixtureCase = {
162
+ /** Human-readable, and what a failure report names. */
163
+ name: string;
164
+ /** Config for the node under test — drives config-derived ports. */
165
+ config?: Record<string, unknown>;
166
+ /**
167
+ * The node's resolved output ports, stated rather than derived.
168
+ *
169
+ * NOT a convenience. TS derives config-driven ports by running a JavaScript
170
+ * function (`switch_case`'s cases, `llm_router`'s routes); PHP cannot, and
171
+ * falls back to the kind's static declaration. Left there, the identical
172
+ * fixture would build a DIFFERENT graph on each runtime — the fixtures would
173
+ * silently stop comparing like with like, which is the exact failure they
174
+ * exist to catch.
175
+ *
176
+ * So a case states its ports the same way an exported document does (see
177
+ * 0.10.1, "serialize resolved ports"), and both runners honour it. Omit it
178
+ * only for a node whose ports are static.
179
+ */
180
+ ports?: string[];
181
+ /** Inputs delivered on the node's input ports. */
182
+ inputs?: Record<string, unknown>;
183
+ expect: FixtureExpectation;
184
+ };
185
+ type FixtureFile = {
186
+ /** The kind under test. Must match the manifest's `kind`. */
187
+ kind: string;
188
+ cases: FixtureCase[];
189
+ };
190
+ type FixtureFailure = {
191
+ case: string;
192
+ message: string;
193
+ };
194
+ type FixtureRunResult = {
195
+ ok: boolean;
196
+ passed: number;
197
+ failures: FixtureFailure[];
198
+ };
199
+ /**
200
+ * Run one fixture file against a kind's executor.
201
+ *
202
+ * `executor` is the node's own; everything else in the graph is supplied here,
203
+ * so a case exercises the node and nothing but the node.
204
+ */
205
+ declare function runFixtures(file: FixtureFile, executor: NodeExecutor): Promise<FixtureRunResult>;
206
+ /**
207
+ * Validate a fixture file's shape before running it.
31
208
  *
32
- * The `onEvent` callback receives a stream of `RunEvent`s wire it to a
33
- * status feed, log panel, or store.
209
+ * A package that publishes an empty or malformed fixture file has satisfied the
210
+ * letter of the requirement and none of its purpose, so this is checked at
211
+ * publish rather than trusted.
34
212
  */
35
- declare function runFlow(graph: FlowGraph, executors: ExecutorRegistry, onEvent?: (event: RunEvent) => void, options?: RunOptions): Promise<RunResult>;
213
+ declare function validateFixtureFile(input: unknown, expectedKind?: string): string[];
36
214
 
37
- export { ExecutorRegistry, FlowGraph, RunEvent, type RunOptions, type RunResult, runFlow };
215
+ export { type FixtureCase, type FixtureExpectation, type FixtureFailure, type FixtureFile, type FixtureRunResult, type ManifestProblem, type ManifestValidation, NODE_MANIFEST_SCHEMA_VERSION, NodeExecutor, type NodePackageManifest, type NodeRuntimeId, PauseAwaiting, checkCapabilities, checkRuntimeSupport, runFixtures, validateFixtureFile, validateNodeManifest };
package/dist/engine.d.ts CHANGED
@@ -1,37 +1,215 @@
1
- import { F as FlowGraph, E as ExecutorRegistry, R as RunEvent } from './types-fc0fFKkf.js';
2
- export { A as ActionNodeData, B as BaseNodeData, D as DecisionNodeData, c as FlowEdge, a as FlowNode, d as FlowNodeData, e as FlowNodeKind, N as NodeExecutor, b as NodeRunStatus, f as NoteNodeData, O as OutputNodeData, P as PortDescriptor, S as SubgraphNodeData, T as TriggerNodeData } from './types-fc0fFKkf.js';
1
+ export { R as RunOptions, a as RunResult, r as runFlow } from './run-flow-ChBi6q-W.js';
2
+ import { N as NodeExecutor } from './types-sOmpCitB.js';
3
+ export { A as ActionNodeData, B as BaseNodeData, D as DecisionNodeData, E as ExecutorRegistry, a as FlowEdge, F as FlowGraph, b as FlowNode, c as FlowNodeData, d as FlowNodeKind, e as NodeRunStatus, f as NoteNodeData, O as OutputNodeData, P as PortDescriptor, R as RunEvent, S as SubgraphNodeData, T as TriggerNodeData } from './types-sOmpCitB.js';
4
+ import { P as PauseAwaiting } from './pause-9iT4tCEV.js';
5
+ export { L as LEGACY_PAUSE_PREFIXES, a as PAUSE_PREFIX, b as PauseSignal, d as decodePause, e as encodePause, i as isPause, p as pauseForHuman } from './pause-9iT4tCEV.js';
3
6
  import '@xyflow/react';
4
7
 
5
- type RunOptions = {
6
- /** Stop the run after this many ms. Default: no timeout. */
7
- timeoutMs?: number;
8
- /** Abort signal host can cancel the run. */
9
- signal?: AbortSignal;
10
- /** Initial inputs supplied to entry-point nodes (no incoming edges). */
11
- initialInputs?: Record<string, Record<string, unknown>>;
12
- /** Nesting depth — set by `subflow` when it runs a child graph. */
13
- depth?: number;
14
- };
15
- type RunResult = {
8
+ /**
9
+ * The node package manifest what a marketplace node declares about itself.
10
+ *
11
+ * A node is not one artifact. It is a kind definition (palette entry, config
12
+ * schema, ports, canvas renderer) plus an executor for EACH runtime the
13
+ * consumer actually runs. A package shipping only a TS executor is unusable to
14
+ * anyone executing on PHP, and today that is invisible until a run fails.
15
+ *
16
+ * So the manifest states which runtimes it implements, and the CLI checks that
17
+ * against the host before installing rather than after. Requested by the MOIC
18
+ * Suite consumer (fancy-flow#2 §2), who runs the editor in TS and executes in
19
+ * PHP and hit exactly this.
20
+ *
21
+ * The manifest is data, not code: the registry, the CLI, and the MCP all read
22
+ * it without executing anything a package author wrote.
23
+ */
24
+
25
+ /** The current manifest schema version. Bump only on a breaking shape change. */
26
+ declare const NODE_MANIFEST_SCHEMA_VERSION = 1;
27
+ /**
28
+ * A runtime a node can implement.
29
+ *
30
+ * Open rather than a closed union — the PHP and Node twins are what exist
31
+ * today, but the point of a manifest is that a runtime we haven't written can
32
+ * declare itself without a release here.
33
+ */
34
+ type NodeRuntimeId = "ts" | "php" | (string & {});
35
+ type NodePackageManifest = {
36
+ /** Must equal `NODE_MANIFEST_SCHEMA_VERSION`. */
37
+ schemaVersion: number;
38
+ /** Package name, as installed (`@acme/fancy-flow-salesforce`). */
39
+ name: string;
40
+ /**
41
+ * The canonical kind id this package provides — namespaced, and the string
42
+ * that gets persisted into every document using it.
43
+ */
44
+ kind: string;
45
+ /** Semver range of fancy-flow this node's contract targets. */
46
+ fancyFlow: string;
47
+ /**
48
+ * Per-runtime entrypoints. TS is a module path within the package; PHP is a
49
+ * Composer requirement, because the two ecosystems install differently and
50
+ * pretending otherwise just moves the problem into the CLI.
51
+ */
52
+ runtimes: Partial<Record<NodeRuntimeId, string>>;
53
+ /**
54
+ * Host capabilities this node needs wired before it can run — `llm`,
55
+ * `workflow_resolver`, `document`, or a host-specific one.
56
+ *
57
+ * Declared so the CLI can tell an author what to wire BEFORE install, rather
58
+ * than the node silently no-opping or crashing mid-run.
59
+ */
60
+ capabilities?: string[];
61
+ /**
62
+ * Path to this node's golden fixtures, relative to the package root.
63
+ *
64
+ * REQUIRED. Every runtime the package claims runs these same cases, which is
65
+ * what makes "behaves identically on both runtimes" verified rather than
66
+ * asserted. See `./fixtures`.
67
+ */
68
+ fixtures: string;
69
+ /** Declares the node halts for a person. Mirrors `NodeKindDefinition`. */
70
+ pausesForHuman?: PauseAwaiting;
71
+ /** One-line summary — what `search_nodes` matches against. */
72
+ description?: string;
73
+ /**
74
+ * Assigned by the registry, never by the author. Present in a manifest being
75
+ * submitted for publication, it is a claim to a trust signal the author does
76
+ * not get to make.
77
+ */
78
+ verified?: boolean;
79
+ };
80
+ type ManifestProblem = {
81
+ level: "error" | "warning";
82
+ field: string;
83
+ message: string;
84
+ };
85
+ type ManifestValidation = {
86
+ /** True when there are no `error`-level problems. Warnings do not block. */
16
87
  ok: boolean;
17
- /** Outputs collected per node, keyed by node id. */
18
- outputs: Record<string, unknown>;
19
- /** Error captured if any node threw. */
20
- error?: string;
88
+ manifest?: NodePackageManifest;
89
+ problems: ManifestProblem[];
21
90
  };
22
91
  /**
23
- * runFlow topological execution of a FlowGraph against an ExecutorRegistry.
92
+ * Validate a manifest read from disk or a registry.
93
+ *
94
+ * Returns every problem rather than throwing on the first, because an author
95
+ * fixing a package wants the whole list — a validator that reveals one error
96
+ * per run turns a five-minute fix into five round trips.
97
+ */
98
+ declare function validateNodeManifest(input: unknown): ManifestValidation;
99
+ /**
100
+ * Check a node against the runtimes a host actually executes on.
101
+ *
102
+ * This is what makes a TS-only package visible to someone running PHP BEFORE
103
+ * they install it rather than at the first run. A missing runtime is an error,
104
+ * not a warning: the node genuinely cannot execute there.
105
+ */
106
+ declare function checkRuntimeSupport(manifest: Pick<NodePackageManifest, "kind" | "runtimes">, hostRuntimes: readonly string[]): ManifestProblem[];
107
+ /**
108
+ * Check that every capability a node needs is actually wired.
109
+ *
110
+ * Pass `capabilityStatus()` from the host. Unwired capabilities are a warning
111
+ * rather than an error — install is the right time to learn what to wire, not
112
+ * a reason to refuse, since wiring usually happens after install.
113
+ */
114
+ declare function checkCapabilities(manifest: Pick<NodePackageManifest, "kind" | "capabilities">, available: Readonly<Record<string, boolean>>): ManifestProblem[];
115
+
116
+ /**
117
+ * Golden fixtures — the parity guarantee, and a publishing requirement.
118
+ *
119
+ * Every runtime a node package claims runs these same JSON cases. That is what
120
+ * makes "this node behaves identically on TS and PHP" verified rather than
121
+ * asserted, and it is the one thing a loose collection of repos can never
122
+ * offer.
123
+ *
124
+ * WHY IT IS REQUIRED RATHER THAN ENCOURAGED: cross-runtime drift does not fail
125
+ * loudly. The 0.9.0 port-resolution divergence produced flows that routed
126
+ * correctly in the editor and silently down one path on the server — status
127
+ * `completed`, no error, no exception, nothing to alert on. A guarantee that
128
+ * only holds when an author opts in is not a guarantee.
24
129
  *
25
- * Each node runs once, when all upstream nodes have produced outputs on the
26
- * connected ports. Decision nodes (or any executor that returns `{ branch:
27
- * 'true' }`) can short-circuit specific output ports — only edges leaving
28
- * an "active" port propagate to downstream nodes.
130
+ * WHAT A CASE ASSERTS, and why it matters more than it looks:
29
131
  *
30
- * Cycles are detected and abort the run with an error.
132
+ * A fixture asserts THE DOWNSTREAM NODE EXECUTED — not the port the node
133
+ * recorded. The distinction is the whole lesson of that incident. A test
134
+ * reading back `outputs.router.__port` stays green while no edge fires and
135
+ * the run halts at the branch: the node faithfully recorded its choice, and
136
+ * nothing downstream ever ran. So the runner wires a real probe to every
137
+ * declared port and reports which probes actually executed.
138
+ *
139
+ * The format is plain JSON with no expressions or callbacks, so the PHP runner
140
+ * executes byte-identical cases without an embedded JS engine.
141
+ */
142
+
143
+ /** What a case expects to have happened. */
144
+ type FixtureExpectation = {
145
+ /**
146
+ * Output ports whose downstream node must have executed — the assertion that
147
+ * catches routing drift. Order-insensitive; the set must match exactly, so a
148
+ * node that fires an extra port fails just as loudly as one that fires none.
149
+ */
150
+ ports?: string[];
151
+ /** The value carried downstream, deep-compared when present. */
152
+ value?: unknown;
153
+ /** The run halted for a person. */
154
+ pause?: {
155
+ awaiting: PauseAwaiting;
156
+ detail?: unknown;
157
+ };
158
+ /** The run failed, and the message contains this substring. */
159
+ error?: string;
160
+ };
161
+ type FixtureCase = {
162
+ /** Human-readable, and what a failure report names. */
163
+ name: string;
164
+ /** Config for the node under test — drives config-derived ports. */
165
+ config?: Record<string, unknown>;
166
+ /**
167
+ * The node's resolved output ports, stated rather than derived.
168
+ *
169
+ * NOT a convenience. TS derives config-driven ports by running a JavaScript
170
+ * function (`switch_case`'s cases, `llm_router`'s routes); PHP cannot, and
171
+ * falls back to the kind's static declaration. Left there, the identical
172
+ * fixture would build a DIFFERENT graph on each runtime — the fixtures would
173
+ * silently stop comparing like with like, which is the exact failure they
174
+ * exist to catch.
175
+ *
176
+ * So a case states its ports the same way an exported document does (see
177
+ * 0.10.1, "serialize resolved ports"), and both runners honour it. Omit it
178
+ * only for a node whose ports are static.
179
+ */
180
+ ports?: string[];
181
+ /** Inputs delivered on the node's input ports. */
182
+ inputs?: Record<string, unknown>;
183
+ expect: FixtureExpectation;
184
+ };
185
+ type FixtureFile = {
186
+ /** The kind under test. Must match the manifest's `kind`. */
187
+ kind: string;
188
+ cases: FixtureCase[];
189
+ };
190
+ type FixtureFailure = {
191
+ case: string;
192
+ message: string;
193
+ };
194
+ type FixtureRunResult = {
195
+ ok: boolean;
196
+ passed: number;
197
+ failures: FixtureFailure[];
198
+ };
199
+ /**
200
+ * Run one fixture file against a kind's executor.
201
+ *
202
+ * `executor` is the node's own; everything else in the graph is supplied here,
203
+ * so a case exercises the node and nothing but the node.
204
+ */
205
+ declare function runFixtures(file: FixtureFile, executor: NodeExecutor): Promise<FixtureRunResult>;
206
+ /**
207
+ * Validate a fixture file's shape before running it.
31
208
  *
32
- * The `onEvent` callback receives a stream of `RunEvent`s wire it to a
33
- * status feed, log panel, or store.
209
+ * A package that publishes an empty or malformed fixture file has satisfied the
210
+ * letter of the requirement and none of its purpose, so this is checked at
211
+ * publish rather than trusted.
34
212
  */
35
- declare function runFlow(graph: FlowGraph, executors: ExecutorRegistry, onEvent?: (event: RunEvent) => void, options?: RunOptions): Promise<RunResult>;
213
+ declare function validateFixtureFile(input: unknown, expectedKind?: string): string[];
36
214
 
37
- export { ExecutorRegistry, FlowGraph, RunEvent, type RunOptions, type RunResult, runFlow };
215
+ export { type FixtureCase, type FixtureExpectation, type FixtureFailure, type FixtureFile, type FixtureRunResult, type ManifestProblem, type ManifestValidation, NODE_MANIFEST_SCHEMA_VERSION, NodeExecutor, type NodePackageManifest, type NodeRuntimeId, PauseAwaiting, checkCapabilities, checkRuntimeSupport, runFixtures, validateFixtureFile, validateNodeManifest };