@particle-academy/fancy-flow 0.65.2 → 0.66.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.
- package/README.md +100 -3
- package/dist/{FlowViewer-BI_AyyvU.d.ts → FlowViewer-BCc_BvuD.d.ts} +1 -1
- package/dist/{FlowViewer-DABx-6A-.d.cts → FlowViewer-CoAJ3o52.d.cts} +1 -1
- package/dist/{HumanPrompt-Bpp3JiVH.d.cts → HumanPrompt--pXDOyYC.d.cts} +2 -2
- package/dist/{HumanPrompt-BKThiyjB.d.ts → HumanPrompt-DXm_FP9z.d.ts} +2 -2
- package/dist/chunk-27RZJAE2.js +2586 -0
- package/dist/chunk-27RZJAE2.js.map +1 -0
- package/dist/{chunk-MBVX4ZRB.js → chunk-2QTEELJE.js} +4 -3
- package/dist/chunk-2QTEELJE.js.map +1 -0
- package/dist/chunk-2QXKDLGT.js +58 -0
- package/dist/chunk-2QXKDLGT.js.map +1 -0
- package/dist/{chunk-W5DPKJY4.js → chunk-6AYC3BWI.js} +4 -4
- package/dist/chunk-6AYC3BWI.js.map +1 -0
- package/dist/{chunk-5H54OTKT.js → chunk-6TH646CS.js} +127 -5
- package/dist/chunk-6TH646CS.js.map +1 -0
- package/dist/{chunk-EO6444T2.js → chunk-BUNFPBTF.js} +5 -4
- package/dist/chunk-BUNFPBTF.js.map +1 -0
- package/dist/{chunk-77V4QC6Y.js → chunk-FV3D366L.js} +3 -3
- package/dist/{chunk-77V4QC6Y.js.map → chunk-FV3D366L.js.map} +1 -1
- package/dist/{chunk-JF6WCRBU.js → chunk-OWENS2H5.js} +36 -1905
- package/dist/chunk-OWENS2H5.js.map +1 -0
- package/dist/{chunk-RIAFHQT5.js → chunk-RE3XNVSB.js} +3 -3
- package/dist/{chunk-RIAFHQT5.js.map → chunk-RE3XNVSB.js.map} +1 -1
- package/dist/connectors.d.cts +2 -2
- package/dist/connectors.d.ts +2 -2
- package/dist/durable/index.d.cts +2 -2
- package/dist/durable/index.d.ts +2 -2
- package/dist/durable.cjs +865 -9135
- package/dist/durable.cjs.map +1 -1
- package/dist/durable.js +2 -4
- package/dist/durable.js.map +1 -1
- package/dist/engine.cjs +927 -9278
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.d.cts +6 -7
- package/dist/engine.d.ts +6 -7
- package/dist/engine.js +5 -7
- package/dist/engine.js.map +1 -1
- package/dist/fields/react-fancy.d.cts +3 -3
- package/dist/fields/react-fancy.d.ts +3 -3
- package/dist/index.cjs +11009 -10282
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +65 -36
- package/dist/index.d.ts +65 -36
- package/dist/index.js +22 -19
- package/dist/index.js.map +1 -1
- package/dist/layout/index.d.cts +1 -1
- package/dist/layout/index.d.ts +1 -1
- package/dist/llm/prism.cjs.map +1 -1
- package/dist/llm/prism.d.cts +1 -2
- package/dist/llm/prism.d.ts +1 -2
- package/dist/llm/prism.js +1 -1
- package/dist/llm/vercel-ai.cjs.map +1 -1
- package/dist/llm/vercel-ai.d.cts +1 -2
- package/dist/llm/vercel-ai.d.ts +1 -2
- package/dist/llm/vercel-ai.js +1 -1
- package/dist/registry/index.d.cts +20 -9
- package/dist/registry/index.d.ts +20 -9
- package/dist/{registry-CntAdUcY.d.cts → registry-BcgllSk2.d.cts} +1 -1
- package/dist/{registry-DYoV-MQi.d.ts → registry-h-2QswZ5.d.ts} +1 -1
- package/dist/registry.cjs +11252 -10409
- package/dist/registry.cjs.map +1 -1
- package/dist/registry.js +5 -4
- package/dist/{run-cohort-C1nRh_mi.d.ts → run-cohort-CjUBWg6X.d.ts} +2 -2
- package/dist/{run-cohort-CBRAUj-z.d.cts → run-cohort-DL9JzzPU.d.cts} +2 -2
- package/dist/{run-flow-2XsHBwpd.d.cts → run-flow-B_8hgO5_.d.cts} +1 -1
- package/dist/{run-flow-D7AOCcfE.d.ts → run-flow-CxEGBOxd.d.ts} +1 -1
- package/dist/runtime/index.d.cts +5 -5
- package/dist/runtime/index.d.ts +5 -5
- package/dist/runtime.cjs +10843 -10194
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.js +5 -5
- package/dist/schema/index.d.cts +19 -6
- package/dist/schema/index.d.ts +19 -6
- package/dist/schema.cjs +881 -9142
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.js +4 -5
- package/dist/screens.cjs +842 -86
- package/dist/screens.cjs.map +1 -1
- package/dist/screens.d.cts +2 -2
- package/dist/screens.d.ts +2 -2
- package/dist/screens.js +7 -6
- package/dist/screens.js.map +1 -1
- package/dist/terminal/fancy-term-host.cjs +99 -0
- package/dist/terminal/fancy-term-host.cjs.map +1 -0
- package/dist/terminal/fancy-term-host.d.cts +76 -0
- package/dist/terminal/fancy-term-host.d.ts +76 -0
- package/dist/terminal/fancy-term-host.js +92 -0
- package/dist/terminal/fancy-term-host.js.map +1 -0
- package/dist/types-B-Syk9-M.d.cts +620 -0
- package/dist/types-B-Syk9-M.d.ts +620 -0
- package/dist/{types-D71SKA5A.d.cts → types-C2ATTmjN.d.cts} +1 -1
- package/dist/{types-Ckhz-YwC.d.ts → types-VunLGqrn.d.ts} +1 -1
- package/dist/ux.cjs +885 -9142
- package/dist/ux.cjs.map +1 -1
- package/dist/ux.d.cts +2 -2
- package/dist/ux.d.ts +2 -2
- package/dist/ux.js +2 -3
- package/dist/ux.js.map +1 -1
- package/package.json +11 -1
- package/dist/capabilities-BYa5p5jw.d.cts +0 -112
- package/dist/capabilities-COOXRiNL.d.ts +0 -112
- package/dist/chunk-5H54OTKT.js.map +0 -1
- package/dist/chunk-EO6444T2.js.map +0 -1
- package/dist/chunk-JF6WCRBU.js.map +0 -1
- package/dist/chunk-MBVX4ZRB.js.map +0 -1
- package/dist/chunk-UM4C46AF.js +0 -103
- package/dist/chunk-UM4C46AF.js.map +0 -1
- package/dist/chunk-USL4FMFU.js +0 -41
- package/dist/chunk-USL4FMFU.js.map +0 -1
- package/dist/chunk-W5DPKJY4.js.map +0 -1
- package/dist/types-JFYjPJAG.d.cts +0 -333
- package/dist/types-JFYjPJAG.d.ts +0 -333
package/README.md
CHANGED
|
@@ -339,9 +339,11 @@ function MyEditor() {
|
|
|
339
339
|
|
|
340
340
|
## Node kinds
|
|
341
341
|
|
|
342
|
-
|
|
342
|
+
31 builtins, grouped by category. Ids are namespaced (`@particle-academy/<name>`)
|
|
343
343
|
and every bare name below is a permanent alias, so graphs saved against either
|
|
344
|
-
keep resolving.
|
|
344
|
+
keep resolving. The count is checked against the registry by a test — a
|
|
345
|
+
hand-maintained mirror that nothing compares is the defect this kit keeps
|
|
346
|
+
finding, so it is compared.
|
|
345
347
|
|
|
346
348
|
| Category | Kinds |
|
|
347
349
|
|---|---|
|
|
@@ -352,7 +354,8 @@ keep resolving.
|
|
|
352
354
|
| `data` | `variable`, `memory_store`, `data_store` |
|
|
353
355
|
| `io` | `api_request`, `webhook_out` |
|
|
354
356
|
| `output` | `output`, `log` |
|
|
355
|
-
| `
|
|
357
|
+
| `io` (terminal) | `terminal_run`, `terminal_send`, `terminal_await` — inside a terminal lane |
|
|
358
|
+
| `layout` / `annotation` | `lane`, `terminal_lane`, `note` — visual only, never executed |
|
|
356
359
|
|
|
357
360
|
Don't hand-copy this list into generated graphs — it moves. Enumerate at
|
|
358
361
|
runtime with `getNodeKind()` / the registry, or ask the Fancy MCP's `list_nodes`.
|
|
@@ -363,6 +366,100 @@ Custom nodes plug in via xyflow's standard `nodeTypes` prop:
|
|
|
363
366
|
<FlowCanvas nodeTypes={{ ...defaultNodeTypes, myNode: MyCustomNode }} ... />
|
|
364
367
|
```
|
|
365
368
|
|
|
369
|
+
## Terminal lanes
|
|
370
|
+
|
|
371
|
+
A **terminal lane** owns one running terminal for the length of a workflow run,
|
|
372
|
+
so a graph can drive an interactive process — including an agent TUI like Claude
|
|
373
|
+
Code or Codex — instead of only firing one-shot commands.
|
|
374
|
+
|
|
375
|
+
Three promises, and all three are about WHEN rather than what:
|
|
376
|
+
|
|
377
|
+
1. **One terminal per lane**, however many nodes are inside it. Two shells look
|
|
378
|
+
exactly like one that forgot a `cd`.
|
|
379
|
+
2. **It opens at the first terminal node**, not at run start. A lane drawn
|
|
380
|
+
around nodes that mostly do other things costs nothing until something uses
|
|
381
|
+
it.
|
|
382
|
+
3. **It stays open until the run finishes**, including when the run FAILS. A
|
|
383
|
+
leaked PTY looks like nothing at all until the machine is full of them.
|
|
384
|
+
|
|
385
|
+
Membership is the canvas's own `parentId`, which already persists into the
|
|
386
|
+
`WorkflowSchema` — so a headless runtime resolves exactly the grouping a person
|
|
387
|
+
drew, with no second association to keep in step.
|
|
388
|
+
|
|
389
|
+
### The nodes
|
|
390
|
+
|
|
391
|
+
| Kind | For |
|
|
392
|
+
|---|---|
|
|
393
|
+
| `terminal_run` | Run a shell command and wait for its **exit code**. Shell only. |
|
|
394
|
+
| `terminal_send` | Type at whatever is running, without waiting. |
|
|
395
|
+
| `terminal_await` | Wait until the output matches. Returns capture groups in regex mode. |
|
|
396
|
+
|
|
397
|
+
`terminal_run` is the shell node and `terminal_send` + `terminal_await` are the
|
|
398
|
+
TUI pair, because a terminal is two different things depending on what is in it.
|
|
399
|
+
A shell answers and returns to a prompt, so the useful unit is "run this, tell me
|
|
400
|
+
what it said and whether it worked". A TUI never finishes — there is no exit code
|
|
401
|
+
to wait for — so there is only text going in and text coming out.
|
|
402
|
+
|
|
403
|
+
Matching runs against the **accumulated** output with escape sequences already
|
|
404
|
+
stripped, so you match what you SEE and a pattern split across PTY chunks still
|
|
405
|
+
resolves. Output that arrived before an await started is not lost. A wait
|
|
406
|
+
consumes through its match, so the same pattern does not resolve twice on one
|
|
407
|
+
line.
|
|
408
|
+
|
|
409
|
+
Three outcomes are reported distinctly — matched, timed out, and *the process
|
|
410
|
+
exited*. Collapsing the last two is how a dead shell gets reported as "timed out
|
|
411
|
+
waiting for X", sending whoever debugs it to lengthen a timeout on a process
|
|
412
|
+
that is not running.
|
|
413
|
+
|
|
414
|
+
### Providing the terminal
|
|
415
|
+
|
|
416
|
+
Core declares the contract and imports no PTY — `node-pty` is a native addon
|
|
417
|
+
that would break every browser build. Same arrangement as `registerLlmClient`:
|
|
418
|
+
|
|
419
|
+
```ts
|
|
420
|
+
import { registerTerminalHost } from "@particle-academy/fancy-flow/registry";
|
|
421
|
+
|
|
422
|
+
registerTerminalHost({
|
|
423
|
+
open: async ({ command, cwd, env, cols, rows }) => {
|
|
424
|
+
const pty = spawnYourPty(command ?? defaultShell(), { cwd, env, cols, rows });
|
|
425
|
+
return {
|
|
426
|
+
id: pty.pid.toString(),
|
|
427
|
+
write: (data) => pty.write(data),
|
|
428
|
+
onData: (listener) => { pty.onData(listener); return () => pty.dispose(); },
|
|
429
|
+
exited: new Promise((r) => pty.onExit(({ exitCode, signal }) => r({ exitCode, signal }))),
|
|
430
|
+
close: () => pty.kill(),
|
|
431
|
+
};
|
|
432
|
+
},
|
|
433
|
+
});
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
There is deliberately **no `waitForOutput(pattern)` in the contract**. Matching
|
|
437
|
+
is derivable from `onData`, so putting it in the contract would mean every host
|
|
438
|
+
implements it — two implementations of one agreed rule, which is how matching
|
|
439
|
+
bugs end up differing per host. Core owns matching; the host owns the process.
|
|
440
|
+
|
|
441
|
+
### The fancy-term-host adapter
|
|
442
|
+
|
|
443
|
+
If you already run `@particle-academy/fancy-term-host`, the adapter is on its
|
|
444
|
+
own subpath:
|
|
445
|
+
|
|
446
|
+
```ts
|
|
447
|
+
import { terminalManager } from "@particle-academy/fancy-term-host";
|
|
448
|
+
import { useFancyTermHost } from "@particle-academy/fancy-flow/terminal/fancy-term-host";
|
|
449
|
+
|
|
450
|
+
useFancyTermHost(terminalManager(), { cwd: "/srv/app" });
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
It takes the backend as an **argument** rather than importing the package.
|
|
454
|
+
`fancy-term-host` requires `node-pty` as a peer and imports it at module scope,
|
|
455
|
+
so depending on it here — even for types — would put a native build in every
|
|
456
|
+
fancy-flow install, including browser consumers who will never open a terminal.
|
|
457
|
+
Anyone who wants this adapter already holds a backend, so passing it in costs
|
|
458
|
+
them one argument and costs everyone else nothing.
|
|
459
|
+
|
|
460
|
+
**`fancy-flow-php` does not have this feature and is not going to.** It needs
|
|
461
|
+
desktop execution, which is not what the PHP runtime is for.
|
|
462
|
+
|
|
366
463
|
## LLM adapters
|
|
367
464
|
|
|
368
465
|
`llm_router` (alias `llm_branch`) asks a model to pick one of a node's declared
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { CSSProperties, ReactNode } from 'react';
|
|
3
|
-
import { F as FlowGraph, a as FlowNode } from './types-
|
|
3
|
+
import { F as FlowGraph, a as FlowNode } from './types-B-Syk9-M.js';
|
|
4
4
|
|
|
5
5
|
/** Outcome of one node in a run, for annotating the graph after the fact. */
|
|
6
6
|
type FlowNodeStatus = "ok" | "running" | "failed" | "skipped" | "pending";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { CSSProperties, ReactNode } from 'react';
|
|
3
|
-
import { F as FlowGraph, a as FlowNode } from './types-
|
|
3
|
+
import { F as FlowGraph, a as FlowNode } from './types-B-Syk9-M.cjs';
|
|
4
4
|
|
|
5
5
|
/** Outcome of one node in a run, for annotating the graph after the fact. */
|
|
6
6
|
type FlowNodeStatus = "ok" | "running" | "failed" | "skipped" | "pending";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { F as FlowGraph } from './types-
|
|
4
|
-
import { C as ConfigField } from './types-
|
|
3
|
+
import { F as FlowGraph } from './types-B-Syk9-M.cjs';
|
|
4
|
+
import { C as ConfigField } from './types-C2ATTmjN.cjs';
|
|
5
5
|
|
|
6
6
|
/** What a host renderer is handed. */
|
|
7
7
|
type ConfigFieldRenderContext = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { F as FlowGraph } from './types-
|
|
4
|
-
import { C as ConfigField } from './types-
|
|
3
|
+
import { F as FlowGraph } from './types-B-Syk9-M.js';
|
|
4
|
+
import { C as ConfigField } from './types-VunLGqrn.js';
|
|
5
5
|
|
|
6
6
|
/** What a host renderer is handed. */
|
|
7
7
|
type ConfigFieldRenderContext = {
|