@particle-academy/fancy-flow 0.65.1 → 0.66.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.
Files changed (106) 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-2QXKDLGT.js +58 -0
  7. package/dist/chunk-2QXKDLGT.js.map +1 -0
  8. package/dist/{chunk-77V4QC6Y.js → chunk-B7HKJJVV.js} +3 -3
  9. package/dist/{chunk-77V4QC6Y.js.map → chunk-B7HKJJVV.js.map} +1 -1
  10. package/dist/{chunk-MBVX4ZRB.js → chunk-FNYLKSFJ.js} +3 -3
  11. package/dist/{chunk-MBVX4ZRB.js.map → chunk-FNYLKSFJ.js.map} +1 -1
  12. package/dist/{chunk-JF6WCRBU.js → chunk-HQGOFGAL.js} +861 -40
  13. package/dist/chunk-HQGOFGAL.js.map +1 -0
  14. package/dist/{chunk-5H54OTKT.js → chunk-IEYCNFXZ.js} +3 -3
  15. package/dist/{chunk-5H54OTKT.js.map → chunk-IEYCNFXZ.js.map} +1 -1
  16. package/dist/{chunk-W5DPKJY4.js → chunk-MTONBM53.js} +4 -4
  17. package/dist/chunk-MTONBM53.js.map +1 -0
  18. package/dist/{chunk-RIAFHQT5.js → chunk-PNHZHEWE.js} +3 -3
  19. package/dist/{chunk-RIAFHQT5.js.map → chunk-PNHZHEWE.js.map} +1 -1
  20. package/dist/{chunk-EO6444T2.js → chunk-UCCTXJXL.js} +4 -4
  21. package/dist/{chunk-EO6444T2.js.map → chunk-UCCTXJXL.js.map} +1 -1
  22. package/dist/connectors.d.cts +2 -2
  23. package/dist/connectors.d.ts +2 -2
  24. package/dist/durable/index.d.cts +2 -2
  25. package/dist/durable/index.d.ts +2 -2
  26. package/dist/durable.cjs +837 -47
  27. package/dist/durable.cjs.map +1 -1
  28. package/dist/durable.js +2 -3
  29. package/dist/durable.js.map +1 -1
  30. package/dist/engine.cjs +843 -132
  31. package/dist/engine.cjs.map +1 -1
  32. package/dist/engine.d.cts +6 -7
  33. package/dist/engine.d.ts +6 -7
  34. package/dist/engine.js +5 -6
  35. package/dist/engine.js.map +1 -1
  36. package/dist/fields/react-fancy.d.cts +3 -3
  37. package/dist/fields/react-fancy.d.ts +3 -3
  38. package/dist/index.cjs +853 -140
  39. package/dist/index.cjs.map +1 -1
  40. package/dist/index.d.cts +65 -36
  41. package/dist/index.d.ts +65 -36
  42. package/dist/index.js +19 -18
  43. package/dist/index.js.map +1 -1
  44. package/dist/layout/index.d.cts +1 -1
  45. package/dist/layout/index.d.ts +1 -1
  46. package/dist/llm/prism.cjs.map +1 -1
  47. package/dist/llm/prism.d.cts +1 -2
  48. package/dist/llm/prism.d.ts +1 -2
  49. package/dist/llm/prism.js +1 -1
  50. package/dist/llm/vercel-ai.cjs.map +1 -1
  51. package/dist/llm/vercel-ai.d.cts +1 -2
  52. package/dist/llm/vercel-ai.d.ts +1 -2
  53. package/dist/llm/vercel-ai.js +1 -1
  54. package/dist/registry/index.d.cts +5 -6
  55. package/dist/registry/index.d.ts +5 -6
  56. package/dist/{registry-CntAdUcY.d.cts → registry-BcgllSk2.d.cts} +1 -1
  57. package/dist/{registry-DYoV-MQi.d.ts → registry-h-2QswZ5.d.ts} +1 -1
  58. package/dist/registry.cjs +867 -37
  59. package/dist/registry.cjs.map +1 -1
  60. package/dist/registry.js +3 -3
  61. package/dist/{run-cohort-C1nRh_mi.d.ts → run-cohort-CjUBWg6X.d.ts} +2 -2
  62. package/dist/{run-cohort-CBRAUj-z.d.cts → run-cohort-DL9JzzPU.d.cts} +2 -2
  63. package/dist/{run-flow-2XsHBwpd.d.cts → run-flow-B_8hgO5_.d.cts} +1 -1
  64. package/dist/{run-flow-D7AOCcfE.d.ts → run-flow-CxEGBOxd.d.ts} +1 -1
  65. package/dist/runtime/index.d.cts +5 -5
  66. package/dist/runtime/index.d.ts +5 -5
  67. package/dist/runtime.cjs +837 -36
  68. package/dist/runtime.cjs.map +1 -1
  69. package/dist/runtime.js +4 -4
  70. package/dist/schema/index.d.cts +19 -6
  71. package/dist/schema/index.d.ts +19 -6
  72. package/dist/schema.cjs +837 -36
  73. package/dist/schema.cjs.map +1 -1
  74. package/dist/schema.js +4 -4
  75. package/dist/screens.cjs +837 -36
  76. package/dist/screens.cjs.map +1 -1
  77. package/dist/screens.d.cts +2 -2
  78. package/dist/screens.d.ts +2 -2
  79. package/dist/screens.js +5 -5
  80. package/dist/terminal/fancy-term-host.cjs +99 -0
  81. package/dist/terminal/fancy-term-host.cjs.map +1 -0
  82. package/dist/terminal/fancy-term-host.d.cts +76 -0
  83. package/dist/terminal/fancy-term-host.d.ts +76 -0
  84. package/dist/terminal/fancy-term-host.js +92 -0
  85. package/dist/terminal/fancy-term-host.js.map +1 -0
  86. package/dist/types-B-Syk9-M.d.cts +620 -0
  87. package/dist/types-B-Syk9-M.d.ts +620 -0
  88. package/dist/{types-D71SKA5A.d.cts → types-C2ATTmjN.d.cts} +1 -1
  89. package/dist/{types-Ckhz-YwC.d.ts → types-VunLGqrn.d.ts} +1 -1
  90. package/dist/ux.cjs +845 -39
  91. package/dist/ux.cjs.map +1 -1
  92. package/dist/ux.d.cts +14 -2
  93. package/dist/ux.d.ts +14 -2
  94. package/dist/ux.js +10 -5
  95. package/dist/ux.js.map +1 -1
  96. package/package.json +11 -1
  97. package/dist/capabilities-BYa5p5jw.d.cts +0 -112
  98. package/dist/capabilities-COOXRiNL.d.ts +0 -112
  99. package/dist/chunk-JF6WCRBU.js.map +0 -1
  100. package/dist/chunk-UM4C46AF.js +0 -103
  101. package/dist/chunk-UM4C46AF.js.map +0 -1
  102. package/dist/chunk-USL4FMFU.js +0 -41
  103. package/dist/chunk-USL4FMFU.js.map +0 -1
  104. package/dist/chunk-W5DPKJY4.js.map +0 -1
  105. package/dist/types-JFYjPJAG.d.cts +0 -333
  106. package/dist/types-JFYjPJAG.d.ts +0 -333
package/dist/ux.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { EffectRegistry, DispatchActor } from '@particle-academy/fancy-auto-common';
2
2
  export { AutoActivityEvent } from '@particle-academy/fancy-auto-common';
3
- import { a as NodeCategory, C as ConfigField } from './types-D71SKA5A.cjs';
4
- import { E as ExecutorRegistry } from './types-JFYjPJAG.cjs';
3
+ import { a as NodeCategory, C as ConfigField } from './types-C2ATTmjN.cjs';
4
+ import { E as ExecutorRegistry } from './types-B-Syk9-M.cjs';
5
5
  import 'react';
6
6
  import '@xyflow/react';
7
7
  import './pause-9iT4tCEV.cjs';
@@ -20,6 +20,18 @@ type UxEffectMeta = {
20
20
  category?: NodeCategory;
21
21
  /** Config form fields = the effect's params. */
22
22
  configSchema?: ConfigField[];
23
+ /**
24
+ * Include the executor's exact resolved input-port map as `$inputs` in the
25
+ * effect params. Off by default so existing effects keep their payload shape.
26
+ */
27
+ includeInputs?: boolean;
28
+ /**
29
+ * Make this UX node an inline step instead of a terminal notification. It
30
+ * gains an `out` port, waits for the effect Promise, then emits its `in`
31
+ * payload unchanged. This is the native shape for dialogs/overlays whose
32
+ * lifetime gates the rest of a workflow.
33
+ */
34
+ passThrough?: boolean;
23
35
  };
24
36
  type FlowRunnerUxOptions = {
25
37
  /** Named host UX effects the flow can invoke. */
package/dist/ux.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { EffectRegistry, DispatchActor } from '@particle-academy/fancy-auto-common';
2
2
  export { AutoActivityEvent } from '@particle-academy/fancy-auto-common';
3
- import { a as NodeCategory, C as ConfigField } from './types-Ckhz-YwC.js';
4
- import { E as ExecutorRegistry } from './types-JFYjPJAG.js';
3
+ import { a as NodeCategory, C as ConfigField } from './types-VunLGqrn.js';
4
+ import { E as ExecutorRegistry } from './types-B-Syk9-M.js';
5
5
  import 'react';
6
6
  import '@xyflow/react';
7
7
  import './pause-9iT4tCEV.js';
@@ -20,6 +20,18 @@ type UxEffectMeta = {
20
20
  category?: NodeCategory;
21
21
  /** Config form fields = the effect's params. */
22
22
  configSchema?: ConfigField[];
23
+ /**
24
+ * Include the executor's exact resolved input-port map as `$inputs` in the
25
+ * effect params. Off by default so existing effects keep their payload shape.
26
+ */
27
+ includeInputs?: boolean;
28
+ /**
29
+ * Make this UX node an inline step instead of a terminal notification. It
30
+ * gains an `out` port, waits for the effect Promise, then emits its `in`
31
+ * payload unchanged. This is the native shape for dialogs/overlays whose
32
+ * lifetime gates the rest of a workflow.
33
+ */
34
+ passThrough?: boolean;
23
35
  };
24
36
  type FlowRunnerUxOptions = {
25
37
  /** Named host UX effects the flow can invoke. */
package/dist/ux.js CHANGED
@@ -1,6 +1,6 @@
1
- import { registerNodeKind } from './chunk-JF6WCRBU.js';
1
+ import { registerNodeKind } from './chunk-HQGOFGAL.js';
2
2
  import './chunk-F5RPRB7A.js';
3
- import './chunk-USL4FMFU.js';
3
+ import './chunk-2QXKDLGT.js';
4
4
  import { useMemo } from 'react';
5
5
  import { createEffectDispatcher } from '@particle-academy/fancy-auto-common';
6
6
 
@@ -15,12 +15,15 @@ function createFlowRunnerUx(options) {
15
15
  const dispatcher = createEffectDispatcher(effects, { actor, targetKind: "ux" });
16
16
  const executors = {};
17
17
  for (const name of Object.keys(effects)) {
18
- executors[kindFor(name)] = async ({ node }) => {
19
- const params = node.data?.config ?? {};
18
+ executors[kindFor(name)] = async ({ node, inputs }) => {
19
+ const m = meta[name] ?? {};
20
+ const config = node.data?.config ?? {};
21
+ const params = m.includeInputs ? { ...config, $inputs: inputs } : config;
20
22
  const result = await dispatcher.dispatch(name, params);
21
23
  if (result && typeof result === "object" && ("branch" in result || "__port" in result)) {
22
24
  return result;
23
25
  }
26
+ if (m.passThrough) return inputs.in ?? inputs;
24
27
  return { effect: name, result };
25
28
  };
26
29
  }
@@ -35,7 +38,9 @@ function createFlowRunnerUx(options) {
35
38
  icon: m.icon ?? "\u2728",
36
39
  accent: m.accent ?? "#8b5cf6",
37
40
  inputs: [{ id: "in" }],
38
- outputs: [],
41
+ outputs: m.passThrough ? [{ id: "out" }] : [],
42
+ emits: m.passThrough ? "input" : void 0,
43
+ sideEffects: "unsafe-to-replay",
39
44
  configSchema: m.configSchema
40
45
  });
41
46
  }
package/dist/ux.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ux.ts"],"names":[],"mappings":";;;;;;AAyEA,IAAM,cAAA,GAAiB,CAAC,IAAA,KAAiB,CAAA,GAAA,EAAM,IAAI,CAAA,CAAA;AAG5C,SAAS,mBAAmB,OAAA,EAA4C;AAC7E,EAAA,MAAM;AAAA,IACJ,OAAA;AAAA,IACA,OAAO,EAAC;AAAA,IACR,KAAA,GAAQ,EAAE,EAAA,EAAI,MAAA,EAAQ,QAAQ,MAAA,EAAO;AAAA,IACrC,OAAA,GAAU;AAAA,GACZ,GAAI,OAAA;AAEJ,EAAA,MAAM,aAAa,sBAAA,CAAuB,OAAA,EAAS,EAAE,KAAA,EAAO,UAAA,EAAY,MAAM,CAAA;AAE9E,EAAA,MAAM,YAA8B,EAAC;AACrC,EAAA,KAAA,MAAW,IAAA,IAAQ,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA,EAAG;AACvC,IAAA,SAAA,CAAU,QAAQ,IAAI,CAAC,IAAI,OAAO,EAAE,MAAK,KAA0B;AACjE,MAAA,MAAM,MAAA,GAAU,IAAA,CAAK,IAAA,EAA2D,MAAA,IAAU,EAAC;AAC3F,MAAA,MAAM,MAAA,GAAS,MAAM,UAAA,CAAW,QAAA,CAAS,MAAM,MAAM,CAAA;AAKrD,MAAA,IAAI,UAAU,OAAO,MAAA,KAAW,aAAa,QAAA,IAAY,MAAA,IAAU,YAAY,MAAA,CAAA,EAAS;AACtF,QAAA,OAAO,MAAA;AAAA,MACT;AACA,MAAA,OAAO,EAAE,MAAA,EAAQ,IAAA,EAAM,MAAA,EAAO;AAAA,IAChC,CAAA;AAAA,EACF;AAEA,EAAA,MAAM,gBAAgB,MAAM;AAC1B,IAAA,KAAA,MAAW,IAAA,IAAQ,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA,EAAG;AACvC,MAAA,MAAM,CAAA,GAAI,IAAA,CAAK,IAAI,CAAA,IAAK,EAAC;AACzB,MAAA,gBAAA,CAAiB;AAAA,QACf,IAAA,EAAM,QAAQ,IAAI,CAAA;AAAA,QAClB,QAAA,EAAU,EAAE,QAAA,IAAY,QAAA;AAAA,QACxB,KAAA,EAAO,EAAE,KAAA,IAAS,IAAA;AAAA,QAClB,WAAA,EAAa,CAAA,CAAE,WAAA,IAAe,CAAA,uBAAA,EAA0B,IAAI,CAAA,CAAA,CAAA;AAAA,QAC5D,IAAA,EAAM,EAAE,IAAA,IAAQ,QAAA;AAAA,QAChB,MAAA,EAAQ,EAAE,MAAA,IAAU,SAAA;AAAA,QACpB,MAAA,EAAQ,CAAC,EAAE,EAAA,EAAI,MAAM,CAAA;AAAA,QACrB,SAAS,EAAC;AAAA,QACV,cAAc,CAAA,CAAE;AAAA,OACjB,CAAA;AAAA,IACH;AAAA,EACF,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,SAAA;AAAA,IACA,UAAU,UAAA,CAAW,QAAA;AAAA,IACrB,aAAa,UAAA,CAAW,KAAA;AAAA,IACxB;AAAA,GACF;AACF;AAMO,SAAS,gBAAgB,OAAA,EAA4C;AAC1E,EAAA,MAAM,MAAM,CAAA,EAAG,MAAA,CAAO,IAAA,CAAK,OAAA,CAAQ,OAAO,CAAA,CAAE,IAAA,EAAK,CAAE,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA,EAAI,OAAA,CAAQ,KAAA,EAAO,MAAM,MAAM,CAAA,CAAA;AAE3F,EAAA,OAAO,QAAQ,MAAM,kBAAA,CAAmB,OAAO,CAAA,EAAG,CAAC,GAAG,CAAC,CAAA;AACzD","file":"ux.js","sourcesContent":["/**\n * FlowRunnerUx — the **flow-driven UX** bridge. The headless counterpart to\n * agent-integrations: where that wires an *agent* to host UI surfaces, this\n * wires a *running flow* to host UX. Both share the same primitives from\n * `@particle-academy/fancy-auto-common` (activity bus, effect dispatch).\n *\n * The host registers named UX effects (toast, navigate, confirm, …); this turns\n * each into a flow executor keyed by a node kind (`ux_<effect>` by default), so\n * dropping a `ux_toast` node into a `<FlowEditor>` and running it fires the\n * host's toast. Every dispatch broadcasts an `AutoActivityEvent` (source:\"flow\")\n * for presence / logging. Human-in-the-loop is free: an effect that returns a\n * Promise (e.g. an approval dialog) pauses the run until the user resolves it.\n *\n * const ux = createFlowRunnerUx({\n * effects: {\n * toast: ({ message }) => toast({ title: message }),\n * navigate:({ to }) => router.visit(to),\n * confirm: ({ prompt }) => new Promise(res => openDialog(prompt, res)), // pauses the run\n * },\n * });\n * ux.registerKinds(); // adds ux_toast / ux_navigate / ux_confirm to the palette\n * <FlowEditor initial={graph} executors={ux.executors} />\n */\nimport { useMemo } from \"react\";\nimport {\n createEffectDispatcher,\n type DispatchActor,\n type EffectRegistry,\n} from \"@particle-academy/fancy-auto-common\";\nimport { registerNodeKind } from \"./registry/registry\";\nimport type { ConfigField, NodeCategory } from \"./registry/types\";\nimport type { ExecutorRegistry, FlowNode } from \"./types\";\n\nexport type { AutoActivityEvent } from \"@particle-academy/fancy-auto-common\";\n\n/** Per-effect presentation for the palette node kind that drives it. */\nexport type UxEffectMeta = {\n /** Palette label. Default: the effect name. */\n label?: string;\n /** One-line palette description. */\n description?: string;\n /** Emoji / glyph for the node header. */\n icon?: string;\n /** Header accent color. */\n accent?: string;\n /** Palette grouping. Default \"output\". */\n category?: NodeCategory;\n /** Config form fields = the effect's params. */\n configSchema?: ConfigField[];\n};\n\nexport type FlowRunnerUxOptions = {\n /** Named host UX effects the flow can invoke. */\n effects: EffectRegistry;\n /** Optional per-effect palette metadata (used by `registerKinds`). */\n meta?: Record<string, UxEffectMeta>;\n /** Identifies the flow run in emitted activity. Default `{ id: \"flow\", source: \"flow\" }`. */\n actor?: DispatchActor;\n /** Map an effect name to its node-kind name. Default `ux_<effect>`. */\n kindFor?: (effectName: string) => string;\n};\n\nexport type FlowRunnerUx = {\n /** Executor registry to hand to `<FlowEditor executors>` or `runFlow`. */\n executors: ExecutorRegistry;\n /** Invoke an effect imperatively (also emits activity). */\n dispatch: <R = unknown>(name: string, params?: unknown) => Promise<R>;\n /** All effect names. */\n effectNames: () => string[];\n /** Register a palette node kind per effect (`ux_<effect>`). Idempotent. */\n registerKinds: () => void;\n};\n\nconst defaultKindFor = (name: string) => `ux_${name}`;\n\n/** Build a FlowRunnerUx from a set of host effects. Framework-agnostic. */\nexport function createFlowRunnerUx(options: FlowRunnerUxOptions): FlowRunnerUx {\n const {\n effects,\n meta = {},\n actor = { id: \"flow\", source: \"flow\" },\n kindFor = defaultKindFor,\n } = options;\n\n const dispatcher = createEffectDispatcher(effects, { actor, targetKind: \"ux\" });\n\n const executors: ExecutorRegistry = {};\n for (const name of Object.keys(effects)) {\n executors[kindFor(name)] = async ({ node }: { node: FlowNode }) => {\n const params = (node.data as { config?: Record<string, unknown> } | undefined)?.config ?? {};\n const result = await dispatcher.dispatch(name, params);\n // A UX effect can drive flow control: if it returns the decision sugar\n // (`{ branch }` or `{ __port }`) — e.g. an interactive \"choose\" effect that\n // awaits a human pick and returns the chosen port — pass it straight\n // through so runFlow routes on it. Otherwise wrap the result for the feed.\n if (result && typeof result === \"object\" && (\"branch\" in result || \"__port\" in result)) {\n return result;\n }\n return { effect: name, result };\n };\n }\n\n const registerKinds = () => {\n for (const name of Object.keys(effects)) {\n const m = meta[name] ?? {};\n registerNodeKind({\n name: kindFor(name),\n category: m.category ?? \"output\",\n label: m.label ?? name,\n description: m.description ?? `Flow-driven UX effect: ${name}.`,\n icon: m.icon ?? \"✨\",\n accent: m.accent ?? \"#8b5cf6\",\n inputs: [{ id: \"in\" }],\n outputs: [],\n configSchema: m.configSchema,\n });\n }\n };\n\n return {\n executors,\n dispatch: dispatcher.dispatch as FlowRunnerUx[\"dispatch\"],\n effectNames: dispatcher.names,\n registerKinds,\n };\n}\n\n/**\n * React hook form — memoizes on the effect-name set + actor id so the returned\n * executors keep a stable identity across renders.\n */\nexport function useFlowRunnerUx(options: FlowRunnerUxOptions): FlowRunnerUx {\n const key = `${Object.keys(options.effects).sort().join(\",\")}|${options.actor?.id ?? \"flow\"}`;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n return useMemo(() => createFlowRunnerUx(options), [key]);\n}\n"]}
1
+ {"version":3,"sources":["../src/ux.ts"],"names":[],"mappings":"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","file":"ux.js","sourcesContent":["/**\n * FlowRunnerUx — the **flow-driven UX** bridge. The headless counterpart to\n * agent-integrations: where that wires an *agent* to host UI surfaces, this\n * wires a *running flow* to host UX. Both share the same primitives from\n * `@particle-academy/fancy-auto-common` (activity bus, effect dispatch).\n *\n * The host registers named UX effects (toast, navigate, confirm, …); this turns\n * each into a flow executor keyed by a node kind (`ux_<effect>` by default), so\n * dropping a `ux_toast` node into a `<FlowEditor>` and running it fires the\n * host's toast. Every dispatch broadcasts an `AutoActivityEvent` (source:\"flow\")\n * for presence / logging. Human-in-the-loop is free: an effect that returns a\n * Promise (e.g. an approval dialog) pauses the run until the user resolves it.\n *\n * const ux = createFlowRunnerUx({\n * effects: {\n * toast: ({ message }) => toast({ title: message }),\n * navigate:({ to }) => router.visit(to),\n * confirm: ({ prompt }) => new Promise(res => openDialog(prompt, res)), // pauses the run\n * },\n * });\n * ux.registerKinds(); // adds ux_toast / ux_navigate / ux_confirm to the palette\n * <FlowEditor initial={graph} executors={ux.executors} />\n */\nimport { useMemo } from \"react\";\nimport {\n createEffectDispatcher,\n type DispatchActor,\n type EffectRegistry,\n} from \"@particle-academy/fancy-auto-common\";\nimport { registerNodeKind } from \"./registry/registry\";\nimport type { ConfigField, NodeCategory } from \"./registry/types\";\nimport type { ExecutorRegistry, FlowNode } from \"./types\";\n\nexport type { AutoActivityEvent } from \"@particle-academy/fancy-auto-common\";\n\n/** Per-effect presentation for the palette node kind that drives it. */\nexport type UxEffectMeta = {\n /** Palette label. Default: the effect name. */\n label?: string;\n /** One-line palette description. */\n description?: string;\n /** Emoji / glyph for the node header. */\n icon?: string;\n /** Header accent color. */\n accent?: string;\n /** Palette grouping. Default \"output\". */\n category?: NodeCategory;\n /** Config form fields = the effect's params. */\n configSchema?: ConfigField[];\n /**\n * Include the executor's exact resolved input-port map as `$inputs` in the\n * effect params. Off by default so existing effects keep their payload shape.\n */\n includeInputs?: boolean;\n /**\n * Make this UX node an inline step instead of a terminal notification. It\n * gains an `out` port, waits for the effect Promise, then emits its `in`\n * payload unchanged. This is the native shape for dialogs/overlays whose\n * lifetime gates the rest of a workflow.\n */\n passThrough?: boolean;\n};\n\nexport type FlowRunnerUxOptions = {\n /** Named host UX effects the flow can invoke. */\n effects: EffectRegistry;\n /** Optional per-effect palette metadata (used by `registerKinds`). */\n meta?: Record<string, UxEffectMeta>;\n /** Identifies the flow run in emitted activity. Default `{ id: \"flow\", source: \"flow\" }`. */\n actor?: DispatchActor;\n /** Map an effect name to its node-kind name. Default `ux_<effect>`. */\n kindFor?: (effectName: string) => string;\n};\n\nexport type FlowRunnerUx = {\n /** Executor registry to hand to `<FlowEditor executors>` or `runFlow`. */\n executors: ExecutorRegistry;\n /** Invoke an effect imperatively (also emits activity). */\n dispatch: <R = unknown>(name: string, params?: unknown) => Promise<R>;\n /** All effect names. */\n effectNames: () => string[];\n /** Register a palette node kind per effect (`ux_<effect>`). Idempotent. */\n registerKinds: () => void;\n};\n\nconst defaultKindFor = (name: string) => `ux_${name}`;\n\n/** Build a FlowRunnerUx from a set of host effects. Framework-agnostic. */\nexport function createFlowRunnerUx(options: FlowRunnerUxOptions): FlowRunnerUx {\n const {\n effects,\n meta = {},\n actor = { id: \"flow\", source: \"flow\" },\n kindFor = defaultKindFor,\n } = options;\n\n const dispatcher = createEffectDispatcher(effects, { actor, targetKind: \"ux\" });\n\n const executors: ExecutorRegistry = {};\n for (const name of Object.keys(effects)) {\n executors[kindFor(name)] = async ({ node, inputs }: { node: FlowNode; inputs: Record<string, unknown> }) => {\n const m = meta[name] ?? {};\n const config = (node.data as { config?: Record<string, unknown> } | undefined)?.config ?? {};\n const params = m.includeInputs ? { ...config, $inputs: inputs } : config;\n const result = await dispatcher.dispatch(name, params);\n // A UX effect can drive flow control: if it returns the decision sugar\n // (`{ branch }` or `{ __port }`) — e.g. an interactive \"choose\" effect that\n // awaits a human pick and returns the chosen port — pass it straight\n // through so runFlow routes on it. Otherwise wrap the result for the feed.\n if (result && typeof result === \"object\" && (\"branch\" in result || \"__port\" in result)) {\n return result;\n }\n if (m.passThrough) return inputs.in ?? inputs;\n return { effect: name, result };\n };\n }\n\n const registerKinds = () => {\n for (const name of Object.keys(effects)) {\n const m = meta[name] ?? {};\n registerNodeKind({\n name: kindFor(name),\n category: m.category ?? \"output\",\n label: m.label ?? name,\n description: m.description ?? `Flow-driven UX effect: ${name}.`,\n icon: m.icon ?? \"✨\",\n accent: m.accent ?? \"#8b5cf6\",\n inputs: [{ id: \"in\" }],\n outputs: m.passThrough ? [{ id: \"out\" }] : [],\n emits: m.passThrough ? \"input\" : undefined,\n sideEffects: \"unsafe-to-replay\",\n configSchema: m.configSchema,\n });\n }\n };\n\n return {\n executors,\n dispatch: dispatcher.dispatch as FlowRunnerUx[\"dispatch\"],\n effectNames: dispatcher.names,\n registerKinds,\n };\n}\n\n/**\n * React hook form — memoizes on the effect-name set + actor id so the returned\n * executors keep a stable identity across renders.\n */\nexport function useFlowRunnerUx(options: FlowRunnerUxOptions): FlowRunnerUx {\n const key = `${Object.keys(options.effects).sort().join(\",\")}|${options.actor?.id ?? \"flow\"}`;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n return useMemo(() => createFlowRunnerUx(options), [key]);\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@particle-academy/fancy-flow",
3
- "version": "0.65.1",
3
+ "version": "0.66.0",
4
4
  "description": "Workflow editor + runner. Six built-in node kits (trigger / action / decision / output / note / subgraph), tokenized theme, topological execution with per-node status. React-flow bundled; consumers npm install fancy-flow and get nothing extra.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -134,6 +134,16 @@
134
134
  "default": "./dist/llm/prism.cjs"
135
135
  }
136
136
  },
137
+ "./terminal/fancy-term-host": {
138
+ "import": {
139
+ "types": "./dist/terminal/fancy-term-host.d.ts",
140
+ "default": "./dist/terminal/fancy-term-host.js"
141
+ },
142
+ "require": {
143
+ "types": "./dist/terminal/fancy-term-host.d.cts",
144
+ "default": "./dist/terminal/fancy-term-host.cjs"
145
+ }
146
+ },
137
147
  "./fields/react-fancy": {
138
148
  "import": {
139
149
  "types": "./dist/fields/react-fancy.d.ts",
@@ -1,112 +0,0 @@
1
- import { F as FlowGraph } from './types-JFYjPJAG.cjs';
2
-
3
- /**
4
- * Host capabilities — the services core nodes need but must never depend on.
5
- *
6
- * A node that imports a provider SDK forces every consumer to install it: a
7
- * workflow app that never calls a model should not inherit an LLM dependency.
8
- * So core declares the CONTRACT and the host supplies the implementation, the
9
- * same arrangement `renderDocumentField` already uses for documents.
10
- *
11
- * That keeps opinionated nodes in core without their opinions: `llm_branch`
12
- * ships the routing semantics, port derivation and config UI, while whichever
13
- * client the host registers — Prism, an OpenAI SDK, a local model, a fake in a
14
- * test — decides how the question actually gets asked.
15
- *
16
- * Registration is deliberately explicit and typed per capability rather than a
17
- * stringly-keyed bag, so a missing one is a clear error at the seam instead of
18
- * an undefined somewhere downstream.
19
- */
20
- type LlmRoute = {
21
- port: string;
22
- description?: string;
23
- };
24
- type LlmRouteRequest = {
25
- /** Optional framing for the decision. */
26
- system?: string;
27
- /** What the model is deciding about. */
28
- prompt: string;
29
- /** The ports it must choose between. */
30
- routes: LlmRoute[];
31
- provider?: string;
32
- model?: string;
33
- /** Host-resolved credential reference, never a raw key. */
34
- credential?: string;
35
- };
36
- type LlmRouteChoice = {
37
- /** Must be one of the requested route ports. */
38
- port: string;
39
- /** Why — carried down the chosen port so a run is explainable afterwards. */
40
- reason?: string;
41
- };
42
- /**
43
- * The only thing core asks of an LLM: given routes, pick one.
44
- *
45
- * Deliberately not a general chat interface. A narrow contract is one a host
46
- * can satisfy in a few lines over any SDK, and it keeps the choice
47
- * machine-checkable — an implementation should constrain the model to the
48
- * declared ports (structured output / enum) rather than parsing prose.
49
- */
50
- type LlmClient = {
51
- chooseRoute: (request: LlmRouteRequest) => Promise<LlmRouteChoice> | LlmRouteChoice;
52
- };
53
- /** Install the host's LLM client. Returns an unregister function. */
54
- declare function registerLlmClient(client: LlmClient): () => void;
55
- declare function getLlmClient(): LlmClient | null;
56
- /**
57
- * Why a workflow reference could not be resolved.
58
- *
59
- * `missing` and `version-mismatch` are deliberately distinct. Collapsing them
60
- * into a bare null makes "no such workflow" indistinguishable from "that
61
- * workflow exists, but it is not the one you pinned" — and the second wants an
62
- * error naming both versions, because it is the interesting failure.
63
- */
64
- type WorkflowResolutionFailure = {
65
- reason: "missing" | "version-mismatch";
66
- /** The version the host actually holds, when it holds one. */
67
- available?: number;
68
- message?: string;
69
- };
70
- type WorkflowResolution = FlowGraph | WorkflowResolutionFailure | null;
71
- /**
72
- * Resolve a workflow reference to a runnable graph.
73
- *
74
- * `subflow` names another workflow rather than embedding it, so the host owns
75
- * where workflows live — a database, a file, an API.
76
- *
77
- * ## Why `version` is here
78
- *
79
- * A workflow another workflow depends on is an INTERFACE, and interfaces need
80
- * pins. Without a version, a parent goes on calling `invoice-triage`, someone
81
- * edits that child, and the parent now runs different logic having reported
82
- * success the whole time — correct-looking, no error, wrong behaviour. The same
83
- * failure family as the 0.9.0 routing divergence.
84
- *
85
- * The parameter lives on the resolver rather than being encoded into the ref
86
- * string (`invoice-triage@3`) because a stringly-typed protocol is one every
87
- * host invents differently — the "three vocabularies for one node" problem.
88
- *
89
- * Raised by the MOIC Suite consumer, whose `workflow_ref` pins versions and
90
- * fails loudly on mismatch. Their point: a host COULD NOT implement pinning
91
- * before this, because the node had no way to ask and the resolver no way to
92
- * receive.
93
- *
94
- * Returning `null` still means "no such workflow". Return a
95
- * {@link WorkflowResolutionFailure} to distinguish a version mismatch.
96
- */
97
- type WorkflowResolver = (ref: string, version?: number) => Promise<WorkflowResolution> | WorkflowResolution;
98
- /** Narrow a resolver's return value to an explicit failure. */
99
- declare function isResolutionFailure(value: WorkflowResolution): value is WorkflowResolutionFailure;
100
- /** Install the host's workflow resolver. Returns an unregister function. */
101
- declare function registerWorkflowResolver(resolver: WorkflowResolver): () => void;
102
- declare function getWorkflowResolver(): WorkflowResolver | null;
103
- type CapabilityId = "llm" | "workflow_resolver" | "document";
104
- /**
105
- * Which capabilities are currently satisfied.
106
- *
107
- * Exists so a host (or the CLI, or an agent over MCP) can answer "what does
108
- * this graph need that I haven't wired?" BEFORE a run fails halfway through.
109
- */
110
- declare function capabilityStatus(): Record<CapabilityId, boolean>;
111
-
112
- export { type CapabilityId as C, type LlmClient as L, type WorkflowResolver as W, type LlmRouteRequest as a, type LlmRoute as b, type LlmRouteChoice as c, type WorkflowResolution as d, type WorkflowResolutionFailure as e, capabilityStatus as f, getLlmClient as g, getWorkflowResolver as h, isResolutionFailure as i, registerWorkflowResolver as j, registerLlmClient as r };
@@ -1,112 +0,0 @@
1
- import { F as FlowGraph } from './types-JFYjPJAG.js';
2
-
3
- /**
4
- * Host capabilities — the services core nodes need but must never depend on.
5
- *
6
- * A node that imports a provider SDK forces every consumer to install it: a
7
- * workflow app that never calls a model should not inherit an LLM dependency.
8
- * So core declares the CONTRACT and the host supplies the implementation, the
9
- * same arrangement `renderDocumentField` already uses for documents.
10
- *
11
- * That keeps opinionated nodes in core without their opinions: `llm_branch`
12
- * ships the routing semantics, port derivation and config UI, while whichever
13
- * client the host registers — Prism, an OpenAI SDK, a local model, a fake in a
14
- * test — decides how the question actually gets asked.
15
- *
16
- * Registration is deliberately explicit and typed per capability rather than a
17
- * stringly-keyed bag, so a missing one is a clear error at the seam instead of
18
- * an undefined somewhere downstream.
19
- */
20
- type LlmRoute = {
21
- port: string;
22
- description?: string;
23
- };
24
- type LlmRouteRequest = {
25
- /** Optional framing for the decision. */
26
- system?: string;
27
- /** What the model is deciding about. */
28
- prompt: string;
29
- /** The ports it must choose between. */
30
- routes: LlmRoute[];
31
- provider?: string;
32
- model?: string;
33
- /** Host-resolved credential reference, never a raw key. */
34
- credential?: string;
35
- };
36
- type LlmRouteChoice = {
37
- /** Must be one of the requested route ports. */
38
- port: string;
39
- /** Why — carried down the chosen port so a run is explainable afterwards. */
40
- reason?: string;
41
- };
42
- /**
43
- * The only thing core asks of an LLM: given routes, pick one.
44
- *
45
- * Deliberately not a general chat interface. A narrow contract is one a host
46
- * can satisfy in a few lines over any SDK, and it keeps the choice
47
- * machine-checkable — an implementation should constrain the model to the
48
- * declared ports (structured output / enum) rather than parsing prose.
49
- */
50
- type LlmClient = {
51
- chooseRoute: (request: LlmRouteRequest) => Promise<LlmRouteChoice> | LlmRouteChoice;
52
- };
53
- /** Install the host's LLM client. Returns an unregister function. */
54
- declare function registerLlmClient(client: LlmClient): () => void;
55
- declare function getLlmClient(): LlmClient | null;
56
- /**
57
- * Why a workflow reference could not be resolved.
58
- *
59
- * `missing` and `version-mismatch` are deliberately distinct. Collapsing them
60
- * into a bare null makes "no such workflow" indistinguishable from "that
61
- * workflow exists, but it is not the one you pinned" — and the second wants an
62
- * error naming both versions, because it is the interesting failure.
63
- */
64
- type WorkflowResolutionFailure = {
65
- reason: "missing" | "version-mismatch";
66
- /** The version the host actually holds, when it holds one. */
67
- available?: number;
68
- message?: string;
69
- };
70
- type WorkflowResolution = FlowGraph | WorkflowResolutionFailure | null;
71
- /**
72
- * Resolve a workflow reference to a runnable graph.
73
- *
74
- * `subflow` names another workflow rather than embedding it, so the host owns
75
- * where workflows live — a database, a file, an API.
76
- *
77
- * ## Why `version` is here
78
- *
79
- * A workflow another workflow depends on is an INTERFACE, and interfaces need
80
- * pins. Without a version, a parent goes on calling `invoice-triage`, someone
81
- * edits that child, and the parent now runs different logic having reported
82
- * success the whole time — correct-looking, no error, wrong behaviour. The same
83
- * failure family as the 0.9.0 routing divergence.
84
- *
85
- * The parameter lives on the resolver rather than being encoded into the ref
86
- * string (`invoice-triage@3`) because a stringly-typed protocol is one every
87
- * host invents differently — the "three vocabularies for one node" problem.
88
- *
89
- * Raised by the MOIC Suite consumer, whose `workflow_ref` pins versions and
90
- * fails loudly on mismatch. Their point: a host COULD NOT implement pinning
91
- * before this, because the node had no way to ask and the resolver no way to
92
- * receive.
93
- *
94
- * Returning `null` still means "no such workflow". Return a
95
- * {@link WorkflowResolutionFailure} to distinguish a version mismatch.
96
- */
97
- type WorkflowResolver = (ref: string, version?: number) => Promise<WorkflowResolution> | WorkflowResolution;
98
- /** Narrow a resolver's return value to an explicit failure. */
99
- declare function isResolutionFailure(value: WorkflowResolution): value is WorkflowResolutionFailure;
100
- /** Install the host's workflow resolver. Returns an unregister function. */
101
- declare function registerWorkflowResolver(resolver: WorkflowResolver): () => void;
102
- declare function getWorkflowResolver(): WorkflowResolver | null;
103
- type CapabilityId = "llm" | "workflow_resolver" | "document";
104
- /**
105
- * Which capabilities are currently satisfied.
106
- *
107
- * Exists so a host (or the CLI, or an agent over MCP) can answer "what does
108
- * this graph need that I haven't wired?" BEFORE a run fails halfway through.
109
- */
110
- declare function capabilityStatus(): Record<CapabilityId, boolean>;
111
-
112
- export { type CapabilityId as C, type LlmClient as L, type WorkflowResolver as W, type LlmRouteRequest as a, type LlmRoute as b, type LlmRouteChoice as c, type WorkflowResolution as d, type WorkflowResolutionFailure as e, capabilityStatus as f, getLlmClient as g, getWorkflowResolver as h, isResolutionFailure as i, registerWorkflowResolver as j, registerLlmClient as r };