@kiberon-labs/behave-graph-flow 1.0.0 → 2.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 (314) hide show
  1. package/.fallowrc.json +16 -0
  2. package/.storybook/main.ts +32 -0
  3. package/.storybook/preview.ts +16 -0
  4. package/.storybook/styles.css +10 -0
  5. package/.storybook/vscode.css +814 -0
  6. package/.turbo/turbo-build.log +7 -0
  7. package/LICENSE +6 -0
  8. package/README.md +2 -2
  9. package/data/Polynomial.json +510 -0
  10. package/data/sequence.json +337 -0
  11. package/data/trigger-event.json +241 -0
  12. package/data/variable-change.json +210 -0
  13. package/dist/entry.css +4 -0
  14. package/dist/index.css +39 -0
  15. package/dist/index.css.map +1 -0
  16. package/dist/index.d.ts +2282 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +14873 -0
  19. package/dist/index.js.map +1 -0
  20. package/docs/notifications.md +246 -0
  21. package/docs/protocol.md +679 -0
  22. package/docs/specifics.md +191 -0
  23. package/package.json +85 -21
  24. package/postcss.config.ts +3 -4
  25. package/src/annotations/index.ts +32 -0
  26. package/src/components/FloatingToolbar/index.module.css +45 -0
  27. package/src/components/FloatingToolbar/index.tsx +256 -0
  28. package/src/components/Flow.tsx +276 -75
  29. package/src/components/contextMenus/NodePicker.module.css +274 -0
  30. package/src/components/contextMenus/NodePicker.tsx +481 -0
  31. package/src/components/contextMenus/edge.tsx +108 -0
  32. package/src/components/contextMenus/node.tsx +155 -0
  33. package/src/components/contextMenus/selection.tsx +77 -0
  34. package/src/components/controls/any/index.tsx +8 -0
  35. package/src/components/controls/boolean/index.tsx +13 -0
  36. package/src/components/controls/colorPicker/InputPopover.module.css +100 -0
  37. package/src/components/controls/colorPicker/InputPopover.tsx +31 -0
  38. package/src/components/controls/colorPicker/index.module.css +18 -0
  39. package/src/components/controls/colorPicker/index.tsx +61 -0
  40. package/src/components/controls/number/index.tsx +35 -0
  41. package/src/components/controls/string/index.tsx +16 -0
  42. package/src/components/edges/index.tsx +469 -0
  43. package/src/components/edges/offsetBezier.ts +134 -0
  44. package/src/components/hotKeys.tsx +20 -0
  45. package/src/components/layoutController/index.module.css +10 -0
  46. package/src/components/layoutController/index.tsx +117 -0
  47. package/src/components/layoutController/utils.ts +205 -0
  48. package/src/components/menubar/defaults.tsx +480 -0
  49. package/src/components/menubar/index.tsx +49 -0
  50. package/src/components/menubar/menuItem.module.css +16 -0
  51. package/src/components/menubar/menuItem.tsx +32 -0
  52. package/src/components/nodes/behave/Node.module.css +23 -0
  53. package/src/components/nodes/behave/Node.tsx +176 -0
  54. package/src/components/nodes/behave/NodeContainer.module.css +87 -0
  55. package/src/components/nodes/behave/NodeContainer.tsx +46 -0
  56. package/src/components/nodes/behave/index.tsx +14 -0
  57. package/src/components/nodes/comment/FormatToolbar.tsx +118 -0
  58. package/src/components/nodes/comment/comment.tsx +103 -0
  59. package/src/components/nodes/comment/styles.module.css +150 -0
  60. package/src/components/nodes/group/index.tsx +109 -0
  61. package/src/components/nodes/wrapper/index.tsx +73 -0
  62. package/src/components/nodes/wrapper/styles.module.css +113 -0
  63. package/src/components/notifications/NotificationProvider.tsx +81 -0
  64. package/src/components/notifications/index.ts +2 -0
  65. package/src/components/notifications/utils.ts +71 -0
  66. package/src/components/panels/alignment/index.module.css +20 -0
  67. package/src/components/panels/alignment/index.tsx +244 -0
  68. package/src/components/panels/base/index.tsx +5 -0
  69. package/src/components/panels/base/styles.module.css +12 -0
  70. package/src/components/panels/conversation/index.module.css +151 -0
  71. package/src/components/panels/conversation/index.tsx +162 -0
  72. package/src/components/panels/events/CustomEventsEditor.tsx +384 -0
  73. package/src/components/panels/events/EditEventPanel.tsx +315 -0
  74. package/src/components/panels/events/ManageEventsPanel.tsx +98 -0
  75. package/src/components/panels/events/index.tsx +23 -0
  76. package/src/components/panels/events/styles.module.css +236 -0
  77. package/src/components/panels/history/index.tsx +92 -0
  78. package/src/components/panels/history/styles.module.css +106 -0
  79. package/src/components/panels/keymaps/index.module.css +78 -0
  80. package/src/components/panels/keymaps/index.tsx +167 -0
  81. package/src/components/panels/layers/index.tsx +240 -0
  82. package/src/components/panels/layers/styles.module.css +110 -0
  83. package/src/components/panels/legend/index.module.css +6 -0
  84. package/src/components/panels/legend/index.tsx +76 -0
  85. package/src/components/panels/logs/index.module.css +212 -0
  86. package/src/components/panels/logs/index.tsx +288 -0
  87. package/src/components/panels/nodeInputs/InputControl.tsx +63 -0
  88. package/src/components/panels/nodeInputs/InputsGroup.tsx +64 -0
  89. package/src/components/panels/nodeInputs/MultipleNodesView.tsx +37 -0
  90. package/src/components/panels/nodeInputs/NodeSettings.tsx +92 -0
  91. package/src/components/panels/nodeInputs/NodeTitleEditor.tsx +125 -0
  92. package/src/components/panels/nodeInputs/OutputsGroup.tsx +65 -0
  93. package/src/components/panels/nodeInputs/SocketGenerators.tsx +32 -0
  94. package/src/components/panels/nodeInputs/index.module.css +284 -0
  95. package/src/components/panels/nodeInputs/index.tsx +339 -0
  96. package/src/components/panels/nodeInputs/useNodeHandlers.ts +76 -0
  97. package/src/components/panels/nodeInputs/useNodeInputsData.ts +173 -0
  98. package/src/components/panels/nodePicker/index.tsx +115 -0
  99. package/src/components/panels/panel/index.module.css +66 -0
  100. package/src/components/panels/panel/index.tsx +88 -0
  101. package/src/components/panels/search/index.module.css +66 -0
  102. package/src/components/panels/search/index.tsx +215 -0
  103. package/src/components/panels/systemSettings/index.tsx +206 -0
  104. package/src/components/panels/systemSettings/styles.module.css +11 -0
  105. package/src/components/panels/traces/GridLines.tsx +38 -0
  106. package/src/components/panels/traces/TimeGrid.tsx +48 -0
  107. package/src/components/panels/traces/TraceLane.tsx +62 -0
  108. package/src/components/panels/traces/TraceTooltip.tsx +22 -0
  109. package/src/components/panels/traces/TracesHeader.tsx +56 -0
  110. package/src/components/panels/traces/index.module.css +166 -0
  111. package/src/components/panels/traces/index.tsx +294 -0
  112. package/src/components/panels/traces/types.ts +48 -0
  113. package/src/components/panels/traces/useDerivedSpans.ts +212 -0
  114. package/src/components/panels/traces/utils.ts +25 -0
  115. package/src/components/panels/variables/CreateVariableScreen.tsx +162 -0
  116. package/src/components/panels/variables/ManageVariablesScreen.tsx +144 -0
  117. package/src/components/panels/variables/index.tsx +125 -0
  118. package/src/components/panels/variables/styles.module.css +236 -0
  119. package/src/components/primitives/icon.module.css +45 -0
  120. package/src/components/primitives/icon.tsx +38 -0
  121. package/src/components/sockets/input/index.tsx +76 -0
  122. package/src/components/sockets/input/styles.module.css +27 -0
  123. package/src/components/sockets/output/index.tsx +61 -0
  124. package/src/components/sockets/output/styles.module.css +27 -0
  125. package/src/css/prosemirror.css +57 -0
  126. package/src/css/rc-dock.css +112 -0
  127. package/src/css/rc-menu.css +100 -0
  128. package/src/css/vars.css +14 -0
  129. package/src/css/vscode.css +13 -0
  130. package/src/entry.css +4 -0
  131. package/src/generators/CustomEventOnTriggeredGenerator.tsx +85 -0
  132. package/src/generators/SequenceGenerator.tsx +104 -0
  133. package/src/generators/SwitchOnIntegerGenerator.tsx +256 -0
  134. package/src/generators/SwitchOnStringGenerator.tsx +263 -0
  135. package/src/generators/registerDefaultGenerators.ts +34 -0
  136. package/src/hooks/useBehaveGraphFlow.ts +17 -16
  137. package/src/hooks/useDetachNodes.ts +39 -0
  138. package/src/hooks/useFlowHandlers.ts +115 -29
  139. package/src/hooks/useWasdPan.ts +188 -0
  140. package/src/index.css +146 -0
  141. package/src/index.ts +36 -18
  142. package/src/layout/dagre.tsx +119 -0
  143. package/src/layout/elk.ts +200 -0
  144. package/src/plugin/alignment/index.ts +81 -0
  145. package/src/plugin/docs/index.tsx +299 -0
  146. package/src/plugin/docs/panel/index.tsx +200 -0
  147. package/src/plugin/docs/panel/styles.module.css +174 -0
  148. package/src/plugin/graphrunner/actions.ts +253 -0
  149. package/src/plugin/graphrunner/buttons.tsx +87 -0
  150. package/src/plugin/graphrunner/client.ts +704 -0
  151. package/src/plugin/graphrunner/index.tsx +255 -0
  152. package/src/plugin/graphrunner/panel.tsx +386 -0
  153. package/src/plugin/graphrunner/runner.ts +358 -0
  154. package/src/plugin/graphrunner/session.ts +243 -0
  155. package/src/plugin/graphrunner/store.ts +206 -0
  156. package/src/plugin/graphrunner/styles.module.css +211 -0
  157. package/src/plugin/graphrunner/transport.ts +224 -0
  158. package/src/plugin/graphrunner/types.ts +672 -0
  159. package/src/plugin/graphrunner-local/execution-utils.ts +457 -0
  160. package/src/plugin/graphrunner-local/index.tsx +166 -0
  161. package/src/plugin/graphrunner-local/panel.tsx +231 -0
  162. package/src/plugin/graphrunner-local/store.ts +41 -0
  163. package/src/plugin/graphrunner-local/styles.module.css +101 -0
  164. package/src/plugin/graphrunner-local/transport.ts +1372 -0
  165. package/src/plugin/graphrunner-local/types.ts +10 -0
  166. package/src/plugin/graphrunner-webworker/graph-executor.worker.ts +633 -0
  167. package/src/plugin/graphrunner-webworker/index.tsx +146 -0
  168. package/src/plugin/graphrunner-webworker/panel.tsx +173 -0
  169. package/src/plugin/graphrunner-webworker/store.ts +89 -0
  170. package/src/plugin/graphrunner-webworker/types.ts +17 -0
  171. package/src/plugin/graphrunner-webworker/worker-transport.ts +123 -0
  172. package/src/plugin/realtime/realtimeRunner.ts +570 -0
  173. package/src/specifics/CustomEventOnTriggeredSpecific.tsx +92 -0
  174. package/src/specifics/CustomEventTriggerSpecific.tsx +141 -0
  175. package/src/specifics/VariableGetSpecific.tsx +110 -0
  176. package/src/specifics/VariableSetSpecific.tsx +110 -0
  177. package/src/specifics/registerDefaultSpecifics.ts +5 -0
  178. package/src/store/actions.tsx +698 -0
  179. package/src/store/chat.ts +73 -0
  180. package/src/store/controls.tsx +62 -0
  181. package/src/store/documentation.tsx +69 -0
  182. package/src/store/events.tsx +116 -0
  183. package/src/store/flow.tsx +245 -0
  184. package/src/store/graphRunnerClient.ts +110 -0
  185. package/src/store/hotKeys.tsx +323 -0
  186. package/src/store/layers.ts +259 -0
  187. package/src/store/legend.tsx +76 -0
  188. package/src/store/logs.ts +28 -0
  189. package/src/store/menubar.ts +41 -0
  190. package/src/store/refs.ts +84 -0
  191. package/src/store/registry.ts +43 -0
  192. package/src/store/selection.ts +22 -0
  193. package/src/store/settings.ts +99 -0
  194. package/src/store/socketGenerator.tsx +54 -0
  195. package/src/store/specific.tsx +75 -0
  196. package/src/store/specs.tsx +35 -0
  197. package/src/store/tabs.ts +278 -0
  198. package/src/store/toolbar.tsx +45 -0
  199. package/src/store/traces.ts +240 -0
  200. package/src/store/variables.ts +37 -0
  201. package/src/system/graph.ts +134 -0
  202. package/src/system/index.ts +3 -0
  203. package/src/system/notifications.ts +98 -0
  204. package/src/system/plugin.ts +27 -0
  205. package/src/system/provider.tsx +22 -0
  206. package/src/system/pubsub.ts +323 -0
  207. package/src/system/system.ts +223 -0
  208. package/src/system/tabLoader.tsx +265 -0
  209. package/src/system/undoRedo.ts +103 -0
  210. package/src/transformers/Uigraph.ts +60 -0
  211. package/src/transformers/behaveToFlow.ts +16 -4
  212. package/src/transformers/flowToBehave.ts +32 -12
  213. package/src/types/NodeMetadata.ts +27 -0
  214. package/src/types/graph.ts +49 -0
  215. package/src/types/nodes.ts +45 -0
  216. package/src/types.ts +16 -0
  217. package/src/util/colors.ts +1 -29
  218. package/src/util/downloadJson.ts +18 -0
  219. package/src/util/extractNodeMetadata.ts +16 -0
  220. package/src/util/getPickerFilters.ts +1 -1
  221. package/src/util/isBehaveNode.ts +6 -0
  222. package/src/util/isValidConnection.ts +28 -15
  223. package/src/util/mergeSockets.ts +29 -0
  224. package/src/util/serializeVariables.ts +66 -0
  225. package/src/util/sockets.ts +43 -0
  226. package/stories/apex/layoutController/example-graph.worker.ts +39 -0
  227. package/stories/apex/layoutController/index.stories.tsx +48 -0
  228. package/stories/apex/layoutController/webworker.stories.tsx +103 -0
  229. package/stories/apex/menubar/menubar.stories.tsx +19 -0
  230. package/stories/components/colorpicker/index.stories.tsx +20 -0
  231. package/stories/components/contextMenus/edge.stories.tsx +32 -0
  232. package/stories/components/contextMenus/node.stories.tsx +26 -0
  233. package/stories/components/contextMenus/nodePicker.stories.tsx +115 -0
  234. package/stories/components/controls/any/index.stories.tsx +19 -0
  235. package/stories/components/controls/boolean/index.stories.tsx +19 -0
  236. package/stories/components/controls/colorPicker/index.stories.tsx +49 -0
  237. package/stories/components/controls/number/index.stories.tsx +19 -0
  238. package/stories/components/controls/string/index.stories.tsx +19 -0
  239. package/stories/components/nodes/behaveNode.stories.tsx +108 -0
  240. package/stories/components/nodes/comment.stories.tsx +106 -0
  241. package/stories/components/panels/alignment.stories.tsx +24 -0
  242. package/stories/components/panels/events.stories.tsx +38 -0
  243. package/stories/components/panels/graphRunner.stories.tsx +317 -0
  244. package/stories/components/panels/history.stories.tsx +37 -0
  245. package/stories/components/panels/keymaps.stories.tsx +21 -0
  246. package/stories/components/panels/legend.stories.tsx +37 -0
  247. package/stories/components/panels/logs.stories.tsx +24 -0
  248. package/stories/components/panels/nodeInputs.stories.tsx +21 -0
  249. package/stories/components/panels/nodePicker.stories.tsx +37 -0
  250. package/stories/components/panels/panel.stories.tsx +39 -0
  251. package/stories/components/panels/search.stories.tsx +24 -0
  252. package/stories/components/panels/systemSettings.stories.tsx +26 -0
  253. package/stories/components/panels/traces.stories.tsx +225 -0
  254. package/stories/components/panels/variables.stories.tsx +24 -0
  255. package/stories/defaults/defaultStoryProvider.tsx +167 -0
  256. package/stories/defaults/systemGenerator.ts +38 -0
  257. package/tests/components/edges/offsetBezier.test.ts +51 -0
  258. package/tests/components/layoutController/utils.test.ts +68 -0
  259. package/tests/components/panels/traces/utils.test.ts +52 -0
  260. package/tests/flowToBehave.test.ts +26 -4
  261. package/tests/notifications.test.ts +87 -0
  262. package/tests/saveLoad.test.ts +372 -0
  263. package/tests/util/calculateNewEdge.test.ts +98 -0
  264. package/tests/util/getSocketsByNodeTypeAndHandleType.test.ts +31 -0
  265. package/tests/util/hasPositionMetaData.test.ts +33 -0
  266. package/tests/util/isBehaveNode.test.ts +22 -0
  267. package/tests/util/isHandleConnected.test.ts +37 -0
  268. package/tests/util/mergeSockets.test.ts +43 -0
  269. package/tests/visual/README.md +64 -0
  270. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-alignment-chromium-win32.png +0 -0
  271. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-conversation-chromium-win32.png +0 -0
  272. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-events-chromium-win32.png +0 -0
  273. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-history-chromium-win32.png +0 -0
  274. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-keymaps-chromium-win32.png +0 -0
  275. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-layers-chromium-win32.png +0 -0
  276. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-legend-chromium-win32.png +0 -0
  277. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-logs-chromium-win32.png +0 -0
  278. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodeInputs-chromium-win32.png +0 -0
  279. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodePicker-chromium-win32.png +0 -0
  280. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-panel-chromium-win32.png +0 -0
  281. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-search-chromium-win32.png +0 -0
  282. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-systemSettings-chromium-win32.png +0 -0
  283. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-traces-chromium-win32.png +0 -0
  284. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-variables-chromium-win32.png +0 -0
  285. package/tests/visual/panels.visual.test.tsx +76 -0
  286. package/tsconfig.base.json +39 -0
  287. package/tsconfig.json +18 -59
  288. package/tsconfig.prod.json +23 -0
  289. package/tsdown.config.ts +15 -3
  290. package/typedoc.json +7 -7
  291. package/vite.config.js +7 -0
  292. package/vitest.config.ts +5 -2
  293. package/vitest.visual.config.ts +48 -0
  294. package/src/components/AutoSizeInput.tsx +0 -65
  295. package/src/components/Controls.tsx +0 -87
  296. package/src/components/InputSocket.tsx +0 -142
  297. package/src/components/Node.tsx +0 -68
  298. package/src/components/NodeContainer.tsx +0 -46
  299. package/src/components/NodePicker.tsx +0 -77
  300. package/src/components/OutputSocket.tsx +0 -58
  301. package/src/components/modals/ClearModal.tsx +0 -40
  302. package/src/components/modals/HelpModal.tsx +0 -36
  303. package/src/components/modals/LoadModal.tsx +0 -96
  304. package/src/components/modals/Modal.tsx +0 -64
  305. package/src/components/modals/SaveModal.tsx +0 -60
  306. package/src/hooks/useCustomNodeTypes.tsx +0 -31
  307. package/src/hooks/useGraphRunner.ts +0 -104
  308. package/src/hooks/useMergeMap.ts +0 -14
  309. package/src/hooks/useNodeSpecJson.ts +0 -20
  310. package/src/hooks/useQueriableDefinitions.ts +0 -22
  311. package/src/styles.css +0 -8
  312. package/tailwind.config.ts +0 -19
  313. package/tests/tsconfig.json +0 -10
  314. /package/src/{types.d.ts → types-declarations.d.ts} +0 -0
@@ -0,0 +1,255 @@
1
+ /**
2
+ * WebSocket client plugin for the Behave-Graph Execution Protocol
3
+ * Provides UI and store integration for remote graph execution
4
+ */
5
+
6
+ import { type System } from '../../system/system';
7
+ import { graphRunnerClientStoreFactory } from './store';
8
+ import { GraphRunnerClient } from './client';
9
+ import { GraphRunnerPanel } from './panel';
10
+ import { ErrorBoundary } from 'react-error-boundary';
11
+ import { MenuItemElement } from '../../components/menubar/menuItem';
12
+ import type { StoreApi } from 'zustand';
13
+ import type { GraphRunnerClientStore } from './store';
14
+ import { GraphRunnerButtons } from './buttons';
15
+ import { plugin } from '@/system/plugin';
16
+ import { isBehaveNode } from '@/util/isBehaveNode';
17
+ import type { Node } from 'reactflow';
18
+ import { GraphRunner } from './runner';
19
+
20
+ export * from './types';
21
+ export * from './client';
22
+ export * from './transport';
23
+ export * from './panel';
24
+ export * from './runner';
25
+ export * from './store';
26
+ export * from './session';
27
+ /**
28
+ * Options for the GraphRunner plugin
29
+ */
30
+ export interface GraphRunnerClientPluginOptions {
31
+ /**
32
+ * Preconfigured GraphRunner client instance.
33
+ * If provided, the plugin will use this client instead of creating a new one.
34
+ * Useful when the client is already connected via a custom transport (e.g., VSCode IPC).
35
+ */
36
+ client?: GraphRunnerClient;
37
+
38
+ /**
39
+ * Preconfigured store instance.
40
+ * If provided, the plugin will use this store instead of creating a new one.
41
+ * Useful for sharing state with external components.
42
+ */
43
+ store?: StoreApi<GraphRunnerClientStore>;
44
+
45
+ /**
46
+ * Whether to skip automatic connection.
47
+ * Default: false (will attempt to connect if client is not provided or not connected)
48
+ */
49
+ skipAutoConnect?: boolean;
50
+
51
+ /**
52
+ * Whether to add the menu item to the Window menu.
53
+ * Default: true
54
+ */
55
+ addMenuItem?: boolean;
56
+ }
57
+
58
+ /**
59
+ * Plugin initialization function
60
+ * Registers the GraphRunnerClient store and actions with the system
61
+ */
62
+ export async function graphRunnerClientPluginLoader(
63
+ system: System,
64
+ options: GraphRunnerClientPluginOptions = {}
65
+ ) {
66
+ // Use provided store or create a new one
67
+ const store = options.store ?? graphRunnerClientStoreFactory(system);
68
+
69
+ // If a preconfigured client is provided, set it in the store
70
+ if (options.client) {
71
+ store.getState().setClient(options.client);
72
+
73
+ // If client is already connected, update connection state
74
+ if (options.client.isConnected()) {
75
+ store.getState().setConnectionState('connected');
76
+
77
+ // Populate connection info if available
78
+ const connectionInfo = {
79
+ serverId: options.client.getServerId(),
80
+ userId: options.client.getUserId(),
81
+ authenticated: options.client.isAuthenticated(),
82
+ capabilities: options.client.getCachedCapabilities(),
83
+ sessionId: null // Session management is external when client is provided
84
+ };
85
+ store.getState().setConnectionInfo(connectionInfo);
86
+ }
87
+ }
88
+
89
+ // Create and decorate actions
90
+ const runner = new GraphRunner(system, store);
91
+ system.decorate('runner', runner);
92
+
93
+ // Add toolbar buttons for graph execution control
94
+ system.toolbarStore.getState().addGroup({
95
+ id: 'graph-runner-controls',
96
+ label: 'Graph Runner',
97
+ buttons: [
98
+ <GraphRunnerButtons
99
+ key="graph-runner-buttons"
100
+ store={store}
101
+ onPlay={() => runner.play()}
102
+ onPause={() => runner.pause()}
103
+ onResume={() => runner.resume()}
104
+ onStep={() => runner.step()}
105
+ onStop={() => runner.stop()}
106
+ />
107
+ ]
108
+ });
109
+
110
+ system.hotKeyStore.getState().register({
111
+ action: 'PLAY',
112
+ description: 'Triggers playing the graph',
113
+ trigger: 'p',
114
+ handler: () => {
115
+ if (runner.store.getState().isExecuting) {
116
+ runner.stop();
117
+ } else {
118
+ runner.play();
119
+ }
120
+ }
121
+ });
122
+
123
+ // Register the panel with TabLoader
124
+ system.tabLoader.register('graphRunner', () => {
125
+ return {
126
+ id: 'graphRunner',
127
+ closable: true,
128
+ title: 'Remote Graph Runner',
129
+ group: 'default',
130
+ content: () => (
131
+ <ErrorBoundary fallback={'Error loading Graph Runner panel'}>
132
+ <GraphRunnerPanel system={system} />
133
+ </ErrorBoundary>
134
+ )
135
+ };
136
+ });
137
+
138
+ // Add menu item to Window menu (unless disabled)
139
+ if (options.addMenuItem !== false) {
140
+ const menuStore = system.menubarStore;
141
+ const currentItems = menuStore.getState().items;
142
+ const windowMenu = currentItems.find((menu) => menu.name === 'window');
143
+
144
+ if (windowMenu) {
145
+ // Add the Graph Runner menu item to the Window menu
146
+ const newMenuItem = {
147
+ name: 'graphRunner',
148
+ render: function GraphRunnerMenuItem() {
149
+ return (
150
+ <MenuItemElement
151
+ onClick={() => system.tabStore.getState().openTab('graphRunner')}
152
+ key="graphRunner"
153
+ >
154
+ Remote Graph Runner
155
+ </MenuItemElement>
156
+ );
157
+ }
158
+ };
159
+
160
+ menuStore
161
+ .getState()
162
+ .setSubMenuItems('window', [...windowMenu.items, newMenuItem]);
163
+ }
164
+ }
165
+
166
+ system.pubsub.subscribe('node:added', (_, node: Node) => {
167
+ if (!isBehaveNode(node)) {
168
+ return;
169
+ }
170
+
171
+ const client = runner.store.getState().client;
172
+ const currentRunId = runner.store.getState().currentRunId;
173
+ const graphId = runner.store.getState().currentGraphId;
174
+
175
+ // Only send if we have an active run and realtime is enabled
176
+ if (client && currentRunId && graphId) {
177
+ const capabilities = runner.store.getState().connectionInfo.capabilities;
178
+ if (capabilities?.realtime) {
179
+ client.addNode(
180
+ currentRunId,
181
+ node.id,
182
+ node.data.type,
183
+ node.data as Record<string, unknown>,
184
+ node.position
185
+ );
186
+ }
187
+ }
188
+ });
189
+
190
+ system.pubsub.subscribe('edge:added', (_, edge) => {
191
+ const client = runner.store.getState().client;
192
+ const currentRunId = runner.store.getState().currentRunId;
193
+ const graphId = runner.store.getState().currentGraphId;
194
+
195
+ // Only send if we have an active run and realtime is enabled
196
+ if (client && currentRunId && graphId && edge.source && edge.target) {
197
+ const capabilities = runner.store.getState().connectionInfo.capabilities;
198
+ if (capabilities?.realtime) {
199
+ client.createLink(
200
+ currentRunId,
201
+ edge.source,
202
+ edge.sourceHandle || '',
203
+ edge.target,
204
+ edge.targetHandle || ''
205
+ );
206
+ }
207
+ }
208
+ });
209
+
210
+ system.pubsub.subscribe('edge:removed', (_, edge) => {
211
+ const client = runner.store.getState().client;
212
+ const currentRunId = runner.store.getState().currentRunId;
213
+ const graphId = runner.store.getState().currentGraphId;
214
+
215
+ // Only send if we have an active run and realtime is enabled
216
+ if (client && currentRunId && graphId && edge.source && edge.target) {
217
+ const capabilities = runner.store.getState().connectionInfo.capabilities;
218
+ if (capabilities?.realtime) {
219
+ client.removeLink(
220
+ currentRunId,
221
+ edge.source,
222
+ edge.sourceHandle || '',
223
+ edge.target,
224
+ edge.targetHandle || ''
225
+ );
226
+ }
227
+ }
228
+ });
229
+
230
+ system.pubsub.subscribe('node:removed', (_, node: Node) => {
231
+ if (!isBehaveNode(node)) {
232
+ return;
233
+ }
234
+
235
+ const client = runner.store.getState().client;
236
+ const currentRunId = runner.store.getState().currentRunId;
237
+ const graphId = runner.store.getState().currentGraphId;
238
+
239
+ // Only send if we have an active run and realtime is enabled
240
+ if (client && currentRunId && graphId) {
241
+ const capabilities = runner.store.getState().connectionInfo.capabilities;
242
+ if (capabilities?.realtime) {
243
+ client.removeNode(currentRunId, node.id);
244
+ }
245
+ }
246
+ });
247
+
248
+ if (!options.skipAutoConnect) {
249
+ await runner.connect();
250
+ }
251
+ }
252
+
253
+ export const graphRunnerClientPlugin = plugin(graphRunnerClientPluginLoader, {
254
+ name: 'graph-runner-client'
255
+ });
@@ -0,0 +1,386 @@
1
+ import React, { useState } from 'react';
2
+ import { useStore } from 'zustand';
3
+ import type { System } from '../../system/system';
4
+ import type { AuthCredentials } from './types';
5
+ import {
6
+ VscodeButton,
7
+ VscodeTextfield,
8
+ VscodeCheckbox,
9
+ VscodeSingleSelect,
10
+ VscodeOption,
11
+ VscodeLabel,
12
+ VscodeBadge,
13
+ VscodeTree,
14
+ VscodeTreeItem,
15
+ VscodeCollapsible
16
+ } from '@vscode-elements/react-elements';
17
+ import styles from './styles.module.css';
18
+
19
+ interface GraphRunnerPanelProps {
20
+ system: System;
21
+ }
22
+
23
+ export const GraphRunnerPanel: React.FC<GraphRunnerPanelProps> = ({
24
+ system
25
+ }) => {
26
+ const store = system.runner.store;
27
+
28
+ const connectionState = useStore(store, (state) => state.connectionState);
29
+ const connectionConfig = useStore(store, (state) => state.connectionConfig);
30
+ const connectionInfo = useStore(store, (state) => state.connectionInfo);
31
+ const error = useStore(store, (state) => state.error);
32
+ const serverVariables = useStore(store, (state) => state.serverVariables);
33
+ const serverEvents = useStore(store, (state) => state.serverEvents);
34
+ const nodeTypes = useStore(store, (state) => state.nodeTypes);
35
+ const messageActivity = useStore(store, (state) => state.messageActivity);
36
+ const clearLogsOnRun = useStore(store, (state) => state.clearLogsOnRun);
37
+ const clearTracesOnRun = useStore(store, (state) => state.clearTracesOnRun);
38
+ const enableTracing = useStore(store, (state) => state.enableTracing);
39
+
40
+ const icons = useStore(system.legendStore, (state) => state.icons);
41
+ const defaultIcon = useStore(
42
+ system.legendStore,
43
+ (state) => state.defaultIcon
44
+ );
45
+
46
+ const [url, setUrl] = useState(connectionConfig.url);
47
+ const [authType, setAuthType] = useState<'none' | 'bearer' | 'apiKey'>(
48
+ connectionConfig.auth.type
49
+ );
50
+ const [authToken, setAuthToken] = useState('');
51
+ const [autoReconnect, setAutoReconnect] = useState(
52
+ connectionConfig.autoReconnect
53
+ );
54
+
55
+ const handleConnect = async () => {
56
+ const auth: AuthCredentials =
57
+ authType === 'bearer'
58
+ ? { type: 'bearer', token: authToken }
59
+ : authType === 'apiKey'
60
+ ? { type: 'apiKey', key: authToken }
61
+ : { type: 'none' };
62
+
63
+ store.getState().setConnectionConfig({ url, auth, autoReconnect });
64
+
65
+ await system.runner.connect();
66
+ };
67
+
68
+ const handleDisconnect = async () => {
69
+ await system.runner.disconnect();
70
+ };
71
+
72
+ const handleRefreshMetadata = async () => {
73
+ await system.runner.refreshMetadata();
74
+ };
75
+
76
+ const handleClearMessages = () => {
77
+ store.getState().clearMessageActivity();
78
+ };
79
+
80
+ const isConnected = connectionState === 'connected';
81
+ const isConnecting =
82
+ connectionState === 'connecting' || connectionState === 'authenticating';
83
+
84
+ return (
85
+ <div className={styles.panel}>
86
+ {/* Scrollable Content Container */}
87
+ <div className={styles.scrollContainer}>
88
+ <h3 className={styles.title}>
89
+ Remote Graph Runner
90
+ <VscodeBadge variant="tab-header-counter">
91
+ {isConnected ? 'Connected' : 'Disconnected'}
92
+ </VscodeBadge>
93
+ </h3>
94
+
95
+ <div>
96
+ {/* Connection Form */}
97
+ <VscodeCollapsible heading="Connection Settings">
98
+ <div className={styles.connectionForm}>
99
+ <div>
100
+ <VscodeLabel>Server URL</VscodeLabel>
101
+ <VscodeTextfield
102
+ value={url}
103
+ onChange={(e: any) => setUrl(e.target.value)}
104
+ placeholder="ws://localhost:8080"
105
+ disabled={isConnected || isConnecting}
106
+ className={styles.formField}
107
+ />
108
+ </div>
109
+
110
+ <div>
111
+ <VscodeLabel>Authentication</VscodeLabel>
112
+ <VscodeSingleSelect
113
+ value={authType}
114
+ onChange={(e: any) =>
115
+ setAuthType(e.target.value as 'none' | 'bearer' | 'apiKey')
116
+ }
117
+ disabled={isConnected || isConnecting}
118
+ className={styles.formField}
119
+ >
120
+ <VscodeOption value="none">None</VscodeOption>
121
+ <VscodeOption value="bearer">Bearer Token</VscodeOption>
122
+ <VscodeOption value="apiKey">API Key</VscodeOption>
123
+ </VscodeSingleSelect>
124
+ </div>
125
+
126
+ {authType !== 'none' && (
127
+ <div>
128
+ <VscodeLabel>
129
+ {authType === 'bearer' ? 'Token' : 'API Key'}
130
+ </VscodeLabel>
131
+ <VscodeTextfield
132
+ type="password"
133
+ value={authToken}
134
+ onChange={(e: any) => setAuthToken(e.target.value)}
135
+ placeholder={
136
+ authType === 'bearer'
137
+ ? 'Enter bearer token'
138
+ : 'Enter API key'
139
+ }
140
+ disabled={isConnected || isConnecting}
141
+ className={styles.formField}
142
+ />
143
+ </div>
144
+ )}
145
+
146
+ <VscodeCheckbox
147
+ checked={autoReconnect}
148
+ onChange={(e: any) => setAutoReconnect(e.target.checked)}
149
+ disabled={isConnected || isConnecting}
150
+ >
151
+ Auto-reconnect
152
+ </VscodeCheckbox>
153
+
154
+ <div className={styles.section}>
155
+ <h4 className={styles.sectionTitle}>Execution Preferences</h4>
156
+ <VscodeCheckbox
157
+ checked={enableTracing}
158
+ onChange={(e: any) =>
159
+ store.getState().setEnableTracing(e.target.checked)
160
+ }
161
+ >
162
+ Enable execution tracing
163
+ </VscodeCheckbox>
164
+ <VscodeCheckbox
165
+ checked={clearLogsOnRun}
166
+ onChange={(e: any) =>
167
+ store.getState().setClearLogsOnRun(e.target.checked)
168
+ }
169
+ >
170
+ Clear logs on new run
171
+ </VscodeCheckbox>
172
+ <VscodeCheckbox
173
+ checked={clearTracesOnRun}
174
+ onChange={(e: any) =>
175
+ store.getState().setClearTracesOnRun(e.target.checked)
176
+ }
177
+ >
178
+ Clear traces on new run
179
+ </VscodeCheckbox>
180
+ </div>
181
+
182
+ <div className={styles.buttonGroup}>
183
+ {!isConnected && (
184
+ <VscodeButton
185
+ onClick={handleConnect}
186
+ disabled={isConnecting || !url}
187
+ className={styles.button}
188
+ >
189
+ {isConnecting ? 'Connecting...' : 'Connect'}
190
+ </VscodeButton>
191
+ )}
192
+ {isConnected && (
193
+ <>
194
+ <VscodeButton
195
+ onClick={handleDisconnect}
196
+ className={styles.button}
197
+ >
198
+ Disconnect
199
+ </VscodeButton>
200
+ <VscodeButton
201
+ onClick={handleRefreshMetadata}
202
+ className={styles.button}
203
+ >
204
+ Refresh
205
+ </VscodeButton>
206
+ </>
207
+ )}
208
+ </div>
209
+ </div>
210
+ </VscodeCollapsible>
211
+
212
+ {/* Error Display */}
213
+ {error && (
214
+ <div className={styles.errorBox}>
215
+ <strong>Error:</strong> {error}
216
+ </div>
217
+ )}
218
+
219
+ {/* Connection Info */}
220
+ {isConnected && (
221
+ <VscodeCollapsible heading="Status">
222
+ <div className={styles.infoBox}>
223
+ <div>
224
+ <strong>Status:</strong> Connected
225
+ </div>
226
+ {connectionInfo.serverId && (
227
+ <div className={styles.infoField}>
228
+ <strong>Server:</strong> {connectionInfo.serverId}
229
+ </div>
230
+ )}
231
+ {connectionInfo.sessionId && (
232
+ <div className={styles.infoField}>
233
+ <strong>Session:</strong> {connectionInfo.sessionId}
234
+ </div>
235
+ )}
236
+ {connectionInfo.userId && (
237
+ <div className={styles.infoField}>
238
+ <strong>User:</strong> {connectionInfo.userId}
239
+ </div>
240
+ )}
241
+ {connectionInfo.capabilities && (
242
+ <div className={styles.infoField}>
243
+ <strong>Capabilities:</strong>{' '}
244
+ {Object.entries(connectionInfo.capabilities)
245
+ .filter(([_, v]) => v === true)
246
+ .map(([k]) => k)
247
+ .join(', ')}
248
+ </div>
249
+ )}
250
+ </div>
251
+ </VscodeCollapsible>
252
+ )}
253
+ {isConnected && (
254
+ <>
255
+ <VscodeCollapsible heading="Variables">
256
+ <VscodeBadge slot="decorations">
257
+ {serverVariables.length}
258
+ </VscodeBadge>
259
+ <VscodeTree>
260
+ {serverVariables.map((variable) => {
261
+ const Icon = icons[variable.valueTypeName] ?? defaultIcon;
262
+ const IconComponent = Icon as React.FC<{ slot?: string }>;
263
+ return (
264
+ <VscodeTreeItem key={variable.name}>
265
+ <IconComponent slot="icon-leaf" />
266
+ <span>{variable.name}</span>
267
+ </VscodeTreeItem>
268
+ );
269
+ })}
270
+ </VscodeTree>
271
+ </VscodeCollapsible>
272
+
273
+ <VscodeCollapsible heading="Events">
274
+ <VscodeBadge slot="decorations">
275
+ {serverEvents.length}
276
+ </VscodeBadge>
277
+
278
+ <div className={styles.tabPanelGap}>
279
+ {serverEvents.length === 0 ? (
280
+ <p className={styles.emptyMessage}>
281
+ No server events available
282
+ </p>
283
+ ) : (
284
+ <VscodeTree>
285
+ {serverEvents.map((event) => (
286
+ <VscodeTreeItem key={event.name}>
287
+ <span className={styles.treeItemTitle}>
288
+ {event.name}
289
+ </span>
290
+ <VscodeTreeItem key={event.name}>
291
+ <span slot="description">{event.description}</span>
292
+ {event.payloadSchema != null ? (
293
+ <pre className={styles.codeBlock}>
294
+ {JSON.stringify(event.payloadSchema, null, 2)}
295
+ </pre>
296
+ ) : null}
297
+ </VscodeTreeItem>
298
+ </VscodeTreeItem>
299
+ ))}
300
+ </VscodeTree>
301
+ )}
302
+ </div>
303
+ </VscodeCollapsible>
304
+
305
+ <VscodeCollapsible heading="Nodes">
306
+ <VscodeBadge slot="decorations">{nodeTypes.length}</VscodeBadge>
307
+ <div className={styles.tabPanelGap}>
308
+ {nodeTypes.length === 0 ? (
309
+ <p className={styles.emptyMessage}>
310
+ No node types available
311
+ </p>
312
+ ) : (
313
+ <VscodeTree>
314
+ {nodeTypes.map((node) => (
315
+ <VscodeTreeItem>
316
+ {node.type}
317
+
318
+ <span slot="description">{node.category}</span>
319
+ </VscodeTreeItem>
320
+ ))}
321
+ </VscodeTree>
322
+ )}
323
+ </div>
324
+ </VscodeCollapsible>
325
+ <VscodeCollapsible heading="Message Activity">
326
+ <VscodeBadge slot="decorations">
327
+ {messageActivity.length}
328
+ </VscodeBadge>
329
+ <div className={styles.tabPanelGapLarge}>
330
+ <div className={styles.messagesToolbar}>
331
+ <div className={styles.messagesCount}>
332
+ {messageActivity.length} message
333
+ {messageActivity.length !== 1 ? 's' : ''}
334
+ </div>
335
+ {messageActivity.length > 0 && (
336
+ <VscodeButton onClick={handleClearMessages}>
337
+ Clear
338
+ </VscodeButton>
339
+ )}
340
+ </div>
341
+ {messageActivity.length === 0 ? (
342
+ <p className={styles.emptyMessage}>No messages yet</p>
343
+ ) : (
344
+ <div className={styles.tabPanelGap}>
345
+ {messageActivity.map((activity) => {
346
+ const time = new Date(
347
+ activity.timestamp
348
+ ).toLocaleTimeString();
349
+ const directionColor =
350
+ activity.direction === 'sent'
351
+ ? 'var(--vscode-gitDecoration-modifiedResourceForeground)'
352
+ : 'var(--vscode-gitDecoration-addedResourceForeground)';
353
+
354
+ return (
355
+ <div key={activity.id} className={styles.messageCard}>
356
+ <div className={styles.messageHeader}>
357
+ <div className={styles.messageDirection}>
358
+ <span
359
+ className={styles.messageDirectionIcon}
360
+ style={{ color: directionColor }}
361
+ >
362
+ {activity.direction === 'sent' ? '→' : '←'}
363
+ </span>
364
+ <span className={styles.messageType}>
365
+ {activity.message.type}
366
+ </span>
367
+ </div>
368
+ <span className={styles.messageTime}>{time}</span>
369
+ </div>
370
+ <pre className={styles.messageContent}>
371
+ {JSON.stringify(activity.message, null, 2)}
372
+ </pre>
373
+ </div>
374
+ );
375
+ })}
376
+ </div>
377
+ )}
378
+ </div>
379
+ </VscodeCollapsible>
380
+ </>
381
+ )}
382
+ </div>
383
+ </div>
384
+ </div>
385
+ );
386
+ };