@particle-academy/fancy-flow 0.15.1 → 0.16.0
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.
- package/dist/{capabilities-BEbLqnJU.d.cts → capabilities-ChE3Xi8R.d.cts} +40 -5
- package/dist/{capabilities-CI3gw0C7.d.ts → capabilities-DUhAc-EJ.d.ts} +40 -5
- package/dist/{chunk-ZQBWPYTI.js → chunk-M2QTDA3B.js} +17 -4
- package/dist/chunk-M2QTDA3B.js.map +1 -0
- package/dist/{chunk-BB45F6S3.js → chunk-USL4FMFU.js} +6 -3
- package/dist/chunk-USL4FMFU.js.map +1 -0
- package/dist/engine.cjs +272 -48
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.d.cts +167 -32
- package/dist/engine.d.ts +167 -32
- package/dist/engine.js +265 -49
- package/dist/engine.js.map +1 -1
- package/dist/index.cjs +17 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -3
- package/dist/llm/vercel-ai.cjs.map +1 -1
- package/dist/llm/vercel-ai.d.cts +1 -1
- package/dist/llm/vercel-ai.d.ts +1 -1
- package/dist/llm/vercel-ai.js +1 -1
- package/dist/registry/index.d.cts +2 -2
- package/dist/registry/index.d.ts +2 -2
- package/dist/registry.cjs +18 -1
- package/dist/registry.cjs.map +1 -1
- package/dist/registry.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-BB45F6S3.js.map +0 -1
- package/dist/chunk-ZQBWPYTI.js.map +0 -1
package/dist/engine.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
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,
|
|
2
|
+
import { F as FlowGraph, R as RunEvent, N as NodeExecutor } from './types-sOmpCitB.cjs';
|
|
3
|
+
export { A as ActionNodeData, B as BaseNodeData, D as DecisionNodeData, E as ExecutorRegistry, a as FlowEdge, b as FlowNode, c as FlowNodeData, d as FlowNodeKind, e as NodeRunStatus, f as NoteNodeData, O as OutputNodeData, P as PortDescriptor, S as SubgraphNodeData, T as TriggerNodeData } from './types-sOmpCitB.cjs';
|
|
4
4
|
import { P as PauseAwaiting } from './pause-9iT4tCEV.cjs';
|
|
5
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';
|
|
6
6
|
import '@xyflow/react';
|
|
@@ -9,17 +9,22 @@ import '@xyflow/react';
|
|
|
9
9
|
* The node package manifest — what a marketplace node declares about itself.
|
|
10
10
|
*
|
|
11
11
|
* A node is not one artifact. It is a kind definition (palette entry, config
|
|
12
|
-
* schema, ports,
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
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.
|
|
12
|
+
* schema, ports, renderer) plus an executor for EACH runtime the consumer runs.
|
|
13
|
+
* A package shipping only a TS executor is unusable to anyone executing on PHP,
|
|
14
|
+
* and without a manifest that is invisible until a run fails. Requested by the
|
|
15
|
+
* MOIC Suite consumer (fancy-flow#2 §2), who runs the editor in TS and executes
|
|
16
|
+
* in PHP and hit exactly this.
|
|
20
17
|
*
|
|
21
18
|
* The manifest is data, not code: the registry, the CLI, and the MCP all read
|
|
22
19
|
* it without executing anything a package author wrote.
|
|
20
|
+
*
|
|
21
|
+
* ## Why the engine range lives per runtime
|
|
22
|
+
*
|
|
23
|
+
* The first cut of this manifest carried ONE `fancyFlow` range, and it was
|
|
24
|
+
* wrong: the two engines version independently, so a single range cannot say
|
|
25
|
+
* "needs npm >=0.11 AND php >=0.5". A package supporting both runtimes would
|
|
26
|
+
* install cleanly against a host whose OTHER runtime was too old — the 0.9.0
|
|
27
|
+
* failure shape wearing a manifest. The range belongs inside each runtime.
|
|
23
28
|
*/
|
|
24
29
|
|
|
25
30
|
/** The current manifest schema version. Bump only on a breaking shape change. */
|
|
@@ -32,6 +37,38 @@ declare const NODE_MANIFEST_SCHEMA_VERSION = 1;
|
|
|
32
37
|
* declare itself without a release here.
|
|
33
38
|
*/
|
|
34
39
|
type NodeRuntimeId = "ts" | "php" | (string & {});
|
|
40
|
+
/**
|
|
41
|
+
* How one runtime provides this node, and which engine version it needs.
|
|
42
|
+
*
|
|
43
|
+
* `entry` and `package` are both here because the two ecosystems install
|
|
44
|
+
* differently — a module path within the package for TS, a Composer
|
|
45
|
+
* requirement for PHP — and pretending otherwise just moves the problem into
|
|
46
|
+
* the CLI. Exactly one is required.
|
|
47
|
+
*/
|
|
48
|
+
type NodeRuntimeSpec = {
|
|
49
|
+
/** Module path within the package (TS-style runtimes). */
|
|
50
|
+
entry?: string;
|
|
51
|
+
/** Dependency requirement resolved by that ecosystem (PHP/Composer-style). */
|
|
52
|
+
package?: string;
|
|
53
|
+
/** Semver range of THIS runtime's engine. Required — see the module note. */
|
|
54
|
+
engine: string;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Whether a capability must be wired for the node to work at all.
|
|
58
|
+
*
|
|
59
|
+
* `required` is checked at AUTHOR time, not run time. The failure that hurts is
|
|
60
|
+
* a node that installs fine, authors fine, and silently no-ops during a run —
|
|
61
|
+
* the same silence as a routing bug. An editor can grey the node and say which
|
|
62
|
+
* capability the host never registered.
|
|
63
|
+
*/
|
|
64
|
+
type CapabilityRequirement = "required" | "optional";
|
|
65
|
+
/**
|
|
66
|
+
* Whether a node is safe to run again.
|
|
67
|
+
*
|
|
68
|
+
* Durable runs RETRY. A node that writes needs to say so, or a host has to pick
|
|
69
|
+
* one retry policy for every node and get it wrong somewhere.
|
|
70
|
+
*/
|
|
71
|
+
type SideEffects = "none" | "idempotent" | "unsafe-to-replay";
|
|
35
72
|
type NodePackageManifest = {
|
|
36
73
|
/** Must equal `NODE_MANIFEST_SCHEMA_VERSION`. */
|
|
37
74
|
schemaVersion: number;
|
|
@@ -42,22 +79,33 @@ type NodePackageManifest = {
|
|
|
42
79
|
* that gets persisted into every document using it.
|
|
43
80
|
*/
|
|
44
81
|
kind: string;
|
|
45
|
-
/** Semver range of fancy-flow this node's contract targets. */
|
|
46
|
-
fancyFlow: string;
|
|
47
82
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
83
|
+
* Previous ids this kind still answers to.
|
|
84
|
+
*
|
|
85
|
+
* Core renamed `llm_branch` to `llm_router` and kept every old id working.
|
|
86
|
+
* Third-party packages will rename too, and their documents break the same
|
|
87
|
+
* way core's would have — so packages get the same escape hatch, otherwise
|
|
88
|
+
* only first-party nodes can rename safely.
|
|
89
|
+
*/
|
|
90
|
+
aliases?: string[];
|
|
91
|
+
/**
|
|
92
|
+
* Version of this node's CONFIG shape, independent of the document schema.
|
|
93
|
+
*
|
|
94
|
+
* A node's config evolves on its own clock. Without a declared version, every
|
|
95
|
+
* executor accretes hand-written read-fallbacks forever (MOIC carries one for
|
|
96
|
+
* `routes[].key` → `routes[].port`), because nothing canonicalises old config
|
|
97
|
+
* the way import canonicalises kind ids.
|
|
51
98
|
*/
|
|
52
|
-
|
|
99
|
+
configVersion?: number;
|
|
100
|
+
/** Per-runtime entrypoints and engine ranges. */
|
|
101
|
+
runtimes: Partial<Record<NodeRuntimeId, NodeRuntimeSpec>>;
|
|
53
102
|
/**
|
|
54
|
-
* Host capabilities this node needs
|
|
55
|
-
* `workflow_resolver`, `document`, or a host-specific one.
|
|
103
|
+
* Host capabilities this node needs, and whether each is mandatory.
|
|
56
104
|
*
|
|
57
|
-
* Declared so the CLI
|
|
58
|
-
* than the node silently no-opping or crashing mid-run.
|
|
105
|
+
* Declared so the CLI and the editor can say what to wire BEFORE a run,
|
|
106
|
+
* rather than the node silently no-opping or crashing mid-run.
|
|
59
107
|
*/
|
|
60
|
-
capabilities?: string
|
|
108
|
+
capabilities?: Record<string, CapabilityRequirement>;
|
|
61
109
|
/**
|
|
62
110
|
* Path to this node's golden fixtures, relative to the package root.
|
|
63
111
|
*
|
|
@@ -66,8 +114,16 @@ type NodePackageManifest = {
|
|
|
66
114
|
* asserted. See `./fixtures`.
|
|
67
115
|
*/
|
|
68
116
|
fixtures: string;
|
|
69
|
-
/**
|
|
117
|
+
/**
|
|
118
|
+
* Declares the node halts for a person. Mirrors `NodeKindDefinition`.
|
|
119
|
+
*
|
|
120
|
+
* A host-planning fact, not a node internal: a parent that embeds workflows
|
|
121
|
+
* needs to reject a child that can pause, because a paused child wedges the
|
|
122
|
+
* parent — and discovering that at run time means watching a run park.
|
|
123
|
+
*/
|
|
70
124
|
pausesForHuman?: PauseAwaiting;
|
|
125
|
+
/** Whether this node is safe to replay. See `SideEffects`. */
|
|
126
|
+
sideEffects?: SideEffects;
|
|
71
127
|
/** One-line summary — what `search_nodes` matches against. */
|
|
72
128
|
description?: string;
|
|
73
129
|
/**
|
|
@@ -97,19 +153,36 @@ type ManifestValidation = {
|
|
|
97
153
|
*/
|
|
98
154
|
declare function validateNodeManifest(input: unknown): ManifestValidation;
|
|
99
155
|
/**
|
|
100
|
-
* Check a node against the runtimes a host
|
|
156
|
+
* Check a node against the runtimes a host executes on, and their versions.
|
|
157
|
+
*
|
|
158
|
+
* Two failures live here, and both are errors because the node genuinely
|
|
159
|
+
* cannot run: a runtime the package does not implement at all, and a runtime
|
|
160
|
+
* it implements against an engine newer than the host's.
|
|
101
161
|
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
* not
|
|
162
|
+
* `engineVersions` is optional — pass what the host knows. An unchecked range
|
|
163
|
+
* is reported as a warning rather than passed over silently, because "we did
|
|
164
|
+
* not check" and "it is fine" must not look the same.
|
|
105
165
|
*/
|
|
106
|
-
declare function checkRuntimeSupport(manifest: Pick<NodePackageManifest, "kind" | "runtimes">, hostRuntimes: readonly string[]): ManifestProblem[];
|
|
166
|
+
declare function checkRuntimeSupport(manifest: Pick<NodePackageManifest, "kind" | "runtimes">, hostRuntimes: readonly string[], engineVersions?: Readonly<Record<string, string>>): ManifestProblem[];
|
|
107
167
|
/**
|
|
108
|
-
*
|
|
168
|
+
* Minimal semver range check — `^x.y.z`, `~x.y.z`, `>=x.y.z`, `x.y.z`, `*`.
|
|
109
169
|
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
* a
|
|
170
|
+
* Deliberately small: this runs in the CLI and in CI, and pulling a semver
|
|
171
|
+
* library into the engine for one comparison is not worth the dependency. It
|
|
172
|
+
* covers the forms a manifest actually uses; anything it cannot parse is
|
|
173
|
+
* treated as unsatisfied rather than silently passed, so an unparseable range
|
|
174
|
+
* fails loudly instead of waving a node through.
|
|
175
|
+
*/
|
|
176
|
+
declare function satisfiesRange(version: string, range: string): boolean;
|
|
177
|
+
/**
|
|
178
|
+
* Check that every capability a node needs is wired.
|
|
179
|
+
*
|
|
180
|
+
* A `required` capability that is missing is an ERROR — that is the whole point
|
|
181
|
+
* of the requirement level. It is meant to be surfaced at author time, so an
|
|
182
|
+
* editor can grey the node and name what the host never registered, rather than
|
|
183
|
+
* the node installing cleanly and silently no-opping during a run.
|
|
184
|
+
*
|
|
185
|
+
* An `optional` one is a warning: the node still works, with less.
|
|
113
186
|
*/
|
|
114
187
|
declare function checkCapabilities(manifest: Pick<NodePackageManifest, "kind" | "capabilities">, available: Readonly<Record<string, boolean>>): ManifestProblem[];
|
|
115
188
|
|
|
@@ -140,6 +213,35 @@ declare function checkCapabilities(manifest: Pick<NodePackageManifest, "kind" |
|
|
|
140
213
|
* executes byte-identical cases without an embedded JS engine.
|
|
141
214
|
*/
|
|
142
215
|
|
|
216
|
+
/**
|
|
217
|
+
* Deterministic stand-ins for host capabilities, declared as DATA.
|
|
218
|
+
*
|
|
219
|
+
* `llm_router` cannot reach a provider in CI, so a fixture has to supply a fake
|
|
220
|
+
* `LlmClient`. If the stub format is not shared, each runtime stubs
|
|
221
|
+
* differently and the fixtures stop being comparable — parity theatre. So the
|
|
222
|
+
* fixture declares the stub's *behaviour* and both engines construct it
|
|
223
|
+
* identically from the same JSON.
|
|
224
|
+
*/
|
|
225
|
+
type FixtureStubs = {
|
|
226
|
+
/** Canned `chooseRoute` answer for the LLM capability. */
|
|
227
|
+
llm_client?: {
|
|
228
|
+
chooseRoute: {
|
|
229
|
+
port: string;
|
|
230
|
+
reason?: string;
|
|
231
|
+
};
|
|
232
|
+
};
|
|
233
|
+
/** Canned workflow resolution, keyed by ref, for `subflow`. */
|
|
234
|
+
workflow_resolver?: Record<string, FlowGraph | null>;
|
|
235
|
+
};
|
|
236
|
+
/** An event a case expects the run to have emitted. */
|
|
237
|
+
type FixtureEventExpectation = {
|
|
238
|
+
type: RunEvent["type"];
|
|
239
|
+
/** Emitting node, when it matters. */
|
|
240
|
+
nodeId?: string;
|
|
241
|
+
level?: "info" | "warn" | "error";
|
|
242
|
+
/** Substring match against the message — full text is too brittle to pin. */
|
|
243
|
+
messageContains?: string;
|
|
244
|
+
};
|
|
143
245
|
/** What a case expects to have happened. */
|
|
144
246
|
type FixtureExpectation = {
|
|
145
247
|
/**
|
|
@@ -157,6 +259,29 @@ type FixtureExpectation = {
|
|
|
157
259
|
};
|
|
158
260
|
/** The run failed, and the message contains this substring. */
|
|
159
261
|
error?: string;
|
|
262
|
+
/**
|
|
263
|
+
* Events the run must have emitted.
|
|
264
|
+
*
|
|
265
|
+
* Emitted events are BEHAVIOUR, not decoration. The hallucinated-port warning
|
|
266
|
+
* is a contract an operator relies on to know a run took the fallback — if
|
|
267
|
+
* one runtime stops emitting it, the guarantee degrades silently. Each entry
|
|
268
|
+
* must match at least one emitted event.
|
|
269
|
+
*/
|
|
270
|
+
events?: FixtureEventExpectation[];
|
|
271
|
+
/**
|
|
272
|
+
* The run resumed after a pause and reached this state.
|
|
273
|
+
*
|
|
274
|
+
* Pause/resume is the ONLY path that crosses a persistence boundary, which
|
|
275
|
+
* makes it where two runtimes are most likely to drift — and it had no parity
|
|
276
|
+
* coverage at all while `PausesForHuman` became public API.
|
|
277
|
+
*/
|
|
278
|
+
afterResume?: {
|
|
279
|
+
/** Delivered on the paused node's `values` input, as a host would on resume. */
|
|
280
|
+
submit: unknown;
|
|
281
|
+
ports?: string[];
|
|
282
|
+
value?: unknown;
|
|
283
|
+
error?: string;
|
|
284
|
+
};
|
|
160
285
|
};
|
|
161
286
|
type FixtureCase = {
|
|
162
287
|
/** Human-readable, and what a failure report names. */
|
|
@@ -180,6 +305,16 @@ type FixtureCase = {
|
|
|
180
305
|
ports?: string[];
|
|
181
306
|
/** Inputs delivered on the node's input ports. */
|
|
182
307
|
inputs?: Record<string, unknown>;
|
|
308
|
+
/**
|
|
309
|
+
* Run this case against an ALIAS or an older config shape.
|
|
310
|
+
*
|
|
311
|
+
* What proves `aliases` and `configVersion` actually work rather than being
|
|
312
|
+
* declared and rotting. A package that renames its kind should have a case
|
|
313
|
+
* pinning that the old id still resolves.
|
|
314
|
+
*/
|
|
315
|
+
legacyKind?: string;
|
|
316
|
+
/** Deterministic capability stand-ins for this case. */
|
|
317
|
+
stubs?: FixtureStubs;
|
|
183
318
|
expect: FixtureExpectation;
|
|
184
319
|
};
|
|
185
320
|
type FixtureFile = {
|
|
@@ -212,4 +347,4 @@ declare function runFixtures(file: FixtureFile, executor: NodeExecutor): Promise
|
|
|
212
347
|
*/
|
|
213
348
|
declare function validateFixtureFile(input: unknown, expectedKind?: string): string[];
|
|
214
349
|
|
|
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 };
|
|
350
|
+
export { type CapabilityRequirement, type FixtureCase, type FixtureEventExpectation, type FixtureExpectation, type FixtureFailure, type FixtureFile, type FixtureRunResult, type FixtureStubs, FlowGraph, type ManifestProblem, type ManifestValidation, NODE_MANIFEST_SCHEMA_VERSION, NodeExecutor, type NodePackageManifest, type NodeRuntimeId, type NodeRuntimeSpec, PauseAwaiting, RunEvent, type SideEffects, checkCapabilities, checkRuntimeSupport, runFixtures, satisfiesRange, validateFixtureFile, validateNodeManifest };
|
package/dist/engine.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
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,
|
|
2
|
+
import { F as FlowGraph, R as RunEvent, N as NodeExecutor } from './types-sOmpCitB.js';
|
|
3
|
+
export { A as ActionNodeData, B as BaseNodeData, D as DecisionNodeData, E as ExecutorRegistry, a as FlowEdge, b as FlowNode, c as FlowNodeData, d as FlowNodeKind, e as NodeRunStatus, f as NoteNodeData, O as OutputNodeData, P as PortDescriptor, S as SubgraphNodeData, T as TriggerNodeData } from './types-sOmpCitB.js';
|
|
4
4
|
import { P as PauseAwaiting } from './pause-9iT4tCEV.js';
|
|
5
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';
|
|
6
6
|
import '@xyflow/react';
|
|
@@ -9,17 +9,22 @@ import '@xyflow/react';
|
|
|
9
9
|
* The node package manifest — what a marketplace node declares about itself.
|
|
10
10
|
*
|
|
11
11
|
* A node is not one artifact. It is a kind definition (palette entry, config
|
|
12
|
-
* schema, ports,
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
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.
|
|
12
|
+
* schema, ports, renderer) plus an executor for EACH runtime the consumer runs.
|
|
13
|
+
* A package shipping only a TS executor is unusable to anyone executing on PHP,
|
|
14
|
+
* and without a manifest that is invisible until a run fails. Requested by the
|
|
15
|
+
* MOIC Suite consumer (fancy-flow#2 §2), who runs the editor in TS and executes
|
|
16
|
+
* in PHP and hit exactly this.
|
|
20
17
|
*
|
|
21
18
|
* The manifest is data, not code: the registry, the CLI, and the MCP all read
|
|
22
19
|
* it without executing anything a package author wrote.
|
|
20
|
+
*
|
|
21
|
+
* ## Why the engine range lives per runtime
|
|
22
|
+
*
|
|
23
|
+
* The first cut of this manifest carried ONE `fancyFlow` range, and it was
|
|
24
|
+
* wrong: the two engines version independently, so a single range cannot say
|
|
25
|
+
* "needs npm >=0.11 AND php >=0.5". A package supporting both runtimes would
|
|
26
|
+
* install cleanly against a host whose OTHER runtime was too old — the 0.9.0
|
|
27
|
+
* failure shape wearing a manifest. The range belongs inside each runtime.
|
|
23
28
|
*/
|
|
24
29
|
|
|
25
30
|
/** The current manifest schema version. Bump only on a breaking shape change. */
|
|
@@ -32,6 +37,38 @@ declare const NODE_MANIFEST_SCHEMA_VERSION = 1;
|
|
|
32
37
|
* declare itself without a release here.
|
|
33
38
|
*/
|
|
34
39
|
type NodeRuntimeId = "ts" | "php" | (string & {});
|
|
40
|
+
/**
|
|
41
|
+
* How one runtime provides this node, and which engine version it needs.
|
|
42
|
+
*
|
|
43
|
+
* `entry` and `package` are both here because the two ecosystems install
|
|
44
|
+
* differently — a module path within the package for TS, a Composer
|
|
45
|
+
* requirement for PHP — and pretending otherwise just moves the problem into
|
|
46
|
+
* the CLI. Exactly one is required.
|
|
47
|
+
*/
|
|
48
|
+
type NodeRuntimeSpec = {
|
|
49
|
+
/** Module path within the package (TS-style runtimes). */
|
|
50
|
+
entry?: string;
|
|
51
|
+
/** Dependency requirement resolved by that ecosystem (PHP/Composer-style). */
|
|
52
|
+
package?: string;
|
|
53
|
+
/** Semver range of THIS runtime's engine. Required — see the module note. */
|
|
54
|
+
engine: string;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Whether a capability must be wired for the node to work at all.
|
|
58
|
+
*
|
|
59
|
+
* `required` is checked at AUTHOR time, not run time. The failure that hurts is
|
|
60
|
+
* a node that installs fine, authors fine, and silently no-ops during a run —
|
|
61
|
+
* the same silence as a routing bug. An editor can grey the node and say which
|
|
62
|
+
* capability the host never registered.
|
|
63
|
+
*/
|
|
64
|
+
type CapabilityRequirement = "required" | "optional";
|
|
65
|
+
/**
|
|
66
|
+
* Whether a node is safe to run again.
|
|
67
|
+
*
|
|
68
|
+
* Durable runs RETRY. A node that writes needs to say so, or a host has to pick
|
|
69
|
+
* one retry policy for every node and get it wrong somewhere.
|
|
70
|
+
*/
|
|
71
|
+
type SideEffects = "none" | "idempotent" | "unsafe-to-replay";
|
|
35
72
|
type NodePackageManifest = {
|
|
36
73
|
/** Must equal `NODE_MANIFEST_SCHEMA_VERSION`. */
|
|
37
74
|
schemaVersion: number;
|
|
@@ -42,22 +79,33 @@ type NodePackageManifest = {
|
|
|
42
79
|
* that gets persisted into every document using it.
|
|
43
80
|
*/
|
|
44
81
|
kind: string;
|
|
45
|
-
/** Semver range of fancy-flow this node's contract targets. */
|
|
46
|
-
fancyFlow: string;
|
|
47
82
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
83
|
+
* Previous ids this kind still answers to.
|
|
84
|
+
*
|
|
85
|
+
* Core renamed `llm_branch` to `llm_router` and kept every old id working.
|
|
86
|
+
* Third-party packages will rename too, and their documents break the same
|
|
87
|
+
* way core's would have — so packages get the same escape hatch, otherwise
|
|
88
|
+
* only first-party nodes can rename safely.
|
|
89
|
+
*/
|
|
90
|
+
aliases?: string[];
|
|
91
|
+
/**
|
|
92
|
+
* Version of this node's CONFIG shape, independent of the document schema.
|
|
93
|
+
*
|
|
94
|
+
* A node's config evolves on its own clock. Without a declared version, every
|
|
95
|
+
* executor accretes hand-written read-fallbacks forever (MOIC carries one for
|
|
96
|
+
* `routes[].key` → `routes[].port`), because nothing canonicalises old config
|
|
97
|
+
* the way import canonicalises kind ids.
|
|
51
98
|
*/
|
|
52
|
-
|
|
99
|
+
configVersion?: number;
|
|
100
|
+
/** Per-runtime entrypoints and engine ranges. */
|
|
101
|
+
runtimes: Partial<Record<NodeRuntimeId, NodeRuntimeSpec>>;
|
|
53
102
|
/**
|
|
54
|
-
* Host capabilities this node needs
|
|
55
|
-
* `workflow_resolver`, `document`, or a host-specific one.
|
|
103
|
+
* Host capabilities this node needs, and whether each is mandatory.
|
|
56
104
|
*
|
|
57
|
-
* Declared so the CLI
|
|
58
|
-
* than the node silently no-opping or crashing mid-run.
|
|
105
|
+
* Declared so the CLI and the editor can say what to wire BEFORE a run,
|
|
106
|
+
* rather than the node silently no-opping or crashing mid-run.
|
|
59
107
|
*/
|
|
60
|
-
capabilities?: string
|
|
108
|
+
capabilities?: Record<string, CapabilityRequirement>;
|
|
61
109
|
/**
|
|
62
110
|
* Path to this node's golden fixtures, relative to the package root.
|
|
63
111
|
*
|
|
@@ -66,8 +114,16 @@ type NodePackageManifest = {
|
|
|
66
114
|
* asserted. See `./fixtures`.
|
|
67
115
|
*/
|
|
68
116
|
fixtures: string;
|
|
69
|
-
/**
|
|
117
|
+
/**
|
|
118
|
+
* Declares the node halts for a person. Mirrors `NodeKindDefinition`.
|
|
119
|
+
*
|
|
120
|
+
* A host-planning fact, not a node internal: a parent that embeds workflows
|
|
121
|
+
* needs to reject a child that can pause, because a paused child wedges the
|
|
122
|
+
* parent — and discovering that at run time means watching a run park.
|
|
123
|
+
*/
|
|
70
124
|
pausesForHuman?: PauseAwaiting;
|
|
125
|
+
/** Whether this node is safe to replay. See `SideEffects`. */
|
|
126
|
+
sideEffects?: SideEffects;
|
|
71
127
|
/** One-line summary — what `search_nodes` matches against. */
|
|
72
128
|
description?: string;
|
|
73
129
|
/**
|
|
@@ -97,19 +153,36 @@ type ManifestValidation = {
|
|
|
97
153
|
*/
|
|
98
154
|
declare function validateNodeManifest(input: unknown): ManifestValidation;
|
|
99
155
|
/**
|
|
100
|
-
* Check a node against the runtimes a host
|
|
156
|
+
* Check a node against the runtimes a host executes on, and their versions.
|
|
157
|
+
*
|
|
158
|
+
* Two failures live here, and both are errors because the node genuinely
|
|
159
|
+
* cannot run: a runtime the package does not implement at all, and a runtime
|
|
160
|
+
* it implements against an engine newer than the host's.
|
|
101
161
|
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
* not
|
|
162
|
+
* `engineVersions` is optional — pass what the host knows. An unchecked range
|
|
163
|
+
* is reported as a warning rather than passed over silently, because "we did
|
|
164
|
+
* not check" and "it is fine" must not look the same.
|
|
105
165
|
*/
|
|
106
|
-
declare function checkRuntimeSupport(manifest: Pick<NodePackageManifest, "kind" | "runtimes">, hostRuntimes: readonly string[]): ManifestProblem[];
|
|
166
|
+
declare function checkRuntimeSupport(manifest: Pick<NodePackageManifest, "kind" | "runtimes">, hostRuntimes: readonly string[], engineVersions?: Readonly<Record<string, string>>): ManifestProblem[];
|
|
107
167
|
/**
|
|
108
|
-
*
|
|
168
|
+
* Minimal semver range check — `^x.y.z`, `~x.y.z`, `>=x.y.z`, `x.y.z`, `*`.
|
|
109
169
|
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
* a
|
|
170
|
+
* Deliberately small: this runs in the CLI and in CI, and pulling a semver
|
|
171
|
+
* library into the engine for one comparison is not worth the dependency. It
|
|
172
|
+
* covers the forms a manifest actually uses; anything it cannot parse is
|
|
173
|
+
* treated as unsatisfied rather than silently passed, so an unparseable range
|
|
174
|
+
* fails loudly instead of waving a node through.
|
|
175
|
+
*/
|
|
176
|
+
declare function satisfiesRange(version: string, range: string): boolean;
|
|
177
|
+
/**
|
|
178
|
+
* Check that every capability a node needs is wired.
|
|
179
|
+
*
|
|
180
|
+
* A `required` capability that is missing is an ERROR — that is the whole point
|
|
181
|
+
* of the requirement level. It is meant to be surfaced at author time, so an
|
|
182
|
+
* editor can grey the node and name what the host never registered, rather than
|
|
183
|
+
* the node installing cleanly and silently no-opping during a run.
|
|
184
|
+
*
|
|
185
|
+
* An `optional` one is a warning: the node still works, with less.
|
|
113
186
|
*/
|
|
114
187
|
declare function checkCapabilities(manifest: Pick<NodePackageManifest, "kind" | "capabilities">, available: Readonly<Record<string, boolean>>): ManifestProblem[];
|
|
115
188
|
|
|
@@ -140,6 +213,35 @@ declare function checkCapabilities(manifest: Pick<NodePackageManifest, "kind" |
|
|
|
140
213
|
* executes byte-identical cases without an embedded JS engine.
|
|
141
214
|
*/
|
|
142
215
|
|
|
216
|
+
/**
|
|
217
|
+
* Deterministic stand-ins for host capabilities, declared as DATA.
|
|
218
|
+
*
|
|
219
|
+
* `llm_router` cannot reach a provider in CI, so a fixture has to supply a fake
|
|
220
|
+
* `LlmClient`. If the stub format is not shared, each runtime stubs
|
|
221
|
+
* differently and the fixtures stop being comparable — parity theatre. So the
|
|
222
|
+
* fixture declares the stub's *behaviour* and both engines construct it
|
|
223
|
+
* identically from the same JSON.
|
|
224
|
+
*/
|
|
225
|
+
type FixtureStubs = {
|
|
226
|
+
/** Canned `chooseRoute` answer for the LLM capability. */
|
|
227
|
+
llm_client?: {
|
|
228
|
+
chooseRoute: {
|
|
229
|
+
port: string;
|
|
230
|
+
reason?: string;
|
|
231
|
+
};
|
|
232
|
+
};
|
|
233
|
+
/** Canned workflow resolution, keyed by ref, for `subflow`. */
|
|
234
|
+
workflow_resolver?: Record<string, FlowGraph | null>;
|
|
235
|
+
};
|
|
236
|
+
/** An event a case expects the run to have emitted. */
|
|
237
|
+
type FixtureEventExpectation = {
|
|
238
|
+
type: RunEvent["type"];
|
|
239
|
+
/** Emitting node, when it matters. */
|
|
240
|
+
nodeId?: string;
|
|
241
|
+
level?: "info" | "warn" | "error";
|
|
242
|
+
/** Substring match against the message — full text is too brittle to pin. */
|
|
243
|
+
messageContains?: string;
|
|
244
|
+
};
|
|
143
245
|
/** What a case expects to have happened. */
|
|
144
246
|
type FixtureExpectation = {
|
|
145
247
|
/**
|
|
@@ -157,6 +259,29 @@ type FixtureExpectation = {
|
|
|
157
259
|
};
|
|
158
260
|
/** The run failed, and the message contains this substring. */
|
|
159
261
|
error?: string;
|
|
262
|
+
/**
|
|
263
|
+
* Events the run must have emitted.
|
|
264
|
+
*
|
|
265
|
+
* Emitted events are BEHAVIOUR, not decoration. The hallucinated-port warning
|
|
266
|
+
* is a contract an operator relies on to know a run took the fallback — if
|
|
267
|
+
* one runtime stops emitting it, the guarantee degrades silently. Each entry
|
|
268
|
+
* must match at least one emitted event.
|
|
269
|
+
*/
|
|
270
|
+
events?: FixtureEventExpectation[];
|
|
271
|
+
/**
|
|
272
|
+
* The run resumed after a pause and reached this state.
|
|
273
|
+
*
|
|
274
|
+
* Pause/resume is the ONLY path that crosses a persistence boundary, which
|
|
275
|
+
* makes it where two runtimes are most likely to drift — and it had no parity
|
|
276
|
+
* coverage at all while `PausesForHuman` became public API.
|
|
277
|
+
*/
|
|
278
|
+
afterResume?: {
|
|
279
|
+
/** Delivered on the paused node's `values` input, as a host would on resume. */
|
|
280
|
+
submit: unknown;
|
|
281
|
+
ports?: string[];
|
|
282
|
+
value?: unknown;
|
|
283
|
+
error?: string;
|
|
284
|
+
};
|
|
160
285
|
};
|
|
161
286
|
type FixtureCase = {
|
|
162
287
|
/** Human-readable, and what a failure report names. */
|
|
@@ -180,6 +305,16 @@ type FixtureCase = {
|
|
|
180
305
|
ports?: string[];
|
|
181
306
|
/** Inputs delivered on the node's input ports. */
|
|
182
307
|
inputs?: Record<string, unknown>;
|
|
308
|
+
/**
|
|
309
|
+
* Run this case against an ALIAS or an older config shape.
|
|
310
|
+
*
|
|
311
|
+
* What proves `aliases` and `configVersion` actually work rather than being
|
|
312
|
+
* declared and rotting. A package that renames its kind should have a case
|
|
313
|
+
* pinning that the old id still resolves.
|
|
314
|
+
*/
|
|
315
|
+
legacyKind?: string;
|
|
316
|
+
/** Deterministic capability stand-ins for this case. */
|
|
317
|
+
stubs?: FixtureStubs;
|
|
183
318
|
expect: FixtureExpectation;
|
|
184
319
|
};
|
|
185
320
|
type FixtureFile = {
|
|
@@ -212,4 +347,4 @@ declare function runFixtures(file: FixtureFile, executor: NodeExecutor): Promise
|
|
|
212
347
|
*/
|
|
213
348
|
declare function validateFixtureFile(input: unknown, expectedKind?: string): string[];
|
|
214
349
|
|
|
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 };
|
|
350
|
+
export { type CapabilityRequirement, type FixtureCase, type FixtureEventExpectation, type FixtureExpectation, type FixtureFailure, type FixtureFile, type FixtureRunResult, type FixtureStubs, FlowGraph, type ManifestProblem, type ManifestValidation, NODE_MANIFEST_SCHEMA_VERSION, NodeExecutor, type NodePackageManifest, type NodeRuntimeId, type NodeRuntimeSpec, PauseAwaiting, RunEvent, type SideEffects, checkCapabilities, checkRuntimeSupport, runFixtures, satisfiesRange, validateFixtureFile, validateNodeManifest };
|