@kiberon-labs/behave-graph-flow 2.0.0 → 3.0.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 (251) hide show
  1. package/.storybook/manager.ts +6 -0
  2. package/.storybook/preview.ts +49 -1
  3. package/.storybook/styles.css +9 -3
  4. package/.turbo/turbo-build.log +1 -1
  5. package/CHANGELOG.md +368 -0
  6. package/dist/AnyControlImpl-Ds-CShIB.js +20 -0
  7. package/dist/AnyControlImpl-Ds-CShIB.js.map +1 -0
  8. package/dist/DocumentationBrowserPanelImpl-deZNzFX8.js +166 -0
  9. package/dist/DocumentationBrowserPanelImpl-deZNzFX8.js.map +1 -0
  10. package/dist/index.css +36 -33
  11. package/dist/index.css.map +1 -1
  12. package/dist/index.d.ts +1865 -550
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +14357 -11221
  15. package/dist/index.js.map +1 -1
  16. package/dist/noteImpl-KkrrWgJd.js +242 -0
  17. package/dist/noteImpl-KkrrWgJd.js.map +1 -0
  18. package/dist/styles.module-CvmpDkZj.css +3 -0
  19. package/dist/styles.module-CvmpDkZj.css.map +1 -0
  20. package/dist/styles.module-DZxg8aW9.js +271 -0
  21. package/dist/styles.module-DZxg8aW9.js.map +1 -0
  22. package/dist/useChangeNodeData-ChQGK7AI.js +23 -0
  23. package/dist/useChangeNodeData-ChQGK7AI.js.map +1 -0
  24. package/docs/protocol.md +43 -20
  25. package/package.json +5 -9
  26. package/src/components/FloatingToolbar/index.module.css +5 -13
  27. package/src/components/FloatingToolbar/index.tsx +9 -9
  28. package/src/components/Flow.tsx +34 -23
  29. package/src/components/contextMenus/DynamicContextMenu.tsx +85 -0
  30. package/src/components/contextMenus/NodePicker.module.css +13 -13
  31. package/src/components/contextMenus/edge.tsx +9 -95
  32. package/src/components/contextMenus/node.tsx +9 -149
  33. package/src/components/contextMenus/selection.tsx +5 -71
  34. package/src/components/controls/any/AnyControlImpl.tsx +14 -0
  35. package/src/components/controls/any/index.tsx +13 -2
  36. package/src/components/edges/index.tsx +75 -69
  37. package/src/components/layoutController/index.module.css +3 -0
  38. package/src/components/layoutController/index.tsx +24 -1
  39. package/src/components/layoutController/utils.ts +46 -3
  40. package/src/components/menubar/defaults.tsx +55 -19
  41. package/src/components/menubar/menuItem.module.css +18 -3
  42. package/src/components/menubar/menuItem.tsx +34 -1
  43. package/src/components/nodes/behave/NodeContainer.module.css +26 -25
  44. package/src/components/nodes/group/index.tsx +3 -3
  45. package/src/components/nodes/wrapper/styles.module.css +6 -32
  46. package/src/components/panels/alignment/index.module.css +0 -10
  47. package/src/components/panels/alignment/index.tsx +4 -4
  48. package/src/components/panels/base/styles.module.css +2 -2
  49. package/src/components/panels/common/PanelHeader.module.css +24 -0
  50. package/src/components/panels/common/PanelHeader.tsx +22 -0
  51. package/src/components/panels/common/SectionTitle.module.css +13 -0
  52. package/src/components/panels/common/SectionTitle.tsx +10 -0
  53. package/src/components/panels/events/EditEventPanel.tsx +14 -5
  54. package/src/components/panels/events/ManageEventsPanel.tsx +11 -8
  55. package/src/components/panels/events/styles.module.css +6 -64
  56. package/src/components/panels/graphProperties/index.tsx +125 -0
  57. package/src/components/panels/history/index.tsx +2 -2
  58. package/src/components/panels/history/styles.module.css +0 -9
  59. package/src/components/panels/keymaps/index.module.css +3 -13
  60. package/src/components/panels/keymaps/index.tsx +1 -2
  61. package/src/components/panels/layers/index.tsx +20 -15
  62. package/src/components/panels/layers/styles.module.css +9 -12
  63. package/src/components/panels/legend/index.tsx +1 -1
  64. package/src/components/panels/logs/index.module.css +25 -19
  65. package/src/components/panels/logs/index.tsx +7 -7
  66. package/src/components/panels/nodeInputs/InputsGroup.tsx +1 -0
  67. package/src/components/panels/nodeInputs/NodeSettings.tsx +2 -2
  68. package/src/components/panels/nodeInputs/NodeTitleEditor.tsx +1 -1
  69. package/src/components/panels/nodeInputs/OutputsGroup.tsx +2 -12
  70. package/src/components/panels/nodeInputs/index.module.css +99 -75
  71. package/src/components/panels/nodeInputs/index.tsx +21 -11
  72. package/src/components/panels/nodeInputs/useNodeHandlers.ts +2 -2
  73. package/src/components/panels/nodeInputs/useNodeInputsData.ts +23 -43
  74. package/src/components/panels/nodePicker/index.tsx +8 -8
  75. package/src/components/panels/panel/index.module.css +7 -7
  76. package/src/components/panels/search/index.module.css +0 -50
  77. package/src/components/panels/search/index.tsx +2 -2
  78. package/src/components/panels/systemSettings/ConversionsSettings.tsx +203 -0
  79. package/src/components/panels/systemSettings/index.tsx +221 -176
  80. package/src/components/panels/systemSettings/styles.module.css +135 -8
  81. package/src/components/panels/traces/GridLines.tsx +1 -1
  82. package/src/components/panels/traces/TimeGrid.tsx +3 -3
  83. package/src/components/panels/traces/TraceLane.tsx +1 -1
  84. package/src/components/panels/traces/index.module.css +1 -8
  85. package/src/components/panels/traces/index.tsx +8 -4
  86. package/src/components/panels/traces/useDerivedSpans.ts +241 -146
  87. package/src/components/panels/traces/utils.ts +8 -0
  88. package/src/components/panels/variables/CreateVariableScreen.tsx +3 -3
  89. package/src/components/panels/variables/ManageVariablesScreen.tsx +12 -9
  90. package/src/components/panels/variables/index.tsx +2 -2
  91. package/src/components/panels/variables/styles.module.css +4 -91
  92. package/src/components/primitives/icon.module.css +4 -4
  93. package/src/components/sockets/input/index.tsx +9 -2
  94. package/src/components/sockets/input/styles.module.css +2 -3
  95. package/src/components/sockets/output/index.tsx +10 -3
  96. package/src/components/sockets/output/styles.module.css +1 -6
  97. package/src/css/notes.css +135 -0
  98. package/src/css/prosemirror.css +3 -3
  99. package/src/css/rc-dock.css +143 -43
  100. package/src/css/rc-menu.css +56 -55
  101. package/src/css/themes/kiberon.css +127 -0
  102. package/src/css/vars.css +197 -13
  103. package/src/css/vscode-elements.css +124 -0
  104. package/src/generators/CallSubgraphGenerator.tsx +136 -0
  105. package/src/generators/CustomEventOnTriggeredGenerator.tsx +2 -2
  106. package/src/generators/GraphBoundaryGenerator.module.css +32 -0
  107. package/src/generators/GraphBoundaryGenerator.tsx +193 -0
  108. package/src/generators/SequenceGenerator.tsx +2 -2
  109. package/src/generators/SwitchOnIntegerGenerator.tsx +2 -2
  110. package/src/generators/SwitchOnStringGenerator.tsx +2 -2
  111. package/src/generators/callSubgraphSync.ts +126 -0
  112. package/src/generators/registerDefaultGenerators.ts +21 -0
  113. package/src/generators/registerDefaults.ts +26 -0
  114. package/src/hooks/useBehaveGraphFlow.ts +2 -2
  115. package/src/hooks/useFlowHandlers.ts +47 -9
  116. package/src/hooks/useWasdPan.ts +26 -4
  117. package/src/index.css +4 -16
  118. package/src/index.ts +17 -0
  119. package/src/manifest/contributionRegistry.ts +93 -0
  120. package/src/manifest/index.ts +4 -0
  121. package/src/manifest/loadManifest.ts +82 -0
  122. package/src/manifest/manifestPlugin.ts +29 -0
  123. package/src/manifest/passthroughValueType.ts +40 -0
  124. package/src/plugin/alignment/index.ts +22 -12
  125. package/src/plugin/autosave/controller.ts +366 -0
  126. package/src/plugin/autosave/index.tsx +114 -0
  127. package/src/plugin/autosave/panel/BackupPanel.tsx +141 -0
  128. package/src/plugin/autosave/panel/index.tsx +1 -0
  129. package/src/plugin/autosave/panel/styles.module.css +56 -0
  130. package/src/plugin/autosave/settings.ts +65 -0
  131. package/src/plugin/autosave/storage.ts +147 -0
  132. package/src/plugin/docs/index.tsx +2 -4
  133. package/src/plugin/docs/panel/DocumentationBrowserPanelImpl.tsx +200 -0
  134. package/src/plugin/docs/panel/index.tsx +15 -194
  135. package/src/plugin/docs/panel/styles.module.css +8 -8
  136. package/src/plugin/graphrunner/actions.ts +258 -185
  137. package/src/plugin/graphrunner/buttons.tsx +34 -26
  138. package/src/plugin/graphrunner/client.ts +4 -1
  139. package/src/plugin/graphrunner/index.tsx +29 -100
  140. package/src/plugin/graphrunner/panel.tsx +2 -2
  141. package/src/plugin/graphrunner/runController.ts +283 -0
  142. package/src/plugin/graphrunner/runner.ts +21 -192
  143. package/src/plugin/graphrunner/store.ts +14 -24
  144. package/src/plugin/graphrunner/styles.module.css +17 -57
  145. package/src/plugin/graphrunner/transport.ts +26 -0
  146. package/src/plugin/graphrunner/types.ts +21 -0
  147. package/src/plugin/graphrunner-local/execution-utils.ts +260 -80
  148. package/src/plugin/graphrunner-local/index.tsx +8 -2
  149. package/src/plugin/graphrunner-local/panel.tsx +131 -175
  150. package/src/plugin/graphrunner-local/styles.module.css +57 -76
  151. package/src/plugin/graphrunner-local/transport.ts +151 -184
  152. package/src/plugin/graphrunner-webworker/graph-executor.worker.ts +2 -0
  153. package/src/plugin/graphrunner-webworker/index.tsx +4 -10
  154. package/src/plugin/graphrunner-webworker/store.ts +9 -0
  155. package/src/plugin/kitchen-sink/index.ts +38 -0
  156. package/src/{layout/dagre.tsx → plugin/layout/dagre.ts} +17 -5
  157. package/src/{layout → plugin/layout}/elk.ts +22 -6
  158. package/src/plugin/layout/index.ts +80 -0
  159. package/src/plugin/notes/FormatToolbar.tsx +200 -0
  160. package/src/plugin/notes/index.tsx +191 -0
  161. package/src/plugin/notes/nodeActions.ts +100 -0
  162. package/src/plugin/notes/note.tsx +20 -0
  163. package/src/plugin/notes/noteImpl.tsx +89 -0
  164. package/src/plugin/realtime/realtimeRunner.ts +58 -4
  165. package/src/specifics/CustomEventOnTriggeredSpecific.tsx +2 -2
  166. package/src/specifics/CustomEventTriggerSpecific.tsx +2 -2
  167. package/src/specifics/VariableGetSpecific.tsx +2 -2
  168. package/src/specifics/VariableSetSpecific.tsx +2 -2
  169. package/src/store/actions.tsx +5 -5
  170. package/src/store/commands.ts +278 -0
  171. package/src/store/contextMenu.ts +192 -0
  172. package/src/store/conversions.ts +47 -0
  173. package/src/store/flow.tsx +23 -38
  174. package/src/store/graphMeta.ts +39 -0
  175. package/src/store/hotKeys.tsx +301 -260
  176. package/src/store/layers.ts +3 -3
  177. package/src/store/registry.ts +12 -4
  178. package/src/store/selection.ts +3 -3
  179. package/src/store/settings.ts +82 -82
  180. package/src/store/settingsSchema.ts +210 -0
  181. package/src/store/tabs.ts +5 -1
  182. package/src/store/traces.ts +3 -3
  183. package/src/system/graph.ts +11 -14
  184. package/src/system/graphSession.ts +172 -0
  185. package/src/system/index.ts +3 -0
  186. package/src/system/notifications.ts +13 -0
  187. package/src/system/persistence.ts +82 -0
  188. package/src/system/plugin.ts +28 -0
  189. package/src/system/provider.tsx +64 -0
  190. package/src/system/system.ts +518 -88
  191. package/src/system/tabLoader.tsx +70 -32
  192. package/src/system/undoRedo.ts +1 -1
  193. package/src/transformers/Uigraph.ts +5 -4
  194. package/src/transformers/contract.ts +87 -0
  195. package/src/transformers/flowToBehave.ts +13 -5
  196. package/src/types/nodes.ts +8 -3
  197. package/src/types.ts +2 -0
  198. package/src/util/autoConvert.ts +200 -0
  199. package/src/util/isValidConnection.ts +23 -2
  200. package/stories/defaults/defaultStoryProvider.tsx +17 -14
  201. package/stories/defaults/systemGenerator.ts +6 -1
  202. package/stories/{components/nodes/comment.stories.tsx → plugins/notes.stories.tsx} +24 -30
  203. package/tests/autoConvert.test.ts +329 -0
  204. package/tests/autosavePlugin.test.ts +204 -0
  205. package/tests/callSubgraphSync.test.ts +148 -0
  206. package/tests/commandRegistry.test.ts +137 -0
  207. package/tests/contract.test.ts +51 -0
  208. package/tests/contractSerialize.test.ts +62 -0
  209. package/tests/deriveSpans.test.ts +71 -0
  210. package/tests/flowToBehave.test.ts +2 -1
  211. package/tests/hotkeys.test.ts +79 -0
  212. package/tests/keepAliveLifecycle.test.ts +167 -0
  213. package/tests/loadManifest.test.ts +113 -0
  214. package/tests/noteMarkdown.test.ts +65 -0
  215. package/tests/notesPlugin.test.ts +162 -0
  216. package/tests/persistence.test.ts +51 -0
  217. package/tests/saveLoad.test.ts +7 -6
  218. package/tests/settings.test.ts +178 -0
  219. package/tests/traceStore.test.ts +46 -0
  220. package/tests/visual/README.md +2 -2
  221. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-conversation-chromium-win32.png +0 -0
  222. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-events-chromium-win32.png +0 -0
  223. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-history-chromium-win32.png +0 -0
  224. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-keymaps-chromium-win32.png +0 -0
  225. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-layers-chromium-win32.png +0 -0
  226. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-legend-chromium-win32.png +0 -0
  227. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-localGraphRunner-chromium-win32.png +0 -0
  228. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-logs-chromium-win32.png +0 -0
  229. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodeInputs-chromium-win32.png +0 -0
  230. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodePicker-chromium-win32.png +0 -0
  231. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-panel-chromium-win32.png +0 -0
  232. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-search-chromium-win32.png +0 -0
  233. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-systemSettings-chromium-win32.png +0 -0
  234. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-variables-chromium-win32.png +0 -0
  235. package/tests/visual/panels.visual.test.tsx +3 -3
  236. package/tests/wasdPan.test.ts +71 -0
  237. package/vitest.config.ts +1 -1
  238. package/vitest.visual.config.ts +7 -0
  239. package/.storybook/vscode.css +0 -814
  240. package/src/components/nodes/comment/FormatToolbar.tsx +0 -118
  241. package/src/components/nodes/comment/comment.tsx +0 -103
  242. package/src/components/nodes/comment/styles.module.css +0 -150
  243. package/src/components/panels/conversation/index.module.css +0 -151
  244. package/src/components/panels/conversation/index.tsx +0 -162
  245. package/src/components/panels/events/CustomEventsEditor.tsx +0 -384
  246. package/src/css/vscode.css +0 -13
  247. package/src/hooks/useDetachNodes.ts +0 -39
  248. package/src/plugin/graphrunner-webworker/types.ts +0 -17
  249. package/src/specifics/registerDefaultSpecifics.ts +0 -5
  250. package/src/store/chat.ts +0 -73
  251. package/src/store/graphRunnerClient.ts +0 -110
package/docs/protocol.md CHANGED
@@ -36,9 +36,9 @@ This protocol defines a WebSocket-based interface for decoupled execution of beh
36
36
  ```
37
37
 
38
38
  **Authentication Types:**
39
- - `bearer` Bearer token (JWT or API key)
40
- - `apiKey` Simple API key
41
- - `none` No authentication (development only)
39
+ - `bearer` , Bearer token (JWT or API key)
40
+ - `apiKey` , Simple API key
41
+ - `none` , No authentication (development only)
42
42
 
43
43
  **Example with API Key:**
44
44
  ```json
@@ -371,7 +371,9 @@ Get metadata about all available node types and their sockets.
371
371
  "trace": true,
372
372
  "eventFilter": { "variables": ["score", "health"], "events": ["onDeath"] },
373
373
  "maxExecutionTimeMs": 30000,
374
- // Whether the graph should complete with no more pending fibres
374
+ // Whether the run finalizes once no fibres are pending. Defaults to
375
+ // false: the run stays alive (servicing event-node subscriptions such
376
+ // as ai/onToolCall) until stopGraph.
375
377
  "autoEnd":true
376
378
  }
377
379
  }
@@ -546,6 +548,27 @@ Get metadata about all available node types and their sockets.
546
548
  }
547
549
  ```
548
550
 
551
+ #### Trace Batch Event
552
+ Servers should prefer `traceBatch` over per-event `trace` messages: node
553
+ execution produces two events per node (start and end), so a graph ticking at
554
+ display rate emits hundreds of events per frame. Buffering them and flushing
555
+ one batch per flush window (roughly one frame, ~16ms) keeps the message
556
+ pipeline off the hot path. Clients accept both; single `trace` messages remain
557
+ valid for servers that predate batching. Timestamps are run-relative
558
+ milliseconds, stamped when the event occurred (not when the batch flushed).
559
+
560
+ ```json
561
+ {
562
+ "type": "traceBatch",
563
+ "runId": "abc123",
564
+ "graphId": "main-graph-1",
565
+ "events": [
566
+ { "nodeId": "node42", "event": "start", "data": { "typeName": "flow/branch" }, "timestamp": 1200 },
567
+ { "nodeId": "node42", "event": "end", "data": { "typeName": "flow/branch" }, "timestamp": 1201 }
568
+ ]
569
+ }
570
+ ```
571
+
549
572
  #### Log Event
550
573
  ```json
551
574
  {
@@ -559,7 +582,7 @@ Get metadata about all available node types and their sockets.
559
582
  ```
560
583
 
561
584
  ### Variable Change Events
562
- - `variableChanged` Emitted when a variable's value changes during execution.
585
+ - `variableChanged` , Emitted when a variable's value changes during execution.
563
586
  - Includes: `runId`, `graphId`, `variableName`, `oldValue`, `newValue`, and optionally `nodeId` (if the change was triggered by a node).
564
587
 
565
588
  #### Example Variable Change Event
@@ -576,7 +599,7 @@ Get metadata about all available node types and their sockets.
576
599
  ```
577
600
 
578
601
  ### Event Emission
579
- - `eventEmitted` Emitted when an event is triggered during graph execution.
602
+ - `eventEmitted` , Emitted when an event is triggered during graph execution.
580
603
  - Includes: `runId`, `graphId`, `eventName`, `payload`, and optionally `nodeId` (if the event was triggered by a specific node).
581
604
 
582
605
  #### Example Event Emission
@@ -592,7 +615,7 @@ Get metadata about all available node types and their sockets.
592
615
  ```
593
616
 
594
617
  ### Node Addition Events
595
- - `nodeAdded` Emitted when a node is added to a graph during execution.
618
+ - `nodeAdded` , Emitted when a node is added to a graph during execution.
596
619
  - Includes: `runId`, `graphId`, `nodeId`, `nodeType`, and optionally `nodeData` with the full node configuration.
597
620
 
598
621
  #### Example Node Addition Event
@@ -617,19 +640,19 @@ Get metadata about all available node types and their sockets.
617
640
  ## 10. Error Handling
618
641
 
619
642
  ### Error Codes
620
- - `PROTOCOL_VERSION_MISMATCH` Incompatible protocol versions
621
- - `PROTOCOL_VIOLATION` Protocol rules violated (e.g., hello not sent first)
622
- - `AUTHENTICATION_FAILED` Invalid or missing authentication credentials
623
- - `AUTHENTICATION_REQUIRED` Authentication is required but not provided
624
- - `SESSION_NOT_FOUND` Session does not exist or expired
625
- - `SESSION_EXPIRED` Session timed out
626
- - `INVALID_GRAPH` Graph definition is malformed
627
- - `VALIDATION_FAILED` Graph failed validation
628
- - `RUN_NOT_FOUND` Run ID does not exist
629
- - `NODE_EXECUTION_ERROR` Error during node execution
630
- - `TIMEOUT` Execution exceeded max time
631
- - `CONCURRENT_LIMIT_EXCEEDED` Too many concurrent runs
632
- - `PERMISSION_DENIED` Unauthorized operation
643
+ - `PROTOCOL_VERSION_MISMATCH` , Incompatible protocol versions
644
+ - `PROTOCOL_VIOLATION` , Protocol rules violated (e.g., hello not sent first)
645
+ - `AUTHENTICATION_FAILED` , Invalid or missing authentication credentials
646
+ - `AUTHENTICATION_REQUIRED` , Authentication is required but not provided
647
+ - `SESSION_NOT_FOUND` , Session does not exist or expired
648
+ - `SESSION_EXPIRED` , Session timed out
649
+ - `INVALID_GRAPH` , Graph definition is malformed
650
+ - `VALIDATION_FAILED` , Graph failed validation
651
+ - `RUN_NOT_FOUND` , Run ID does not exist
652
+ - `NODE_EXECUTION_ERROR` , Error during node execution
653
+ - `TIMEOUT` , Execution exceeded max time
654
+ - `CONCURRENT_LIMIT_EXCEEDED` , Too many concurrent runs
655
+ - `PERMISSION_DENIED` , Unauthorized operation
633
656
 
634
657
  ### Error Response Format
635
658
  ```json
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kiberon-labs/behave-graph-flow",
3
- "version": "2.0.0",
3
+ "version": "3.0.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -18,8 +18,6 @@
18
18
  "access": "public"
19
19
  },
20
20
  "devDependencies": {
21
- "@bosh-code/tsdown-plugin-inject-css": "^2.0.0",
22
- "@bosh-code/tsdown-plugin-tailwindcss": "^1.0.1",
23
21
  "@storybook/addon-a11y": "^10.0.8",
24
22
  "@storybook/addon-docs": "^10.0.8",
25
23
  "@storybook/addon-vitest": "^10.0.8",
@@ -41,14 +39,13 @@
41
39
  "react-dom": "19.2.3",
42
40
  "reactflow": "^11.11.4",
43
41
  "storybook": "^10.0.8",
44
- "tailwindcss": "^4.1.17",
45
42
  "tsdown": "^0.16.5",
46
43
  "unplugin-lightningcss": "^0.4.3",
47
44
  "vite": "^7.2.4",
48
45
  "vite-tsconfig-paths": "^5.1.4",
49
46
  "vitest": "^4.0.10",
50
47
  "vitest-browser-react": "^2.2.0",
51
- "@kiberon-labs/behave-graph": "1.1.0"
48
+ "@kiberon-labs/behave-graph": "1.2.0"
52
49
  },
53
50
  "repository": {
54
51
  "type": "git",
@@ -60,6 +57,7 @@
60
57
  "dependencies": {
61
58
  "@radix-ui/react-popover": "^1.1.15",
62
59
  "@reactflow/node-resizer": "^2.2.14",
60
+ "@tiptap/extension-youtube": "^3.27.1",
63
61
  "@tiptap/react": "^3.19.0",
64
62
  "@tiptap/starter-kit": "^3.19.0",
65
63
  "@vscode-elements/react-elements": "^2.4.0",
@@ -67,9 +65,7 @@
67
65
  "clsx": "^2.1.1",
68
66
  "copy-to-clipboard": "^3.3.3",
69
67
  "dagre": "^0.8.5",
70
- "dockview": "^4.11.0",
71
68
  "elkjs": "^0.11.0",
72
- "fastify": "^5.7.4",
73
69
  "fuse.js": "^7.1.0",
74
70
  "graphlib": "^2.1.8",
75
71
  "iconoir-react": "^7.11.0",
@@ -82,17 +78,17 @@
82
78
  "react-hotkeys": "^2.0.0",
83
79
  "tiptap-markdown": "^0.9.0",
84
80
  "uuid": "^8.3.2",
85
- "zod": "^4.1.13",
86
81
  "zustand": "^5.0.8"
87
82
  },
88
83
  "peerDependencies": {
89
84
  "reactflow": "^11.1.1",
90
- "@kiberon-labs/behave-graph": "1.1.0"
85
+ "@kiberon-labs/behave-graph": "1.2.0"
91
86
  },
92
87
  "scripts": {
93
88
  "audit": "fallow",
94
89
  "dev": "tsdown --watch src",
95
90
  "build": "tsdown",
91
+ "release": "npm publish --dry-run",
96
92
  "test": "vitest",
97
93
  "test:visual": "vitest run --config vitest.visual.config.ts",
98
94
  "test:visual:update": "vitest run --config vitest.visual.config.ts --update",
@@ -7,10 +7,10 @@
7
7
  display: flex;
8
8
  gap: 0.5rem;
9
9
  padding: 0.25rem;
10
- background: var(--colors-bgSurface);
11
- border: 1px solid var(--colors-borderSubtle);
10
+ background: var(--ds-widget-bg, #292929);
11
+ border: 1px solid var(--ds-border-subtle, #454545);
12
12
  border-radius: 0.375rem;
13
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
13
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.36);
14
14
  }
15
15
 
16
16
  .buttonGroup {
@@ -28,18 +28,10 @@
28
28
  display: flex;
29
29
  align-items: center;
30
30
  padding: 0 0.5rem;
31
- font-size: 0.85rem;
31
+ font-size: var(--fs-label, 0.8rem);
32
32
  font-weight: 500;
33
- color: var(--colors-fg);
33
+ color: var(--ds-fg);
34
34
  user-select: none;
35
35
  min-width: 3rem;
36
36
  justify-content: center;
37
- }
38
-
39
- .contextMenu {
40
- position: absolute;
41
- top: 100%;
42
- left: 0;
43
- margin-top: 0.25rem;
44
- z-index: 1000;
45
37
  }
@@ -5,7 +5,7 @@ import {
5
5
  VscodeContextMenu
6
6
  } from '@vscode-elements/react-elements';
7
7
  import { ZoomIn, ZoomOut, AlignLeft, LayoutRight } from 'iconoir-react';
8
- import { useSystem } from '@/system/provider';
8
+ import { useGraph } from '@/system/provider';
9
9
  import { useStore } from 'zustand';
10
10
  import styles from './index.module.css';
11
11
  import { useRefFromStore } from '@/system';
@@ -13,10 +13,10 @@ import type { ToolbarButton } from '@/store/toolbar';
13
13
  import type { AlignmentAxis, AlignmentType } from '@/plugin/alignment';
14
14
 
15
15
  export const FloatingToolbar: React.FC = () => {
16
- const system = useSystem();
17
- const visible = useStore(system.toolbarStore, (x) => x.visible);
18
- const customGroups = useStore(system.toolbarStore, (x) => x.groups);
19
- const reactFlowInstance = useRefFromStore(system.refStore, 'reactflow');
16
+ const session = useGraph();
17
+ const visible = useStore(session.editor.toolbarStore, (x) => x.visible);
18
+ const customGroups = useStore(session.editor.toolbarStore, (x) => x.groups);
19
+ const reactFlowInstance = useRefFromStore(session.refStore, 'reactflow');
20
20
  const { zoom } = useViewport();
21
21
  const currentZoom = Math.round(zoom * 100);
22
22
  const [alignMenuOpen, setAlignMenuOpen] = useState(false);
@@ -27,16 +27,16 @@ export const FloatingToolbar: React.FC = () => {
27
27
 
28
28
  const publishAlignment = useCallback(
29
29
  (type: AlignmentType, axis: AlignmentAxis) => {
30
- system.pubsub.publishSync('alignment:align', { type, axis });
30
+ session.pubsub.publishSync('alignment:align', { type, axis });
31
31
  },
32
- [system]
32
+ [session]
33
33
  );
34
34
 
35
35
  const publishDistribution = useCallback(
36
36
  (type: AlignmentType, axis: AlignmentAxis) => {
37
- system.pubsub.publishSync('alignment:distribute', { type, axis });
37
+ session.pubsub.publishSync('alignment:distribute', { type, axis });
38
38
  },
39
- [system]
39
+ [session]
40
40
  );
41
41
 
42
42
  const handleZoomIn = useCallback(() => {
@@ -18,7 +18,7 @@ import {
18
18
  import { useBehaveGraphFlow } from '../hooks/useBehaveGraphFlow.js';
19
19
  import { useFlowHandlers } from '../hooks/useFlowHandlers.js';
20
20
  import { useWasdPan } from '../hooks/useWasdPan.js';
21
- import { useSystem } from '@/system/provider.js';
21
+ import { useGraph } from '@/system/provider.js';
22
22
  import { useStore } from 'zustand';
23
23
  import {
24
24
  NodeContextMenu,
@@ -32,7 +32,7 @@ import {
32
32
  SelectionContextMenu,
33
33
  type ISelectionContextMenuProps
34
34
  } from './contextMenus/selection.js';
35
- import { registerDefaultSocketGenerators } from '@/generators/registerDefaultGenerators';
35
+ import { registerDefaults } from '@/generators/registerDefaults';
36
36
  import { FloatingToolbar } from './FloatingToolbar';
37
37
  import { layerId } from '@/annotations';
38
38
 
@@ -63,25 +63,36 @@ const isNodeVisibleInLayers = (
63
63
  };
64
64
 
65
65
  export const Flow: React.FC = () => {
66
- const system = useSystem();
67
- const getGraphJson = useStore(system.flowStore, (x) => x.getGraph);
68
- const specJson = useStore(system.specStore, (x) => x.specs);
69
- const showGrid = useStore(system.systemSettings, (x) => x.showGrid);
70
- const showMinimap = useStore(system.systemSettings, (x) => x.showMinimap);
71
- const snapToGrid = useStore(system.systemSettings, (x) => x.snapGrid);
72
- const gridSize = useStore(system.systemSettings, (x) => x.gridSize);
73
- const edgeTypes = useStore(system.flowStore, (x) => x.edgeTypes);
74
- const nodeTypes = useStore(system.flowStore, (x) => x.nodeTypes);
75
- const layers = useStore(system.layerStore, (x) => x.layers);
76
- const nodeLayers = useStore(system.layerStore, (x) => x.nodeLayers);
77
- const defaultLayerId = useStore(system.layerStore, (x) => x.defaultLayerId);
66
+ const session = useGraph();
67
+ const editor = session.editor;
68
+ const getGraphJson = useStore(session.flowStore, (x) => x.getGraph);
69
+ const specJson = useStore(editor.specStore, (x) => x.specs);
70
+ const showGrid = useStore(editor.systemSettings, (x) => x.showGrid);
71
+ const showMinimap = useStore(editor.systemSettings, (x) => x.showMinimap);
72
+ const snapToGrid = useStore(editor.systemSettings, (x) => x.snapGrid);
73
+ const gridSize = useStore(editor.systemSettings, (x) => x.gridSize);
74
+ const edgeTypes = useStore(session.flowStore, (x) => x.edgeTypes);
75
+ const nodeTypes = useStore(session.flowStore, (x) => x.nodeTypes);
76
+ const layers = useStore(session.layerStore, (x) => x.layers);
77
+ const nodeLayers = useStore(session.layerStore, (x) => x.nodeLayers);
78
+ const defaultLayerId = useStore(session.layerStore, (x) => x.defaultLayerId);
78
79
 
79
80
  const ref = useRef<HTMLDivElement>(null);
80
- const setRef = useStore(system.refStore, (x) => x.setRef);
81
+ const setRef = useStore(session.refStore, (x) => x.setRef);
82
+
83
+ // When this canvas is interacted with, mark its graph as focused so the shared
84
+ // side-panels (Variables, Traces, ...) bind to it. Lets two graphs be open at
85
+ // once without a singular "active graph" , focus simply follows interaction.
86
+ const focusThisGraph = useCallback(() => {
87
+ const active = editor.activeGraph.getState();
88
+ if (active.activeGraphId !== session.id) {
89
+ active.setActiveGraph(session.id);
90
+ }
91
+ }, [editor, session.id]);
81
92
 
82
93
  const getReactFlowInstance = useCallback(
83
- () => system.refStore.getState().getRef('reactflow'),
84
- [system.refStore]
94
+ () => session.refStore.getState().getRef('reactflow'),
95
+ [session.refStore]
85
96
  );
86
97
 
87
98
  useWasdPan({ getReactFlowInstance });
@@ -98,13 +109,11 @@ export const Flow: React.FC = () => {
98
109
 
99
110
  const graph = useMemo(() => getGraphJson(), []);
100
111
 
112
+ // Editor-level built-in content. Idempotent per editor, so opening multiple
113
+ // graph tabs (each a Flow canvas) registers it once rather than per mount.
101
114
  useEffect(() => {
102
- const cleanupGenerators = registerDefaultSocketGenerators(system);
103
-
104
- return () => {
105
- cleanupGenerators();
106
- };
107
- }, [system]);
115
+ registerDefaults(editor);
116
+ }, [editor]);
108
117
 
109
118
  const { nodes, edges, onNodesChange, onEdgesChange } = useBehaveGraphFlow({
110
119
  initialGraphJson: graph,
@@ -253,8 +262,10 @@ export const Flow: React.FC = () => {
253
262
  return (
254
263
  <>
255
264
  <ReactFlow
265
+ id={session.id}
256
266
  style={{ flex: 1 }}
257
267
  ref={ref}
268
+ onPointerDownCapture={focusThisGraph}
258
269
  onInit={setReactflowRef}
259
270
  nodeTypes={nodeTypes}
260
271
  edgeTypes={edgeTypes}
@@ -0,0 +1,85 @@
1
+ import type { CSSProperties } from 'react';
2
+ import { useStore } from 'zustand';
3
+ import { VscodeContextMenu } from '@vscode-elements/react-elements';
4
+ import { useGraph } from '@/system';
5
+ import type { CommandContext } from '@/store/commands';
6
+ import type { ContextMenuTarget } from '@/store/contextMenu';
7
+
8
+ type MenuData =
9
+ | { separator: true }
10
+ | { label: string; value: string; keybinding?: string };
11
+
12
+ /**
13
+ * Renders a context menu for a target from the editor's contextMenu registry,
14
+ * dispatching selections through the command registry. The three concrete menus
15
+ * (node/edge/selection) are thin wrappers that supply the target + context.
16
+ */
17
+ export const DynamicContextMenu = ({
18
+ target,
19
+ context,
20
+ style
21
+ }: {
22
+ target: ContextMenuTarget;
23
+ context: Omit<CommandContext, 'editor' | 'session'>;
24
+ style?: CSSProperties;
25
+ }) => {
26
+ const session = useGraph();
27
+ const editor = session.editor;
28
+
29
+ // Subscribe so the menu re-renders when items/commands/keymap change.
30
+ useStore(editor.contextMenuStore, (s) => s.items);
31
+ useStore(editor.commandStore, (s) => s.commands);
32
+ useStore(editor.hotKeyStore, (s) => s.keymap);
33
+
34
+ const hotKeys = editor.hotKeyStore.getState();
35
+
36
+ const ctx: CommandContext = { editor, session, ...context };
37
+
38
+ const items = editor.contextMenuStore
39
+ .getState()
40
+ .getItems(target)
41
+ .filter((i) => !i.when || i.when(ctx));
42
+
43
+ const data: MenuData[] = [];
44
+ let lastGroup: unknown;
45
+ for (const item of items) {
46
+ if (data.length > 0 && item.group !== lastGroup) {
47
+ data.push({ separator: true });
48
+ }
49
+ lastGroup = item.group;
50
+ // Auto-detect the shortcut from the command's live keymap binding; fall
51
+ // back to a static hint only when the command has no bound key.
52
+ const derived = item.commandId
53
+ ? hotKeys.getCommandKeybinding(item.commandId)
54
+ : undefined;
55
+ data.push({
56
+ label: typeof item.label === 'function' ? item.label(ctx) : item.label,
57
+ value: item.id,
58
+ keybinding: derived ?? item.keybinding
59
+ });
60
+ }
61
+
62
+ if (data.length === 0) return null;
63
+
64
+ const onSelect = (e: any) => {
65
+ const id = e?.detail?.value as string | undefined;
66
+ const item = items.find((i) => i.id === id);
67
+ if (!item) return;
68
+ if (item.onSelect) {
69
+ item.onSelect(ctx);
70
+ return;
71
+ }
72
+ if (item.commandId) {
73
+ void editor.commandStore.getState().run(item.commandId, ctx);
74
+ }
75
+ };
76
+
77
+ return (
78
+ <VscodeContextMenu
79
+ show
80
+ onVscContextMenuSelect={onSelect}
81
+ style={{ zIndex: 2000, position: 'absolute', ...style }}
82
+ data={data}
83
+ />
84
+ );
85
+ };
@@ -16,7 +16,7 @@
16
16
  }
17
17
 
18
18
  .sidebar {
19
- border-right: 1px solid var(--vscode-input-border, var(--colors-borderSubtle));
19
+ border-right: 1px solid var(--ds-input-border, var(--colors-borderSubtle));
20
20
  background: var(--colors-bgPanel);
21
21
  display: flex;
22
22
  flex-direction: column;
@@ -41,12 +41,12 @@
41
41
  }
42
42
 
43
43
  .sidebarItem:hover {
44
- background: var(--vscode-button-hoverBackground, #026ec1);
44
+ background: var(--ds-button-hover-bg, #026ec1);
45
45
  }
46
46
 
47
47
  .sidebarItemActive {
48
- background: var(--vscode-button-secondaryBackground, #313131);
49
- color: var(--vscode-list-activeSelectionForeground);
48
+ background: var(--ds-button-secondary-bg, #313131);
49
+ color: var(--ds-list-active-fg);
50
50
  }
51
51
 
52
52
  .main {
@@ -61,7 +61,7 @@
61
61
  align-items: center;
62
62
  gap: 0.5rem;
63
63
  padding: 0.5rem;
64
- border-bottom: 1px solid var(--vscode-input-border, var(--colors-borderSubtle));
64
+ border-bottom: 1px solid var(--ds-input-border, var(--colors-borderSubtle));
65
65
  }
66
66
 
67
67
  .search {
@@ -110,7 +110,7 @@
110
110
  }
111
111
 
112
112
  .nodeRow:hover {
113
- background: var(--vscode-button-hoverBackground, #026ec1);
113
+ background: var(--ds-button-hover-bg, #026ec1);
114
114
  }
115
115
 
116
116
  .infoButton {
@@ -128,7 +128,7 @@
128
128
  }
129
129
 
130
130
  .infoButton:hover {
131
- background: var(--vscode-button-secondaryBackground, #313131);
131
+ background: var(--ds-button-secondary-bg, #313131);
132
132
  opacity: 1 !important;
133
133
  }
134
134
 
@@ -145,7 +145,7 @@
145
145
  width: 28px;
146
146
  height: 28px;
147
147
  border-radius: 0.25rem;
148
- border: 1px solid var(--vscode-input-border, var(--colors-borderSubtle));
148
+ border: 1px solid var(--ds-input-border, var(--colors-borderSubtle));
149
149
  background: var(--colors-bgCanvas);
150
150
  overflow: hidden;
151
151
  display: flex;
@@ -210,8 +210,8 @@
210
210
  font-size: 0.65rem;
211
211
  padding: 0.1rem 0.35rem;
212
212
  border-radius: 0.25rem;
213
- background: var(--vscode-badge-background, #4d4d4d);
214
- color: var(--vscode-badge-foreground, #ffffff);
213
+ background: var(--ds-badge-bg, #4d4d4d);
214
+ color: var(--ds-badge-fg, #ffffff);
215
215
  opacity: 0.85;
216
216
  }
217
217
 
@@ -223,7 +223,7 @@
223
223
  }
224
224
 
225
225
  .card:hover {
226
- background: var(--vscode-button-hoverBackground, #026ec1);
226
+ background: var(--ds-button-hover-bg, #026ec1);
227
227
  }
228
228
 
229
229
  .cardInner {
@@ -245,7 +245,7 @@
245
245
  width: 56px;
246
246
  height: 56px;
247
247
  border-radius: 0.25rem;
248
- border: 1px solid var(--vscode-input-border, var(--colors-borderSubtle));
248
+ border: 1px solid var(--ds-input-border, var(--colors-borderSubtle));
249
249
  overflow: hidden;
250
250
  display: flex;
251
251
  align-items: center;
@@ -260,7 +260,7 @@
260
260
 
261
261
  .footer {
262
262
  padding: 0.35rem 0.5rem;
263
- border-top: 1px solid var(--vscode-input-border, var(--colors-borderSubtle));
263
+ border-top: 1px solid var(--ds-input-border, var(--colors-borderSubtle));
264
264
  font-size: 0.75rem;
265
265
  opacity: 0.8;
266
266
  display: flex;
@@ -1,12 +1,5 @@
1
1
  import type { CSSProperties } from 'react';
2
- import { useCallback } from 'react';
3
- import type { EdgeChange } from 'reactflow';
4
- import {
5
- VscodeContextMenu,
6
- VscodeContextMenuItem,
7
- VscodeDivider
8
- } from '@vscode-elements/react-elements';
9
- import { useSystem } from '@/system';
2
+ import { DynamicContextMenu } from './DynamicContextMenu';
10
3
 
11
4
  export interface IEdgeContextMenuProps extends CSSProperties {
12
5
  edgeID: string;
@@ -14,95 +7,16 @@ export interface IEdgeContextMenuProps extends CSSProperties {
14
7
  targetID: string;
15
8
  }
16
9
 
10
+ /** Edge context menu , items from the contextMenu registry (target 'edge'). */
17
11
  export const EdgeContextMenu = ({
18
12
  edgeID,
19
13
  sourceID,
20
14
  targetID,
21
15
  ...rest
22
- }: IEdgeContextMenuProps) => {
23
- const sys = useSystem();
24
-
25
- const centerOnNode = useCallback(
26
- (nodeId: string) => {
27
- const node = sys.nodeStore.getState().nodes.find((n) => n.id === nodeId);
28
- if (!node) return;
29
-
30
- const x = node.position.x + (node.width ?? 0) / 2;
31
- const y = node.position.y + (node.height ?? 0) / 2;
32
-
33
- sys.refStore.getState().getRef('reactflow')?.setCenter(x, y, {
34
- duration: 200,
35
- zoom: 1
36
- });
37
- },
38
- [sys]
39
- );
40
-
41
- const findSource = useCallback(
42
- () => centerOnNode(sourceID),
43
- [centerOnNode, sourceID]
44
- );
45
- const findTarget = useCallback(
46
- () => centerOnNode(targetID),
47
- [centerOnNode, targetID]
48
- );
49
-
50
- const deleteEdge = useCallback(() => {
51
- const change: EdgeChange = {
52
- id: edgeID,
53
- type: 'remove'
54
- };
55
- sys.edgeStore.getState().applyEdgeChanges([change]);
56
- }, [edgeID, sys.edgeStore]);
57
-
58
- const onSelect = useCallback(
59
- (e: any) => {
60
- switch (e.detail.value) {
61
- case 'findSource':
62
- findSource();
63
- break;
64
- case 'findTarget':
65
- findTarget();
66
- break;
67
- case 'delete':
68
- deleteEdge();
69
- break;
70
- }
71
- },
72
- [deleteEdge, findSource, findTarget]
73
- );
74
-
75
- return (
76
- <VscodeContextMenu
77
- show
78
- onVscContextMenuSelect={onSelect}
79
- style={{ zIndex: 2000, position: 'absolute', ...rest }}
80
- data={[
81
- {
82
- label: 'Find Source',
83
- value: 'findSource'
84
- },
85
- {
86
- label: 'Find Target',
87
- value: 'findTarget'
88
- },
89
- {
90
- separator: true
91
- },
92
- {
93
- label: 'Delete',
94
- value: 'delete'
95
- }
96
- ]}
97
- >
98
- <VscodeContextMenuItem onClick={findSource}>
99
- Find Source
100
- </VscodeContextMenuItem>
101
- <VscodeContextMenuItem onClick={findTarget}>
102
- Find Target
103
- </VscodeContextMenuItem>
104
- <VscodeDivider />
105
- <VscodeContextMenuItem onClick={deleteEdge}>Delete</VscodeContextMenuItem>
106
- </VscodeContextMenu>
107
- );
108
- };
16
+ }: IEdgeContextMenuProps) => (
17
+ <DynamicContextMenu
18
+ target="edge"
19
+ context={{ edgeId: edgeID, sourceId: sourceID, targetId: targetID }}
20
+ style={rest}
21
+ />
22
+ );