@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.
Files changed (112) hide show
  1. package/README.md +100 -3
  2. package/dist/{FlowViewer-BI_AyyvU.d.ts → FlowViewer-BCc_BvuD.d.ts} +1 -1
  3. package/dist/{FlowViewer-DABx-6A-.d.cts → FlowViewer-CoAJ3o52.d.cts} +1 -1
  4. package/dist/{HumanPrompt-Bpp3JiVH.d.cts → HumanPrompt--pXDOyYC.d.cts} +2 -2
  5. package/dist/{HumanPrompt-BKThiyjB.d.ts → HumanPrompt-DXm_FP9z.d.ts} +2 -2
  6. package/dist/chunk-27RZJAE2.js +2586 -0
  7. package/dist/chunk-27RZJAE2.js.map +1 -0
  8. package/dist/{chunk-MBVX4ZRB.js → chunk-2QTEELJE.js} +4 -3
  9. package/dist/chunk-2QTEELJE.js.map +1 -0
  10. package/dist/chunk-2QXKDLGT.js +58 -0
  11. package/dist/chunk-2QXKDLGT.js.map +1 -0
  12. package/dist/{chunk-W5DPKJY4.js → chunk-6AYC3BWI.js} +4 -4
  13. package/dist/chunk-6AYC3BWI.js.map +1 -0
  14. package/dist/{chunk-5H54OTKT.js → chunk-6TH646CS.js} +127 -5
  15. package/dist/chunk-6TH646CS.js.map +1 -0
  16. package/dist/{chunk-EO6444T2.js → chunk-BUNFPBTF.js} +5 -4
  17. package/dist/chunk-BUNFPBTF.js.map +1 -0
  18. package/dist/{chunk-77V4QC6Y.js → chunk-FV3D366L.js} +3 -3
  19. package/dist/{chunk-77V4QC6Y.js.map → chunk-FV3D366L.js.map} +1 -1
  20. package/dist/{chunk-JF6WCRBU.js → chunk-OWENS2H5.js} +36 -1905
  21. package/dist/chunk-OWENS2H5.js.map +1 -0
  22. package/dist/{chunk-RIAFHQT5.js → chunk-RE3XNVSB.js} +3 -3
  23. package/dist/{chunk-RIAFHQT5.js.map → chunk-RE3XNVSB.js.map} +1 -1
  24. package/dist/connectors.d.cts +2 -2
  25. package/dist/connectors.d.ts +2 -2
  26. package/dist/durable/index.d.cts +2 -2
  27. package/dist/durable/index.d.ts +2 -2
  28. package/dist/durable.cjs +865 -9135
  29. package/dist/durable.cjs.map +1 -1
  30. package/dist/durable.js +2 -4
  31. package/dist/durable.js.map +1 -1
  32. package/dist/engine.cjs +927 -9278
  33. package/dist/engine.cjs.map +1 -1
  34. package/dist/engine.d.cts +6 -7
  35. package/dist/engine.d.ts +6 -7
  36. package/dist/engine.js +5 -7
  37. package/dist/engine.js.map +1 -1
  38. package/dist/fields/react-fancy.d.cts +3 -3
  39. package/dist/fields/react-fancy.d.ts +3 -3
  40. package/dist/index.cjs +11009 -10282
  41. package/dist/index.cjs.map +1 -1
  42. package/dist/index.d.cts +65 -36
  43. package/dist/index.d.ts +65 -36
  44. package/dist/index.js +22 -19
  45. package/dist/index.js.map +1 -1
  46. package/dist/layout/index.d.cts +1 -1
  47. package/dist/layout/index.d.ts +1 -1
  48. package/dist/llm/prism.cjs.map +1 -1
  49. package/dist/llm/prism.d.cts +1 -2
  50. package/dist/llm/prism.d.ts +1 -2
  51. package/dist/llm/prism.js +1 -1
  52. package/dist/llm/vercel-ai.cjs.map +1 -1
  53. package/dist/llm/vercel-ai.d.cts +1 -2
  54. package/dist/llm/vercel-ai.d.ts +1 -2
  55. package/dist/llm/vercel-ai.js +1 -1
  56. package/dist/registry/index.d.cts +20 -9
  57. package/dist/registry/index.d.ts +20 -9
  58. package/dist/{registry-CntAdUcY.d.cts → registry-BcgllSk2.d.cts} +1 -1
  59. package/dist/{registry-DYoV-MQi.d.ts → registry-h-2QswZ5.d.ts} +1 -1
  60. package/dist/registry.cjs +11252 -10409
  61. package/dist/registry.cjs.map +1 -1
  62. package/dist/registry.js +5 -4
  63. package/dist/{run-cohort-C1nRh_mi.d.ts → run-cohort-CjUBWg6X.d.ts} +2 -2
  64. package/dist/{run-cohort-CBRAUj-z.d.cts → run-cohort-DL9JzzPU.d.cts} +2 -2
  65. package/dist/{run-flow-2XsHBwpd.d.cts → run-flow-B_8hgO5_.d.cts} +1 -1
  66. package/dist/{run-flow-D7AOCcfE.d.ts → run-flow-CxEGBOxd.d.ts} +1 -1
  67. package/dist/runtime/index.d.cts +5 -5
  68. package/dist/runtime/index.d.ts +5 -5
  69. package/dist/runtime.cjs +10843 -10194
  70. package/dist/runtime.cjs.map +1 -1
  71. package/dist/runtime.js +5 -5
  72. package/dist/schema/index.d.cts +19 -6
  73. package/dist/schema/index.d.ts +19 -6
  74. package/dist/schema.cjs +881 -9142
  75. package/dist/schema.cjs.map +1 -1
  76. package/dist/schema.js +4 -5
  77. package/dist/screens.cjs +842 -86
  78. package/dist/screens.cjs.map +1 -1
  79. package/dist/screens.d.cts +2 -2
  80. package/dist/screens.d.ts +2 -2
  81. package/dist/screens.js +7 -6
  82. package/dist/screens.js.map +1 -1
  83. package/dist/terminal/fancy-term-host.cjs +99 -0
  84. package/dist/terminal/fancy-term-host.cjs.map +1 -0
  85. package/dist/terminal/fancy-term-host.d.cts +76 -0
  86. package/dist/terminal/fancy-term-host.d.ts +76 -0
  87. package/dist/terminal/fancy-term-host.js +92 -0
  88. package/dist/terminal/fancy-term-host.js.map +1 -0
  89. package/dist/types-B-Syk9-M.d.cts +620 -0
  90. package/dist/types-B-Syk9-M.d.ts +620 -0
  91. package/dist/{types-D71SKA5A.d.cts → types-C2ATTmjN.d.cts} +1 -1
  92. package/dist/{types-Ckhz-YwC.d.ts → types-VunLGqrn.d.ts} +1 -1
  93. package/dist/ux.cjs +885 -9142
  94. package/dist/ux.cjs.map +1 -1
  95. package/dist/ux.d.cts +2 -2
  96. package/dist/ux.d.ts +2 -2
  97. package/dist/ux.js +2 -3
  98. package/dist/ux.js.map +1 -1
  99. package/package.json +11 -1
  100. package/dist/capabilities-BYa5p5jw.d.cts +0 -112
  101. package/dist/capabilities-COOXRiNL.d.ts +0 -112
  102. package/dist/chunk-5H54OTKT.js.map +0 -1
  103. package/dist/chunk-EO6444T2.js.map +0 -1
  104. package/dist/chunk-JF6WCRBU.js.map +0 -1
  105. package/dist/chunk-MBVX4ZRB.js.map +0 -1
  106. package/dist/chunk-UM4C46AF.js +0 -103
  107. package/dist/chunk-UM4C46AF.js.map +0 -1
  108. package/dist/chunk-USL4FMFU.js +0 -41
  109. package/dist/chunk-USL4FMFU.js.map +0 -1
  110. package/dist/chunk-W5DPKJY4.js.map +0 -1
  111. package/dist/types-JFYjPJAG.d.cts +0 -333
  112. 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
- 27 builtins, grouped by category. Ids are namespaced (`@particle-academy/<name>`)
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
- | `layout` / `annotation` | `lane`, `note` — visual only, never executed |
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-JFYjPJAG.js';
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-JFYjPJAG.cjs';
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-JFYjPJAG.cjs';
4
- import { C as ConfigField } from './types-D71SKA5A.cjs';
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-JFYjPJAG.js';
4
- import { C as ConfigField } from './types-Ckhz-YwC.js';
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 = {