@flowdrop/flowdrop 1.4.0 → 1.6.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 (441) hide show
  1. package/README.md +94 -51
  2. package/dist/adapters/WorkflowAdapter.d.ts +1 -1
  3. package/dist/adapters/WorkflowAdapter.js +27 -47
  4. package/dist/adapters/agentspec/AgentSpecAdapter.d.ts +2 -2
  5. package/dist/adapters/agentspec/AgentSpecAdapter.js +122 -133
  6. package/dist/adapters/agentspec/agentAdapter.d.ts +2 -2
  7. package/dist/adapters/agentspec/agentAdapter.js +10 -10
  8. package/dist/adapters/agentspec/autoLayout.d.ts +52 -6
  9. package/dist/adapters/agentspec/autoLayout.js +118 -23
  10. package/dist/adapters/agentspec/componentTypeDefaults.d.ts +1 -1
  11. package/dist/adapters/agentspec/componentTypeDefaults.js +120 -120
  12. package/dist/adapters/agentspec/defaultNodeTypes.d.ts +2 -2
  13. package/dist/adapters/agentspec/defaultNodeTypes.js +307 -307
  14. package/dist/adapters/agentspec/index.d.ts +10 -10
  15. package/dist/adapters/agentspec/index.js +6 -6
  16. package/dist/adapters/agentspec/validator.d.ts +2 -2
  17. package/dist/adapters/agentspec/validator.js +20 -22
  18. package/dist/api/enhanced-client.d.ts +3 -3
  19. package/dist/api/enhanced-client.js +72 -73
  20. package/dist/chat/commandClassifier.d.ts +19 -0
  21. package/dist/chat/commandClassifier.js +30 -0
  22. package/dist/chat/index.d.ts +27 -0
  23. package/dist/chat/index.js +32 -0
  24. package/dist/chat/responseParser.d.ts +21 -0
  25. package/dist/chat/responseParser.js +91 -0
  26. package/dist/commands/batch.d.ts +18 -0
  27. package/dist/commands/batch.js +54 -0
  28. package/dist/commands/executor.d.ts +37 -0
  29. package/dist/commands/executor.js +1133 -0
  30. package/dist/commands/index.d.ts +14 -0
  31. package/dist/commands/index.js +17 -0
  32. package/dist/commands/parser.d.ts +16 -0
  33. package/dist/commands/parser.js +295 -0
  34. package/dist/commands/positioner.d.ts +19 -0
  35. package/dist/commands/positioner.js +33 -0
  36. package/dist/commands/storeIntegration.svelte.d.ts +16 -0
  37. package/dist/commands/storeIntegration.svelte.js +67 -0
  38. package/dist/commands/types.d.ts +343 -0
  39. package/dist/commands/types.js +45 -0
  40. package/dist/components/App.svelte +522 -237
  41. package/dist/components/App.svelte.d.ts +11 -8
  42. package/dist/components/CanvasBanner.stories.svelte +10 -16
  43. package/dist/components/CanvasBanner.stories.svelte.d.ts +1 -1
  44. package/dist/components/CanvasBanner.svelte +2 -2
  45. package/dist/components/CanvasBanner.svelte.d.ts +1 -1
  46. package/dist/components/CanvasController.svelte +37 -0
  47. package/dist/components/CanvasController.svelte.d.ts +32 -0
  48. package/dist/components/ConfigForm.svelte +118 -256
  49. package/dist/components/ConfigForm.svelte.d.ts +2 -2
  50. package/dist/components/ConfigMappingRow.svelte +128 -0
  51. package/dist/components/ConfigMappingRow.svelte.d.ts +8 -0
  52. package/dist/components/ConfigModal.svelte +3 -3
  53. package/dist/components/ConfigModal.svelte.d.ts +1 -1
  54. package/dist/components/ConfigPanel.stories.svelte +19 -19
  55. package/dist/components/ConfigPanel.stories.svelte.d.ts +1 -1
  56. package/dist/components/ConfigPanel.svelte +57 -19
  57. package/dist/components/ConfigPanel.svelte.d.ts +3 -1
  58. package/dist/components/ConnectionLine.svelte +4 -4
  59. package/dist/components/EdgeRefresher.svelte +1 -1
  60. package/dist/components/FlowDropEdge.stories.svelte +110 -110
  61. package/dist/components/FlowDropEdge.svelte +11 -19
  62. package/dist/components/FlowDropEdge.svelte.d.ts +1 -1
  63. package/dist/components/FlowDropZone.svelte +6 -9
  64. package/dist/components/FlowDropZone.svelte.d.ts +1 -1
  65. package/dist/components/LoadingSpinner.stories.svelte +13 -13
  66. package/dist/components/LoadingSpinner.stories.svelte.d.ts +1 -1
  67. package/dist/components/LoadingSpinner.svelte +3 -3
  68. package/dist/components/LoadingSpinner.svelte.d.ts +1 -1
  69. package/dist/components/Logo.stories.svelte +4 -4
  70. package/dist/components/Logo.stories.svelte.d.ts +1 -1
  71. package/dist/components/Logo.svelte +3 -9
  72. package/dist/components/LogsSidebar.svelte +46 -53
  73. package/dist/components/LogsSidebar.svelte.d.ts +1 -1
  74. package/dist/components/MarkdownDisplay.stories.svelte +10 -14
  75. package/dist/components/MarkdownDisplay.stories.svelte.d.ts +1 -1
  76. package/dist/components/MarkdownDisplay.svelte +4 -6
  77. package/dist/components/Navbar.stories.svelte +19 -19
  78. package/dist/components/Navbar.stories.svelte.d.ts +1 -1
  79. package/dist/components/Navbar.svelte +28 -49
  80. package/dist/components/Navbar.svelte.d.ts +2 -2
  81. package/dist/components/NodeSidebar.svelte +55 -135
  82. package/dist/components/NodeSidebar.svelte.d.ts +1 -1
  83. package/dist/components/NodeStatusOverlay.stories.svelte +19 -31
  84. package/dist/components/NodeStatusOverlay.stories.svelte.d.ts +1 -1
  85. package/dist/components/NodeStatusOverlay.svelte +40 -55
  86. package/dist/components/NodeStatusOverlay.svelte.d.ts +3 -3
  87. package/dist/components/NodeSwapPicker.svelte +493 -0
  88. package/dist/components/NodeSwapPicker.svelte.d.ts +16 -0
  89. package/dist/components/PipelineStatus.svelte +63 -89
  90. package/dist/components/PipelineStatus.svelte.d.ts +4 -4
  91. package/dist/components/PortCoordinateTracker.svelte +5 -7
  92. package/dist/components/PortCoordinateTracker.svelte.d.ts +1 -1
  93. package/dist/components/PortMappingRow.svelte +205 -0
  94. package/dist/components/PortMappingRow.svelte.d.ts +12 -0
  95. package/dist/components/ReadOnlyDetails.svelte +1 -1
  96. package/dist/components/SchemaForm.stories.svelte +53 -53
  97. package/dist/components/SchemaForm.stories.svelte.d.ts +1 -1
  98. package/dist/components/SchemaForm.svelte +24 -51
  99. package/dist/components/SchemaForm.svelte.d.ts +2 -2
  100. package/dist/components/SettingsModal.svelte +6 -9
  101. package/dist/components/SettingsModal.svelte.d.ts +1 -1
  102. package/dist/components/SettingsPanel.svelte +138 -158
  103. package/dist/components/SettingsPanel.svelte.d.ts +1 -1
  104. package/dist/components/StatusIcon.stories.svelte +16 -29
  105. package/dist/components/StatusIcon.stories.svelte.d.ts +1 -1
  106. package/dist/components/StatusIcon.svelte +19 -19
  107. package/dist/components/StatusIcon.svelte.d.ts +2 -2
  108. package/dist/components/StatusLabel.stories.svelte +8 -8
  109. package/dist/components/StatusLabel.stories.svelte.d.ts +1 -1
  110. package/dist/components/SwapMappingEditor.svelte +529 -0
  111. package/dist/components/SwapMappingEditor.svelte.d.ts +12 -0
  112. package/dist/components/ThemeToggle.stories.svelte +10 -10
  113. package/dist/components/ThemeToggle.stories.svelte.d.ts +1 -1
  114. package/dist/components/ThemeToggle.svelte +22 -33
  115. package/dist/components/ThemeToggle.svelte.d.ts +1 -1
  116. package/dist/components/UniversalNode.svelte +29 -41
  117. package/dist/components/UniversalNode.svelte.d.ts +3 -3
  118. package/dist/components/WorkflowEditor.svelte +210 -170
  119. package/dist/components/WorkflowEditor.svelte.d.ts +12 -4
  120. package/dist/components/chat/AIChatPanel.svelte +797 -0
  121. package/dist/components/chat/AIChatPanel.svelte.d.ts +13 -0
  122. package/dist/components/chat/CommandPreview.svelte +234 -0
  123. package/dist/components/chat/CommandPreview.svelte.d.ts +9 -0
  124. package/dist/components/console/CommandConsole.stories.svelte +111 -0
  125. package/dist/components/console/CommandConsole.stories.svelte.d.ts +27 -0
  126. package/dist/components/console/CommandConsole.svelte +263 -0
  127. package/dist/components/console/CommandConsole.svelte.d.ts +11 -0
  128. package/dist/components/console/ConsoleAutocomplete.svelte +142 -0
  129. package/dist/components/console/ConsoleAutocomplete.svelte.d.ts +21 -0
  130. package/dist/components/console/ConsoleInput.svelte +771 -0
  131. package/dist/components/console/ConsoleInput.svelte.d.ts +16 -0
  132. package/dist/components/console/ConsoleOutput.svelte +116 -0
  133. package/dist/components/console/ConsoleOutput.svelte.d.ts +11 -0
  134. package/dist/components/console/formatters.d.ts +26 -0
  135. package/dist/components/console/formatters.js +116 -0
  136. package/dist/components/form/FormArray.svelte +75 -132
  137. package/dist/components/form/FormArray.svelte.d.ts +1 -1
  138. package/dist/components/form/FormAutocomplete.svelte +65 -108
  139. package/dist/components/form/FormAutocomplete.svelte.d.ts +1 -1
  140. package/dist/components/form/FormCheckboxGroup.stories.svelte +13 -16
  141. package/dist/components/form/FormCheckboxGroup.stories.svelte.d.ts +1 -1
  142. package/dist/components/form/FormCheckboxGroup.svelte +2 -2
  143. package/dist/components/form/FormCodeEditor.svelte +42 -56
  144. package/dist/components/form/FormField.svelte +79 -90
  145. package/dist/components/form/FormField.svelte.d.ts +2 -2
  146. package/dist/components/form/FormFieldLight.svelte +72 -88
  147. package/dist/components/form/FormFieldLight.svelte.d.ts +1 -1
  148. package/dist/components/form/FormFieldWrapper.stories.svelte +14 -14
  149. package/dist/components/form/FormFieldWrapper.stories.svelte.d.ts +1 -1
  150. package/dist/components/form/FormFieldWrapper.svelte +2 -9
  151. package/dist/components/form/FormFieldWrapper.svelte.d.ts +1 -1
  152. package/dist/components/form/FormFieldset.svelte +3 -3
  153. package/dist/components/form/FormFieldset.svelte.d.ts +2 -2
  154. package/dist/components/form/FormMarkdownEditor.svelte +123 -156
  155. package/dist/components/form/FormNumberField.stories.svelte +18 -18
  156. package/dist/components/form/FormNumberField.stories.svelte.d.ts +1 -1
  157. package/dist/components/form/FormNumberField.svelte +6 -6
  158. package/dist/components/form/FormRangeField.stories.svelte +13 -13
  159. package/dist/components/form/FormRangeField.stories.svelte.d.ts +1 -1
  160. package/dist/components/form/FormRangeField.svelte +4 -12
  161. package/dist/components/form/FormSelect.stories.svelte +21 -21
  162. package/dist/components/form/FormSelect.stories.svelte.d.ts +1 -1
  163. package/dist/components/form/FormSelect.svelte +5 -5
  164. package/dist/components/form/FormSelect.svelte.d.ts +1 -1
  165. package/dist/components/form/FormTemplateEditor.svelte +126 -175
  166. package/dist/components/form/FormTemplateEditor.svelte.d.ts +1 -1
  167. package/dist/components/form/FormTextField.stories.svelte +17 -23
  168. package/dist/components/form/FormTextField.stories.svelte.d.ts +1 -1
  169. package/dist/components/form/FormTextField.svelte +4 -4
  170. package/dist/components/form/FormTextarea.stories.svelte +18 -21
  171. package/dist/components/form/FormTextarea.stories.svelte.d.ts +1 -1
  172. package/dist/components/form/FormTextarea.svelte +4 -4
  173. package/dist/components/form/FormToggle.stories.svelte +13 -16
  174. package/dist/components/form/FormToggle.stories.svelte.d.ts +1 -1
  175. package/dist/components/form/FormToggle.svelte +3 -3
  176. package/dist/components/form/FormUISchemaRenderer.svelte +12 -19
  177. package/dist/components/form/FormUISchemaRenderer.svelte.d.ts +3 -3
  178. package/dist/components/form/index.d.ts +19 -19
  179. package/dist/components/form/index.js +18 -18
  180. package/dist/components/form/templateAutocomplete.d.ts +2 -2
  181. package/dist/components/form/templateAutocomplete.js +55 -64
  182. package/dist/components/form/types.d.ts +6 -6
  183. package/dist/components/form/types.js +4 -9
  184. package/dist/components/icons/AlertCircleIcon.svelte +1 -6
  185. package/dist/components/icons/CogIcon.svelte +1 -6
  186. package/dist/components/interrupt/ChoicePrompt.stories.svelte +27 -27
  187. package/dist/components/interrupt/ChoicePrompt.stories.svelte.d.ts +1 -1
  188. package/dist/components/interrupt/ChoicePrompt.svelte +17 -41
  189. package/dist/components/interrupt/ChoicePrompt.svelte.d.ts +1 -1
  190. package/dist/components/interrupt/ConfirmationPrompt.stories.svelte +17 -17
  191. package/dist/components/interrupt/ConfirmationPrompt.stories.svelte.d.ts +1 -1
  192. package/dist/components/interrupt/ConfirmationPrompt.svelte +10 -16
  193. package/dist/components/interrupt/ConfirmationPrompt.svelte.d.ts +1 -1
  194. package/dist/components/interrupt/FormPrompt.svelte +10 -15
  195. package/dist/components/interrupt/FormPrompt.svelte.d.ts +1 -1
  196. package/dist/components/interrupt/InterruptBubble.svelte +87 -121
  197. package/dist/components/interrupt/InterruptBubble.svelte.d.ts +2 -2
  198. package/dist/components/interrupt/ReviewPrompt.stories.svelte +37 -37
  199. package/dist/components/interrupt/ReviewPrompt.stories.svelte.d.ts +1 -1
  200. package/dist/components/interrupt/ReviewPrompt.svelte +55 -75
  201. package/dist/components/interrupt/ReviewPrompt.svelte.d.ts +1 -1
  202. package/dist/components/interrupt/TextInputPrompt.stories.svelte +16 -17
  203. package/dist/components/interrupt/TextInputPrompt.stories.svelte.d.ts +1 -1
  204. package/dist/components/interrupt/TextInputPrompt.svelte +13 -18
  205. package/dist/components/interrupt/TextInputPrompt.svelte.d.ts +1 -1
  206. package/dist/components/interrupt/index.d.ts +6 -5
  207. package/dist/components/interrupt/index.js +6 -5
  208. package/dist/components/layouts/MainLayout.svelte +46 -84
  209. package/dist/components/layouts/MainLayout.svelte.d.ts +6 -6
  210. package/dist/components/nodes/GatewayNode.stories.svelte +64 -65
  211. package/dist/components/nodes/GatewayNode.svelte +37 -70
  212. package/dist/components/nodes/GatewayNode.svelte.d.ts +3 -3
  213. package/dist/components/nodes/IdeaNode.stories.svelte +25 -26
  214. package/dist/components/nodes/IdeaNode.svelte +22 -36
  215. package/dist/components/nodes/IdeaNode.svelte.d.ts +1 -1
  216. package/dist/components/nodes/NotesNode.stories.svelte +37 -38
  217. package/dist/components/nodes/NotesNode.svelte +28 -39
  218. package/dist/components/nodes/NotesNode.svelte.d.ts +1 -1
  219. package/dist/components/nodes/SimpleNode.stories.svelte +137 -138
  220. package/dist/components/nodes/SimpleNode.svelte +44 -74
  221. package/dist/components/nodes/SimpleNode.svelte.d.ts +1 -1
  222. package/dist/components/nodes/SquareNode.stories.svelte +75 -75
  223. package/dist/components/nodes/SquareNode.svelte +42 -68
  224. package/dist/components/nodes/SquareNode.svelte.d.ts +1 -1
  225. package/dist/components/nodes/TerminalNode.stories.svelte +10 -10
  226. package/dist/components/nodes/TerminalNode.svelte +74 -112
  227. package/dist/components/nodes/TerminalNode.svelte.d.ts +1 -1
  228. package/dist/components/nodes/ToolNode.stories.svelte +115 -116
  229. package/dist/components/nodes/ToolNode.svelte +31 -64
  230. package/dist/components/nodes/ToolNode.svelte.d.ts +1 -1
  231. package/dist/components/nodes/WorkflowNode.stories.svelte +84 -89
  232. package/dist/components/nodes/WorkflowNode.svelte +50 -103
  233. package/dist/components/nodes/WorkflowNode.svelte.d.ts +3 -3
  234. package/dist/components/playground/ChatPanel.svelte +47 -103
  235. package/dist/components/playground/ExecutionLogs.svelte +45 -68
  236. package/dist/components/playground/InputCollector.svelte +32 -51
  237. package/dist/components/playground/MessageBubble.stories.svelte +25 -25
  238. package/dist/components/playground/MessageBubble.stories.svelte.d.ts +1 -1
  239. package/dist/components/playground/MessageBubble.svelte +54 -70
  240. package/dist/components/playground/MessageBubble.svelte.d.ts +1 -1
  241. package/dist/components/playground/Playground.svelte +60 -91
  242. package/dist/components/playground/Playground.svelte.d.ts +3 -3
  243. package/dist/components/playground/PlaygroundModal.svelte +8 -12
  244. package/dist/components/playground/PlaygroundModal.svelte.d.ts +3 -3
  245. package/dist/components/playground/SessionManager.svelte +34 -40
  246. package/dist/components/playground/SessionManager.svelte.d.ts +1 -1
  247. package/dist/config/agentSpecEndpoints.d.ts +1 -1
  248. package/dist/config/agentSpecEndpoints.js +20 -20
  249. package/dist/config/constants.js +2 -2
  250. package/dist/config/defaultCategories.d.ts +1 -1
  251. package/dist/config/defaultCategories.js +86 -86
  252. package/dist/config/defaultPortConfig.d.ts +1 -1
  253. package/dist/config/defaultPortConfig.js +144 -144
  254. package/dist/config/endpoints.d.ts +12 -4
  255. package/dist/config/endpoints.js +70 -65
  256. package/dist/config/runtimeConfig.d.ts +2 -2
  257. package/dist/config/runtimeConfig.js +8 -8
  258. package/dist/core/index.d.ts +68 -63
  259. package/dist/core/index.js +44 -35
  260. package/dist/display/index.d.ts +2 -2
  261. package/dist/display/index.js +2 -2
  262. package/dist/editor/index.d.ts +64 -62
  263. package/dist/editor/index.js +57 -55
  264. package/dist/form/code.d.ts +5 -5
  265. package/dist/form/code.js +14 -14
  266. package/dist/form/fieldRegistry.d.ts +3 -3
  267. package/dist/form/fieldRegistry.js +9 -11
  268. package/dist/form/full.d.ts +8 -8
  269. package/dist/form/full.js +9 -9
  270. package/dist/form/index.d.ts +18 -18
  271. package/dist/form/index.js +16 -16
  272. package/dist/form/markdown.d.ts +4 -4
  273. package/dist/form/markdown.js +8 -8
  274. package/dist/helpers/proximityConnect.d.ts +3 -3
  275. package/dist/helpers/proximityConnect.js +40 -35
  276. package/dist/helpers/workflowEditorHelper.d.ts +8 -58
  277. package/dist/helpers/workflowEditorHelper.js +73 -292
  278. package/dist/index.d.ts +6 -6
  279. package/dist/index.js +6 -6
  280. package/dist/mocks/app-environment.js +2 -2
  281. package/dist/mocks/app-forms.js +1 -1
  282. package/dist/mocks/app-navigation.js +2 -2
  283. package/dist/mocks/app-stores.js +3 -3
  284. package/dist/playground/index.d.ts +19 -19
  285. package/dist/playground/index.js +16 -16
  286. package/dist/playground/mount.d.ts +3 -3
  287. package/dist/playground/mount.js +24 -24
  288. package/dist/registry/builtinFormats.js +13 -13
  289. package/dist/registry/builtinNodes.d.ts +2 -2
  290. package/dist/registry/builtinNodes.js +77 -77
  291. package/dist/registry/index.d.ts +4 -4
  292. package/dist/registry/index.js +4 -4
  293. package/dist/registry/nodeComponentRegistry.d.ts +8 -8
  294. package/dist/registry/nodeComponentRegistry.js +9 -11
  295. package/dist/registry/plugin.d.ts +2 -2
  296. package/dist/registry/plugin.js +11 -11
  297. package/dist/registry/workflowFormatRegistry.d.ts +3 -3
  298. package/dist/registry/workflowFormatRegistry.js +2 -2
  299. package/dist/schema/index.d.ts +1 -1
  300. package/dist/schema/index.js +2 -2
  301. package/dist/schemas/v1/workflow.schema.json +107 -22
  302. package/dist/services/agentSpecExecutionService.d.ts +3 -3
  303. package/dist/services/agentSpecExecutionService.js +55 -56
  304. package/dist/services/api.d.ts +2 -2
  305. package/dist/services/api.js +37 -37
  306. package/dist/services/apiVariableService.d.ts +1 -1
  307. package/dist/services/apiVariableService.js +34 -41
  308. package/dist/services/autoSaveService.js +8 -8
  309. package/dist/services/categoriesApi.d.ts +2 -2
  310. package/dist/services/categoriesApi.js +8 -8
  311. package/dist/services/chatService.d.ts +65 -0
  312. package/dist/services/chatService.js +131 -0
  313. package/dist/services/draftStorage.d.ts +1 -1
  314. package/dist/services/draftStorage.js +11 -11
  315. package/dist/services/dynamicSchemaService.d.ts +1 -1
  316. package/dist/services/dynamicSchemaService.js +39 -41
  317. package/dist/services/globalSave.d.ts +2 -2
  318. package/dist/services/globalSave.js +38 -41
  319. package/dist/services/historyService.d.ts +7 -5
  320. package/dist/services/historyService.js +29 -14
  321. package/dist/services/interruptService.d.ts +1 -1
  322. package/dist/services/interruptService.js +29 -35
  323. package/dist/services/nodeExecutionService.d.ts +1 -1
  324. package/dist/services/nodeExecutionService.js +44 -45
  325. package/dist/services/playgroundService.d.ts +1 -1
  326. package/dist/services/playgroundService.js +29 -29
  327. package/dist/services/portConfigApi.d.ts +2 -2
  328. package/dist/services/portConfigApi.js +8 -8
  329. package/dist/services/settingsService.d.ts +2 -2
  330. package/dist/services/settingsService.js +19 -25
  331. package/dist/services/toastService.d.ts +4 -4
  332. package/dist/services/toastService.js +33 -33
  333. package/dist/services/variableService.d.ts +1 -1
  334. package/dist/services/variableService.js +36 -36
  335. package/dist/services/workflowStorage.d.ts +2 -2
  336. package/dist/services/workflowStorage.js +13 -13
  337. package/dist/settings/index.d.ts +7 -7
  338. package/dist/settings/index.js +6 -6
  339. package/dist/skins/default.d.ts +1 -1
  340. package/dist/skins/default.js +1 -1
  341. package/dist/skins/index.d.ts +3 -3
  342. package/dist/skins/index.js +7 -7
  343. package/dist/skins/slate.d.ts +1 -1
  344. package/dist/skins/slate.js +69 -69
  345. package/dist/stores/categoriesStore.svelte.d.ts +1 -1
  346. package/dist/stores/categoriesStore.svelte.js +5 -5
  347. package/dist/stores/editorStateMachine.svelte.d.ts +2 -2
  348. package/dist/stores/editorStateMachine.svelte.js +34 -34
  349. package/dist/stores/historyStore.svelte.d.ts +4 -4
  350. package/dist/stores/historyStore.svelte.js +4 -4
  351. package/dist/stores/interruptStore.svelte.d.ts +3 -3
  352. package/dist/stores/interruptStore.svelte.js +27 -22
  353. package/dist/stores/playgroundStore.svelte.d.ts +3 -3
  354. package/dist/stores/playgroundStore.svelte.js +29 -23
  355. package/dist/stores/portCoordinateStore.svelte.d.ts +6 -2
  356. package/dist/stores/portCoordinateStore.svelte.js +30 -39
  357. package/dist/stores/settingsStore.svelte.d.ts +2 -2
  358. package/dist/stores/settingsStore.svelte.js +57 -62
  359. package/dist/stores/workflowStore.svelte.d.ts +34 -5
  360. package/dist/stores/workflowStore.svelte.js +127 -108
  361. package/dist/stories/CanvasDecorator.svelte +7 -10
  362. package/dist/stories/CanvasDecorator.svelte.d.ts +2 -2
  363. package/dist/stories/EdgeDecorator.svelte +28 -31
  364. package/dist/stories/EdgeDecorator.svelte.d.ts +1 -1
  365. package/dist/stories/NodeDecorator.svelte +14 -20
  366. package/dist/stories/NodeDecorator.svelte.d.ts +1 -1
  367. package/dist/stories/utils.d.ts +2 -2
  368. package/dist/stories/utils.js +89 -93
  369. package/dist/styles/base.css +16 -50
  370. package/dist/styles/tokens.css +10 -28
  371. package/dist/svelte-app.d.ts +10 -10
  372. package/dist/svelte-app.js +39 -39
  373. package/dist/themes/default.d.ts +1 -1
  374. package/dist/themes/default.js +4 -4
  375. package/dist/themes/index.d.ts +3 -3
  376. package/dist/themes/index.js +11 -11
  377. package/dist/themes/minimal.d.ts +1 -1
  378. package/dist/themes/minimal.js +5 -5
  379. package/dist/types/agentspec.d.ts +18 -18
  380. package/dist/types/agentspec.js +2 -2
  381. package/dist/types/auth.d.ts +1 -1
  382. package/dist/types/auth.js +6 -6
  383. package/dist/types/chat.d.ts +63 -0
  384. package/dist/types/chat.js +9 -0
  385. package/dist/types/config.d.ts +6 -6
  386. package/dist/types/events.d.ts +28 -2
  387. package/dist/types/events.js +2 -1
  388. package/dist/types/index.d.ts +40 -32
  389. package/dist/types/index.js +6 -6
  390. package/dist/types/interrupt.d.ts +6 -6
  391. package/dist/types/interrupt.js +21 -21
  392. package/dist/types/interruptState.d.ts +12 -12
  393. package/dist/types/interruptState.js +66 -66
  394. package/dist/types/playground.d.ts +7 -7
  395. package/dist/types/playground.js +14 -14
  396. package/dist/types/settings.d.ts +12 -4
  397. package/dist/types/settings.js +21 -23
  398. package/dist/types/skin.d.ts +1 -1
  399. package/dist/types/theme.d.ts +2 -2
  400. package/dist/types/uischema.d.ts +4 -4
  401. package/dist/types/uischema.js +3 -3
  402. package/dist/utils/colors.d.ts +1 -1
  403. package/dist/utils/colors.js +95 -97
  404. package/dist/utils/config.d.ts +2 -2
  405. package/dist/utils/config.js +48 -48
  406. package/dist/utils/connections.d.ts +2 -2
  407. package/dist/utils/connections.js +15 -15
  408. package/dist/utils/edgeStyling.d.ts +42 -0
  409. package/dist/utils/edgeStyling.js +173 -0
  410. package/dist/utils/errors.js +3 -3
  411. package/dist/utils/fetchWithAuth.d.ts +1 -1
  412. package/dist/utils/fetchWithAuth.js +2 -2
  413. package/dist/utils/handleIds.d.ts +2 -2
  414. package/dist/utils/handleIds.js +8 -8
  415. package/dist/utils/handlePositioning.d.ts +1 -1
  416. package/dist/utils/handlePositioning.js +2 -2
  417. package/dist/utils/icons.d.ts +1 -1
  418. package/dist/utils/icons.js +74 -74
  419. package/dist/utils/logger.d.ts +1 -1
  420. package/dist/utils/logger.js +7 -7
  421. package/dist/utils/nodeIds.d.ts +31 -0
  422. package/dist/utils/nodeIds.js +42 -0
  423. package/dist/utils/nodeStatus.d.ts +1 -1
  424. package/dist/utils/nodeStatus.js +48 -48
  425. package/dist/utils/nodeSwap.d.ts +221 -0
  426. package/dist/utils/nodeSwap.js +680 -0
  427. package/dist/utils/nodeTypes.d.ts +1 -1
  428. package/dist/utils/nodeTypes.js +20 -21
  429. package/dist/utils/nodeWrapper.d.ts +7 -7
  430. package/dist/utils/nodeWrapper.js +19 -21
  431. package/dist/utils/performanceUtils.d.ts +1 -1
  432. package/dist/utils/performanceUtils.js +1 -2
  433. package/dist/utils/portUtils.d.ts +2 -2
  434. package/dist/utils/portUtils.js +1 -1
  435. package/dist/utils/sanitize.js +1 -1
  436. package/dist/utils/uischema.d.ts +2 -2
  437. package/dist/utils/uischema.js +8 -8
  438. package/dist/utils/validation.js +8 -8
  439. package/package.json +12 -11
  440. package/dist/helpers/nodeLayoutHelper.d.ts +0 -14
  441. package/dist/helpers/nodeLayoutHelper.js +0 -19
@@ -0,0 +1,1133 @@
1
+ /**
2
+ * Command Executor
3
+ *
4
+ * Executes parsed Command objects against a CommandContext,
5
+ * dispatching mutations to the workflow store.
6
+ *
7
+ * @module commands/executor
8
+ */
9
+ import { generateNodeId } from '../utils/nodeIds.js';
10
+ import { extractConfigDefaults } from '../utils/nodeIds.js';
11
+ import { computeAutoPosition } from './positioner.js';
12
+ import { buildHandleId, extractPortId } from '../utils/handleIds.js';
13
+ import { applyConnectionStyling } from '../utils/edgeStyling.js';
14
+ import { computeSwapPreview, executeSwap } from '../utils/nodeSwap.js';
15
+ import { computeAutoLayout, computeBeautifyLayout } from '../adapters/agentspec/autoLayout.js';
16
+ // ============================================================================
17
+ // Internal Helpers
18
+ // ============================================================================
19
+ /**
20
+ * Convert an internal namespaced node ID to a DSL short ID.
21
+ * "agentspec.llm_node.1" → "llm_node.1"
22
+ * "llm_node.1" → "llm_node.1" (no namespace, unchanged)
23
+ */
24
+ export function toShortId(internalId) {
25
+ // Node IDs are <namespace>.<typeId>.<number> or <typeId>.<number>
26
+ // The namespace is the first segment if there are 3+ dot-separated parts
27
+ // and the last segment is a number
28
+ const parts = internalId.split('.');
29
+ if (parts.length >= 3) {
30
+ const lastPart = parts[parts.length - 1];
31
+ if (/^\d+$/.test(lastPart)) {
32
+ // Strip the first segment (namespace)
33
+ return parts.slice(1).join('.');
34
+ }
35
+ }
36
+ return internalId;
37
+ }
38
+ /**
39
+ * Convert a namespaced type ID to a short type ID.
40
+ * "agentspec.llm_node" → "llm_node"
41
+ * "llm_node" → "llm_node" (no namespace, unchanged)
42
+ */
43
+ export function toShortTypeId(typeId) {
44
+ const dotIndex = typeId.indexOf('.');
45
+ if (dotIndex !== -1) {
46
+ return typeId.substring(dotIndex + 1);
47
+ }
48
+ return typeId;
49
+ }
50
+ /**
51
+ * Resolve a DSL short ID (e.g. "llm_node.1") to the actual workflow node.
52
+ * Tries direct match first, then looks for a namespaced match.
53
+ */
54
+ export function resolveNode(shortId, nodes) {
55
+ // Direct match
56
+ const direct = nodes.find((n) => n.id === shortId);
57
+ if (direct)
58
+ return direct;
59
+ // Namespaced match: node ID ends with ".<shortId>"
60
+ return nodes.find((n) => n.id.endsWith(`.${shortId}`));
61
+ }
62
+ // ============================================================================
63
+ // Command Handlers
64
+ // ============================================================================
65
+ function executeAddNode(command, context) {
66
+ const workflow = context.getWorkflow();
67
+ if (!workflow) {
68
+ return { ok: false, error: 'No workflow loaded', code: 'NO_WORKFLOW' };
69
+ }
70
+ const metadata = context.typeMap.get(command.nodeTypeId);
71
+ if (!metadata) {
72
+ return {
73
+ ok: false,
74
+ error: `Unknown node type: ${command.nodeTypeId}`,
75
+ code: 'NODE_TYPE_NOT_FOUND'
76
+ };
77
+ }
78
+ const position = command.position ?? computeAutoPosition(workflow.nodes);
79
+ const nodeId = generateNodeId(metadata.id, workflow.nodes);
80
+ const config = extractConfigDefaults(metadata.configSchema);
81
+ const node = {
82
+ id: nodeId,
83
+ type: 'universalNode',
84
+ position,
85
+ deletable: true,
86
+ data: {
87
+ label: metadata.name,
88
+ config,
89
+ metadata,
90
+ nodeId
91
+ }
92
+ };
93
+ context.dispatch.addNode(node);
94
+ const shortId = toShortId(nodeId);
95
+ const resultData = {
96
+ nodeId: shortId,
97
+ type: command.nodeTypeId,
98
+ label: metadata.name,
99
+ position
100
+ };
101
+ return {
102
+ ok: true,
103
+ message: `Added ${metadata.name} as ${shortId}`,
104
+ data: resultData
105
+ };
106
+ }
107
+ function executeDeleteNode(command, context) {
108
+ const workflow = context.getWorkflow();
109
+ if (!workflow) {
110
+ return { ok: false, error: 'No workflow loaded', code: 'NO_WORKFLOW' };
111
+ }
112
+ const node = resolveNode(command.nodeId, workflow.nodes);
113
+ if (!node) {
114
+ return {
115
+ ok: false,
116
+ error: `Node not found: ${command.nodeId}`,
117
+ code: 'NODE_NOT_FOUND'
118
+ };
119
+ }
120
+ context.dispatch.removeNode(node.id);
121
+ return {
122
+ ok: true,
123
+ message: `Deleted node ${toShortId(node.id)}`
124
+ };
125
+ }
126
+ function executeRenameNode(command, context) {
127
+ const workflow = context.getWorkflow();
128
+ if (!workflow) {
129
+ return { ok: false, error: 'No workflow loaded', code: 'NO_WORKFLOW' };
130
+ }
131
+ const node = resolveNode(command.nodeId, workflow.nodes);
132
+ if (!node) {
133
+ return {
134
+ ok: false,
135
+ error: `Node not found: ${command.nodeId}`,
136
+ code: 'NODE_NOT_FOUND'
137
+ };
138
+ }
139
+ context.dispatch.updateNode(node.id, {
140
+ data: { ...node.data, label: command.label }
141
+ });
142
+ return {
143
+ ok: true,
144
+ message: `Renamed ${toShortId(node.id)} to "${command.label}"`
145
+ };
146
+ }
147
+ /**
148
+ * Parse a raw value string into the appropriate JS type.
149
+ * Priority: quoted string (preserved) > JSON > number > boolean > raw string
150
+ */
151
+ function parseConfigValue(raw) {
152
+ // Double-quoted string — JSON-unescape so \n, \t, \\ etc. work
153
+ if (raw.startsWith('"') && raw.endsWith('"')) {
154
+ try {
155
+ return JSON.parse(raw);
156
+ }
157
+ catch {
158
+ return raw.slice(1, -1);
159
+ }
160
+ }
161
+ // Single-quoted string — strip quotes (no escape processing)
162
+ if (raw.startsWith("'") && raw.endsWith("'")) {
163
+ return raw.slice(1, -1);
164
+ }
165
+ // Try JSON (arrays, objects, null)
166
+ if (raw.startsWith('[') || raw.startsWith('{') || raw === 'null') {
167
+ try {
168
+ return JSON.parse(raw);
169
+ }
170
+ catch {
171
+ // fall through
172
+ }
173
+ }
174
+ // Number
175
+ if (raw !== '' && !isNaN(Number(raw))) {
176
+ return Number(raw);
177
+ }
178
+ // Boolean
179
+ if (raw === 'true')
180
+ return true;
181
+ if (raw === 'false')
182
+ return false;
183
+ // Raw string
184
+ return raw;
185
+ }
186
+ /**
187
+ * Validate a parsed config value against a ConfigProperty schema.
188
+ * Returns an array of validation warnings (empty if valid or no schema).
189
+ */
190
+ function validateConfigValue(key, value, property) {
191
+ if (!property)
192
+ return [];
193
+ const warnings = [];
194
+ // Enum validation
195
+ if (property.enum && property.enum.length > 0) {
196
+ if (!property.enum.includes(value)) {
197
+ warnings.push({
198
+ type: 'enum',
199
+ message: `Value ${JSON.stringify(value)} is not in allowed values: ${property.enum.map((v) => JSON.stringify(v)).join(', ')}`,
200
+ allowedValues: property.enum
201
+ });
202
+ }
203
+ }
204
+ // Type validation
205
+ if (property.type) {
206
+ const actualType = Array.isArray(value) ? 'array' : typeof value;
207
+ const expectedType = property.type === 'integer' ? 'number' : property.type;
208
+ // Only warn if there's a genuine mismatch (null/object handled specially)
209
+ if (value !== null &&
210
+ actualType !== expectedType &&
211
+ !(expectedType === 'object' && actualType === 'object')) {
212
+ warnings.push({
213
+ type: 'type_mismatch',
214
+ message: `Expected type '${property.type}' but got '${actualType}'`,
215
+ expectedType: property.type,
216
+ actualType
217
+ });
218
+ }
219
+ }
220
+ return warnings;
221
+ }
222
+ function executeSetConfig(command, context) {
223
+ const workflow = context.getWorkflow();
224
+ if (!workflow) {
225
+ return { ok: false, error: 'No workflow loaded', code: 'NO_WORKFLOW' };
226
+ }
227
+ const node = resolveNode(command.nodeId, workflow.nodes);
228
+ if (!node) {
229
+ return {
230
+ ok: false,
231
+ error: `Node not found: ${command.nodeId}`,
232
+ code: 'NODE_NOT_FOUND'
233
+ };
234
+ }
235
+ const parsedValue = parseConfigValue(command.value);
236
+ // Validate against configSchema if present
237
+ const metadata = node.data.metadata;
238
+ const configSchema = metadata?.configSchema;
239
+ const property = configSchema?.properties?.[command.key];
240
+ const warnings = validateConfigValue(command.key, parsedValue, property);
241
+ // In strict mode, validation warnings become errors
242
+ if (command.strict && warnings && warnings.length > 0) {
243
+ const messages = warnings.map((w) => w.message).join('; ');
244
+ return {
245
+ ok: false,
246
+ error: `Config validation failed for ${toShortId(node.id)}:${command.key}: ${messages}`,
247
+ code: 'CONFIG_VALIDATION_ERROR'
248
+ };
249
+ }
250
+ const updatedConfig = { ...node.data.config, [command.key]: parsedValue };
251
+ context.dispatch.updateNode(node.id, {
252
+ data: { ...node.data, config: updatedConfig }
253
+ });
254
+ const resultData = {
255
+ nodeId: toShortId(node.id),
256
+ key: command.key,
257
+ value: parsedValue,
258
+ ...(warnings && warnings.length > 0 ? { warnings } : {})
259
+ };
260
+ const warningMsg = warnings && warnings.length > 0
261
+ ? ` (warning: ${warnings.map((w) => w.message).join('; ')})`
262
+ : '';
263
+ return {
264
+ ok: true,
265
+ message: `Set ${toShortId(node.id)}:${command.key} = ${JSON.stringify(parsedValue)}${warningMsg}`,
266
+ data: resultData
267
+ };
268
+ }
269
+ function executeGetConfig(command, context) {
270
+ const workflow = context.getWorkflow();
271
+ if (!workflow) {
272
+ return { ok: false, error: 'No workflow loaded', code: 'NO_WORKFLOW' };
273
+ }
274
+ const node = resolveNode(command.nodeId, workflow.nodes);
275
+ if (!node) {
276
+ return {
277
+ ok: false,
278
+ error: `Node not found: ${command.nodeId}`,
279
+ code: 'NODE_NOT_FOUND'
280
+ };
281
+ }
282
+ const config = node.data.config;
283
+ if (!config || !(command.key in config)) {
284
+ return {
285
+ ok: false,
286
+ error: `Config key not found: ${command.key} on ${toShortId(node.id)}`,
287
+ code: 'CONFIG_KEY_NOT_FOUND'
288
+ };
289
+ }
290
+ const resultData = {
291
+ nodeId: toShortId(node.id),
292
+ key: command.key,
293
+ value: config[command.key]
294
+ };
295
+ return {
296
+ ok: true,
297
+ message: `${toShortId(node.id)}:${command.key} = ${JSON.stringify(config[command.key])}`,
298
+ data: resultData
299
+ };
300
+ }
301
+ function executeInfo(command, context) {
302
+ const workflow = context.getWorkflow();
303
+ if (!workflow) {
304
+ return { ok: false, error: 'No workflow loaded', code: 'NO_WORKFLOW' };
305
+ }
306
+ const node = resolveNode(command.nodeId, workflow.nodes);
307
+ if (!node) {
308
+ return {
309
+ ok: false,
310
+ error: `Node not found: ${command.nodeId}`,
311
+ code: 'NODE_NOT_FOUND'
312
+ };
313
+ }
314
+ const metadata = node.data.metadata;
315
+ const shortId = toShortId(node.id);
316
+ const inputs = (metadata?.inputs ?? []).map((p) => ({
317
+ portId: p.id,
318
+ name: p.name,
319
+ dataType: p.dataType
320
+ }));
321
+ const staticOutputs = (metadata?.outputs ?? []).map((p) => ({
322
+ portId: p.id,
323
+ name: p.name,
324
+ dataType: p.dataType
325
+ }));
326
+ // Gateway nodes expose dynamic branch ports from config.branches
327
+ const branchOutputs = metadata?.type === 'gateway'
328
+ ? (node.data.config?.branches ?? []).map((b) => ({
329
+ portId: b.name,
330
+ name: b.name,
331
+ dataType: 'trigger'
332
+ }))
333
+ : [];
334
+ const outputs = [...staticOutputs, ...branchOutputs];
335
+ // Build connected edges info
336
+ const connectedEdges = [];
337
+ for (const edge of workflow.edges) {
338
+ if (edge.source === node.id) {
339
+ connectedEdges.push({
340
+ edgeId: edge.id,
341
+ direction: 'outgoing',
342
+ remoteNodeId: toShortId(edge.target),
343
+ remotePort: extractPortId(edge.targetHandle) ?? '',
344
+ localPort: extractPortId(edge.sourceHandle) ?? ''
345
+ });
346
+ }
347
+ else if (edge.target === node.id) {
348
+ connectedEdges.push({
349
+ edgeId: edge.id,
350
+ direction: 'incoming',
351
+ remoteNodeId: toShortId(edge.source),
352
+ remotePort: extractPortId(edge.sourceHandle) ?? '',
353
+ localPort: extractPortId(edge.targetHandle) ?? ''
354
+ });
355
+ }
356
+ }
357
+ const resultData = {
358
+ nodeId: shortId,
359
+ label: node.data.label ?? metadata?.name ?? '',
360
+ type: metadata?.id ? toShortTypeId(metadata.id) : '',
361
+ position: node.position,
362
+ config: node.data.config ?? {},
363
+ inputs,
364
+ outputs,
365
+ connectedEdges
366
+ };
367
+ return {
368
+ ok: true,
369
+ message: `Info for ${shortId}`,
370
+ data: resultData
371
+ };
372
+ }
373
+ // ============================================================================
374
+ // Connection Operations
375
+ // ============================================================================
376
+ /**
377
+ * Find a port in a node's metadata by port ID, checking both inputs and outputs.
378
+ * Returns the port and its direction.
379
+ */
380
+ function findPort(node, portId, preferDirection) {
381
+ const metadata = node.data?.metadata;
382
+ if (!metadata)
383
+ return null;
384
+ const outputPort = metadata.outputs?.find((p) => p.id === portId);
385
+ const inputPort = metadata.inputs?.find((p) => p.id === portId);
386
+ if (preferDirection === 'output') {
387
+ if (outputPort)
388
+ return { port: outputPort, direction: 'output' };
389
+ if (inputPort)
390
+ return { port: inputPort, direction: 'input' };
391
+ }
392
+ else if (preferDirection === 'input') {
393
+ if (inputPort)
394
+ return { port: inputPort, direction: 'input' };
395
+ if (outputPort)
396
+ return { port: outputPort, direction: 'output' };
397
+ }
398
+ else {
399
+ if (outputPort)
400
+ return { port: outputPort, direction: 'output' };
401
+ if (inputPort)
402
+ return { port: inputPort, direction: 'input' };
403
+ }
404
+ // Gateway nodes have dynamic branch ports stored in config.branches, not metadata.outputs
405
+ if (metadata.type === 'gateway') {
406
+ const branches = node.data.config?.branches;
407
+ if (branches?.some((b) => b.name === portId)) {
408
+ return {
409
+ port: { id: portId, name: portId, dataType: 'trigger' },
410
+ direction: 'output'
411
+ };
412
+ }
413
+ }
414
+ return null;
415
+ }
416
+ function executeConnect(command, context) {
417
+ const workflow = context.getWorkflow();
418
+ if (!workflow) {
419
+ return { ok: false, error: 'No workflow loaded', code: 'NO_WORKFLOW' };
420
+ }
421
+ // Resolve both nodes
422
+ const sourceNode = resolveNode(command.sourceNodeId, workflow.nodes);
423
+ if (!sourceNode) {
424
+ return {
425
+ ok: false,
426
+ error: `Node not found: ${command.sourceNodeId}`,
427
+ code: 'NODE_NOT_FOUND'
428
+ };
429
+ }
430
+ const targetNode = resolveNode(command.targetNodeId, workflow.nodes);
431
+ if (!targetNode) {
432
+ return {
433
+ ok: false,
434
+ error: `Node not found: ${command.targetNodeId}`,
435
+ code: 'NODE_NOT_FOUND'
436
+ };
437
+ }
438
+ // Look up ports in metadata to determine direction.
439
+ // Since connections always flow output → input, prefer the output port on the
440
+ // source node and the input port on the target node when the same port name
441
+ // exists in both directions on a node.
442
+ const sourcePortInfo = findPort(sourceNode, command.sourcePort, 'output');
443
+ if (!sourcePortInfo) {
444
+ return {
445
+ ok: false,
446
+ error: `Port '${command.sourcePort}' not found on node ${toShortId(sourceNode.id)}`,
447
+ code: 'PORT_NOT_FOUND'
448
+ };
449
+ }
450
+ const targetPortInfo = findPort(targetNode, command.targetPort, 'input');
451
+ if (!targetPortInfo) {
452
+ return {
453
+ ok: false,
454
+ error: `Port '${command.targetPort}' not found on node ${toShortId(targetNode.id)}`,
455
+ code: 'PORT_NOT_FOUND'
456
+ };
457
+ }
458
+ // Validate directions: source port must be output, target port must be input
459
+ if (sourcePortInfo.direction !== 'output' || targetPortInfo.direction !== 'input') {
460
+ // Check if they're reversed
461
+ if (sourcePortInfo.direction === 'input' && targetPortInfo.direction === 'output') {
462
+ return {
463
+ ok: false,
464
+ error: `Connection direction reversed: '${command.sourcePort}' is an input on ${toShortId(sourceNode.id)} and '${command.targetPort}' is an output on ${toShortId(targetNode.id)}. Swap source and target.`,
465
+ code: 'INVALID_CONNECTION'
466
+ };
467
+ }
468
+ // One of them is the wrong direction
469
+ if (sourcePortInfo.direction !== 'output') {
470
+ return {
471
+ ok: false,
472
+ error: `Port '${command.sourcePort}' on ${toShortId(sourceNode.id)} is an input, not an output (per node metadata)`,
473
+ code: 'INVALID_CONNECTION'
474
+ };
475
+ }
476
+ return {
477
+ ok: false,
478
+ error: `Port '${command.targetPort}' on ${toShortId(targetNode.id)} is an output, not an input (per node metadata)`,
479
+ code: 'INVALID_CONNECTION'
480
+ };
481
+ }
482
+ // Build handle IDs
483
+ const sourceHandle = buildHandleId(sourceNode.id, 'output', command.sourcePort);
484
+ const targetHandle = buildHandleId(targetNode.id, 'input', command.targetPort);
485
+ // Generate edge ID
486
+ const edgeId = `${sourceNode.id}-${sourceHandle}-${targetNode.id}-${targetHandle}`;
487
+ // Build edge
488
+ const edge = {
489
+ id: edgeId,
490
+ source: sourceNode.id,
491
+ target: targetNode.id,
492
+ sourceHandle,
493
+ targetHandle
494
+ };
495
+ // Apply styling
496
+ applyConnectionStyling(edge, sourceNode, targetNode);
497
+ // Dispatch
498
+ context.dispatch.addEdge(edge);
499
+ return {
500
+ ok: true,
501
+ message: `Connected ${toShortId(sourceNode.id)}:${command.sourcePort} → ${toShortId(targetNode.id)}:${command.targetPort}`
502
+ };
503
+ }
504
+ function executeDisconnectPorts(command, context) {
505
+ const workflow = context.getWorkflow();
506
+ if (!workflow) {
507
+ return { ok: false, error: 'No workflow loaded', code: 'NO_WORKFLOW' };
508
+ }
509
+ // Resolve both nodes
510
+ const sourceNode = resolveNode(command.sourceNodeId, workflow.nodes);
511
+ if (!sourceNode) {
512
+ return {
513
+ ok: false,
514
+ error: `Node not found: ${command.sourceNodeId}`,
515
+ code: 'NODE_NOT_FOUND'
516
+ };
517
+ }
518
+ const targetNode = resolveNode(command.targetNodeId, workflow.nodes);
519
+ if (!targetNode) {
520
+ return {
521
+ ok: false,
522
+ error: `Node not found: ${command.targetNodeId}`,
523
+ code: 'NODE_NOT_FOUND'
524
+ };
525
+ }
526
+ // Find the matching edge by checking source/target node IDs and port IDs
527
+ const edge = workflow.edges.find((e) => {
528
+ if (e.source !== sourceNode.id || e.target !== targetNode.id)
529
+ return false;
530
+ const sourcePort = extractPortId(e.sourceHandle);
531
+ const targetPort = extractPortId(e.targetHandle);
532
+ return sourcePort === command.sourcePort && targetPort === command.targetPort;
533
+ });
534
+ if (!edge) {
535
+ return {
536
+ ok: false,
537
+ error: `No edge found from ${toShortId(sourceNode.id)}:${command.sourcePort} to ${toShortId(targetNode.id)}:${command.targetPort}`,
538
+ code: 'EDGE_NOT_FOUND'
539
+ };
540
+ }
541
+ context.dispatch.removeEdge(edge.id);
542
+ return {
543
+ ok: true,
544
+ message: `Disconnected ${toShortId(sourceNode.id)}:${command.sourcePort} from ${toShortId(targetNode.id)}:${command.targetPort}`
545
+ };
546
+ }
547
+ function executeDisconnectNode(command, context) {
548
+ const workflow = context.getWorkflow();
549
+ if (!workflow) {
550
+ return { ok: false, error: 'No workflow loaded', code: 'NO_WORKFLOW' };
551
+ }
552
+ const node = resolveNode(command.nodeId, workflow.nodes);
553
+ if (!node) {
554
+ return {
555
+ ok: false,
556
+ error: `Node not found: ${command.nodeId}`,
557
+ code: 'NODE_NOT_FOUND'
558
+ };
559
+ }
560
+ // Find all edges connected to this node
561
+ const connectedEdges = workflow.edges.filter((e) => e.source === node.id || e.target === node.id);
562
+ for (const edge of connectedEdges) {
563
+ context.dispatch.removeEdge(edge.id);
564
+ }
565
+ return {
566
+ ok: true,
567
+ message: `Disconnected ${connectedEdges.length} edge(s) from ${toShortId(node.id)}`
568
+ };
569
+ }
570
+ // ============================================================================
571
+ // List & Help Operations
572
+ // ============================================================================
573
+ function executeListNodes(context) {
574
+ const workflow = context.getWorkflow();
575
+ if (!workflow) {
576
+ return { ok: false, error: 'No workflow loaded', code: 'NO_WORKFLOW' };
577
+ }
578
+ const nodes = workflow.nodes.map((n) => ({
579
+ nodeId: toShortId(n.id),
580
+ label: n.data.label ?? n.data.metadata?.name ?? '',
581
+ type: n.data.metadata?.id ? toShortTypeId(n.data.metadata.id) : ''
582
+ }));
583
+ const resultData = { nodes };
584
+ return {
585
+ ok: true,
586
+ message: nodes.length === 0
587
+ ? 'No nodes in workflow'
588
+ : `${nodes.length} node(s): ${nodes.map((n) => n.nodeId).join(', ')}`,
589
+ data: resultData
590
+ };
591
+ }
592
+ function executeListEdges(context) {
593
+ const workflow = context.getWorkflow();
594
+ if (!workflow) {
595
+ return { ok: false, error: 'No workflow loaded', code: 'NO_WORKFLOW' };
596
+ }
597
+ const edges = workflow.edges.map((e) => ({
598
+ edgeId: e.id,
599
+ sourceNodeId: toShortId(e.source),
600
+ sourcePort: extractPortId(e.sourceHandle) ?? '',
601
+ targetNodeId: toShortId(e.target),
602
+ targetPort: extractPortId(e.targetHandle) ?? ''
603
+ }));
604
+ const resultData = { edges };
605
+ return {
606
+ ok: true,
607
+ message: edges.length === 0 ? 'No edges in workflow' : `${edges.length} edge(s)`,
608
+ data: resultData
609
+ };
610
+ }
611
+ function executeListTypes(context) {
612
+ const types = context.nodeTypes.map((m) => ({
613
+ typeId: toShortTypeId(m.id),
614
+ name: m.name,
615
+ category: m.category
616
+ }));
617
+ const resultData = { types };
618
+ return {
619
+ ok: true,
620
+ message: `${types.length} type(s) available`,
621
+ data: resultData
622
+ };
623
+ }
624
+ /** All command help entries */
625
+ export const COMMAND_HELP = [
626
+ {
627
+ name: 'add',
628
+ syntax: 'add <type> [at <x>,<y>]',
629
+ description: 'Add a new node of the specified type'
630
+ },
631
+ {
632
+ name: 'delete',
633
+ syntax: 'delete <nodeId>',
634
+ description: 'Delete a node and its connections'
635
+ },
636
+ {
637
+ name: 'rename',
638
+ syntax: 'rename <nodeId> <label>',
639
+ description: "Rename a node's display label"
640
+ },
641
+ {
642
+ name: 'set',
643
+ syntax: 'set <nodeId>:<key> <value>',
644
+ description: 'Set a config value on a node'
645
+ },
646
+ {
647
+ name: 'get',
648
+ syntax: 'get <nodeId>:<key>',
649
+ description: 'Get a config value from a node'
650
+ },
651
+ {
652
+ name: 'connect',
653
+ syntax: 'connect <nid>:<port> to <nid>:<port>',
654
+ description: 'Connect two node ports'
655
+ },
656
+ {
657
+ name: 'disconnect',
658
+ syntax: 'disconnect <nid>:<port> from <nid>:<port>',
659
+ description: 'Disconnect two node ports'
660
+ },
661
+ {
662
+ name: 'disconnect',
663
+ syntax: 'disconnect <nodeId>',
664
+ description: 'Disconnect all edges from a node'
665
+ },
666
+ {
667
+ name: 'list',
668
+ syntax: 'list nodes|edges|types',
669
+ description: 'List workflow nodes, edges, or available types'
670
+ },
671
+ {
672
+ name: 'info',
673
+ syntax: 'info <nodeId>',
674
+ description: 'Show detailed info about a node'
675
+ },
676
+ {
677
+ name: 'config',
678
+ syntax: 'config <nodeId>',
679
+ description: 'Open the config panel for a node'
680
+ },
681
+ {
682
+ name: 'select',
683
+ syntax: 'select <nodeId>',
684
+ description: 'Select a node on the canvas'
685
+ },
686
+ {
687
+ name: 'swap',
688
+ syntax: 'swap <nodeId> with <type>',
689
+ description: "Replace a node's type, preserving connections"
690
+ },
691
+ {
692
+ name: 'move',
693
+ syntax: 'move <nodeId> to <x>,<y>',
694
+ description: 'Move a node to a position'
695
+ },
696
+ {
697
+ name: 'layout',
698
+ syntax: 'layout auto [--direction horizontal|vertical]',
699
+ description: 'Auto-arrange all nodes'
700
+ },
701
+ {
702
+ name: 'layout',
703
+ syntax: 'layout beautify',
704
+ description: 'Normalize spacing while preserving node arrangement'
705
+ },
706
+ { name: 'undo', syntax: 'undo', description: 'Undo the last action' },
707
+ { name: 'redo', syntax: 'redo', description: 'Redo the last undone action' },
708
+ {
709
+ name: 'help',
710
+ syntax: 'help [<command>]',
711
+ description: 'Show help for all or a specific command'
712
+ },
713
+ { name: 'clear', syntax: 'clear', description: 'Remove all nodes and edges' },
714
+ {
715
+ name: 'canvas',
716
+ syntax: 'canvas fitview',
717
+ description: 'Fit all nodes into the viewport'
718
+ },
719
+ {
720
+ name: 'canvas',
721
+ syntax: 'canvas zoom in',
722
+ description: 'Zoom in on the canvas'
723
+ },
724
+ {
725
+ name: 'canvas',
726
+ syntax: 'canvas zoom out',
727
+ description: 'Zoom out on the canvas'
728
+ },
729
+ {
730
+ name: 'canvas',
731
+ syntax: 'canvas zoom <level>',
732
+ description: 'Set zoom to a specific level (e.g. 1.5)'
733
+ },
734
+ {
735
+ name: 'canvas',
736
+ syntax: 'canvas pan <x>,<y>',
737
+ description: 'Pan the canvas to center on a position'
738
+ },
739
+ {
740
+ name: 'canvas',
741
+ syntax: 'canvas reset',
742
+ description: 'Reset viewport to default position and zoom'
743
+ }
744
+ ];
745
+ function executeHelp(command) {
746
+ let commands;
747
+ if (command.command) {
748
+ commands = COMMAND_HELP.filter((h) => h.name === command.command);
749
+ if (commands.length === 0) {
750
+ commands = COMMAND_HELP; // Unknown command name — show all
751
+ }
752
+ }
753
+ else {
754
+ commands = COMMAND_HELP;
755
+ }
756
+ const resultData = { commands };
757
+ const message = commands.map((c) => ` ${c.syntax} — ${c.description}`).join('\n');
758
+ return {
759
+ ok: true,
760
+ message: command.command
761
+ ? `Help for '${command.command}':\n${message}`
762
+ : `Available commands:\n${message}`,
763
+ data: resultData
764
+ };
765
+ }
766
+ // ============================================================================
767
+ // Undo, Redo, Clear, Config, Select
768
+ // ============================================================================
769
+ function executeUndo(context) {
770
+ const success = context.dispatch.undo();
771
+ if (!success) {
772
+ return {
773
+ ok: false,
774
+ error: 'Nothing to undo',
775
+ code: 'UNDO_UNAVAILABLE'
776
+ };
777
+ }
778
+ return { ok: true, message: 'Undone' };
779
+ }
780
+ function executeRedo(context) {
781
+ const success = context.dispatch.redo();
782
+ if (!success) {
783
+ return {
784
+ ok: false,
785
+ error: 'Nothing to redo',
786
+ code: 'REDO_UNAVAILABLE'
787
+ };
788
+ }
789
+ return { ok: true, message: 'Redone' };
790
+ }
791
+ function executeClear(context) {
792
+ const workflow = context.getWorkflow();
793
+ if (!workflow) {
794
+ return { ok: false, error: 'No workflow loaded', code: 'NO_WORKFLOW' };
795
+ }
796
+ const nodeCount = workflow.nodes.length;
797
+ const edgeCount = workflow.edges.length;
798
+ context.dispatch.batchUpdate({ nodes: [], edges: [] });
799
+ return {
800
+ ok: true,
801
+ message: `Cleared ${nodeCount} node(s) and ${edgeCount} edge(s)`
802
+ };
803
+ }
804
+ function executeConfigOpen(command, context) {
805
+ const workflow = context.getWorkflow();
806
+ if (!workflow) {
807
+ return { ok: false, error: 'No workflow loaded', code: 'NO_WORKFLOW' };
808
+ }
809
+ const node = resolveNode(command.nodeId, workflow.nodes);
810
+ if (!node) {
811
+ return {
812
+ ok: false,
813
+ error: `Node not found: ${command.nodeId}`,
814
+ code: 'NODE_NOT_FOUND'
815
+ };
816
+ }
817
+ if (context.dispatch.emitUIAction) {
818
+ context.dispatch.emitUIAction({ type: 'open_config', nodeId: node.id });
819
+ return {
820
+ ok: true,
821
+ message: `Opened config for ${toShortId(node.id)}`
822
+ };
823
+ }
824
+ return {
825
+ ok: true,
826
+ message: `Config open requested for ${toShortId(node.id)} (no UI handler)`,
827
+ uiActionPending: true
828
+ };
829
+ }
830
+ function executeSelectNode(command, context) {
831
+ const workflow = context.getWorkflow();
832
+ if (!workflow) {
833
+ return { ok: false, error: 'No workflow loaded', code: 'NO_WORKFLOW' };
834
+ }
835
+ const node = resolveNode(command.nodeId, workflow.nodes);
836
+ if (!node) {
837
+ return {
838
+ ok: false,
839
+ error: `Node not found: ${command.nodeId}`,
840
+ code: 'NODE_NOT_FOUND'
841
+ };
842
+ }
843
+ if (context.dispatch.emitUIAction) {
844
+ context.dispatch.emitUIAction({ type: 'select_node', nodeId: node.id });
845
+ return {
846
+ ok: true,
847
+ message: `Selected ${toShortId(node.id)}`
848
+ };
849
+ }
850
+ return {
851
+ ok: true,
852
+ message: `Select requested for ${toShortId(node.id)} (no UI handler)`,
853
+ uiActionPending: true
854
+ };
855
+ }
856
+ function executeSwapNode(command, context) {
857
+ const workflow = context.getWorkflow();
858
+ if (!workflow) {
859
+ return { ok: false, error: 'No workflow loaded', code: 'NO_WORKFLOW' };
860
+ }
861
+ const node = resolveNode(command.nodeId, workflow.nodes);
862
+ if (!node) {
863
+ return {
864
+ ok: false,
865
+ error: `Node not found: ${command.nodeId}`,
866
+ code: 'NODE_NOT_FOUND'
867
+ };
868
+ }
869
+ const newMetadata = context.typeMap.get(command.newTypeId);
870
+ if (!newMetadata) {
871
+ return {
872
+ ok: false,
873
+ error: `Unknown node type: ${command.newTypeId}`,
874
+ code: 'NODE_TYPE_NOT_FOUND'
875
+ };
876
+ }
877
+ const preview = computeSwapPreview(node, newMetadata, workflow.edges, workflow.nodes);
878
+ const swapResult = executeSwap(node, newMetadata, preview, workflow.nodes, workflow.edges);
879
+ if (context.dispatch.swapNode) {
880
+ context.dispatch.swapNode({
881
+ nodes: swapResult.updatedNodes,
882
+ edges: swapResult.updatedEdges
883
+ });
884
+ }
885
+ else {
886
+ context.dispatch.batchUpdate({
887
+ nodes: swapResult.updatedNodes,
888
+ edges: swapResult.updatedEdges
889
+ });
890
+ }
891
+ const resultData = {
892
+ oldNodeId: toShortId(node.id),
893
+ newNodeId: toShortId(preview.newNodeId),
894
+ newType: command.newTypeId,
895
+ keptEdges: preview.keptEdges.length,
896
+ droppedEdges: preview.droppedEdges.length,
897
+ hasDataLoss: preview.hasDataLoss,
898
+ configCarriedOver: preview.configCarriedOver,
899
+ configReset: preview.configReset
900
+ };
901
+ const droppedMsg = preview.droppedEdges.length > 0 ? ` (${preview.droppedEdges.length} edge(s) dropped)` : '';
902
+ return {
903
+ ok: true,
904
+ message: `Swapped ${toShortId(node.id)} → ${toShortId(preview.newNodeId)} (${command.newTypeId})${droppedMsg}`,
905
+ data: resultData
906
+ };
907
+ }
908
+ function executeMoveNode(command, context) {
909
+ const workflow = context.getWorkflow();
910
+ if (!workflow) {
911
+ return { ok: false, error: 'No workflow loaded', code: 'NO_WORKFLOW' };
912
+ }
913
+ const node = resolveNode(command.nodeId, workflow.nodes);
914
+ if (!node) {
915
+ return {
916
+ ok: false,
917
+ error: `Node not found: ${command.nodeId}`,
918
+ code: 'NODE_NOT_FOUND'
919
+ };
920
+ }
921
+ context.dispatch.updateNode(node.id, {
922
+ position: command.position
923
+ });
924
+ return {
925
+ ok: true,
926
+ message: `Moved ${toShortId(node.id)} to (${command.position.x}, ${command.position.y})`
927
+ };
928
+ }
929
+ function executeAutoLayout(command, context) {
930
+ const workflow = context.getWorkflow();
931
+ if (!workflow) {
932
+ return { ok: false, error: 'No workflow loaded', code: 'NO_WORKFLOW' };
933
+ }
934
+ if (workflow.nodes.length === 0) {
935
+ return { ok: true, message: 'No nodes to layout' };
936
+ }
937
+ const isVertical = command.direction === 'vertical';
938
+ // Filter out loopback edges (loop_back port) — they go backwards and
939
+ // would reverse the layout direction if included.
940
+ const layoutEdges = workflow.edges.filter((e) => !(e.targetHandle ?? '').includes('-input-loop_back'));
941
+ // Determine start node via in-degree: a node with no incoming edges
942
+ // (from non-loopback edges) is a root. Fall back to leftmost position.
943
+ const inDegree = new Map();
944
+ for (const n of workflow.nodes)
945
+ inDegree.set(n.id, 0);
946
+ for (const e of layoutEdges) {
947
+ inDegree.set(e.target, (inDegree.get(e.target) ?? 0) + 1);
948
+ }
949
+ const startNode = workflow.nodes.find((n) => (inDegree.get(n.id) ?? 0) === 0)?.id ??
950
+ workflow.nodes.reduce((leftmost, n) => (n.position.x < leftmost.position.x ? n : leftmost)).id;
951
+ const flow = {
952
+ component_type: 'flow',
953
+ name: 'layout',
954
+ start_node: startNode,
955
+ nodes: workflow.nodes.map((n) => ({
956
+ component_type: 'start_node',
957
+ name: n.id
958
+ })),
959
+ control_flow_connections: layoutEdges.map((e) => ({
960
+ name: e.id,
961
+ from_node: e.source,
962
+ to_node: e.target
963
+ }))
964
+ };
965
+ // Collect measured node dimensions when available
966
+ const nodeDimensions = new Map();
967
+ for (const n of workflow.nodes) {
968
+ const w = n.measured?.width ?? n.width;
969
+ const h = n.measured?.height ?? n.height;
970
+ if (w != null && h != null) {
971
+ nodeDimensions.set(n.id, { width: w, height: h });
972
+ }
973
+ }
974
+ const positions = computeAutoLayout(flow, {}, nodeDimensions.size > 0 ? nodeDimensions : undefined);
975
+ // Apply positions — swap x/y for vertical layout
976
+ const updatedNodes = workflow.nodes.map((n) => {
977
+ const pos = positions.get(n.id);
978
+ if (!pos)
979
+ return n;
980
+ return {
981
+ ...n,
982
+ position: isVertical ? { x: pos.y, y: pos.x } : pos
983
+ };
984
+ });
985
+ context.dispatch.batchUpdate({ nodes: updatedNodes });
986
+ const direction = command.direction ?? 'horizontal';
987
+ return {
988
+ ok: true,
989
+ message: `Auto-layout applied to ${workflow.nodes.length} nodes (${direction})`
990
+ };
991
+ }
992
+ function executeBeautifyLayout(_command, context) {
993
+ const workflow = context.getWorkflow();
994
+ if (!workflow) {
995
+ return { ok: false, error: 'No workflow loaded', code: 'NO_WORKFLOW' };
996
+ }
997
+ if (workflow.nodes.length === 0) {
998
+ return { ok: true, message: 'No nodes to beautify' };
999
+ }
1000
+ // Collect current positions
1001
+ const currentPositions = new Map();
1002
+ for (const n of workflow.nodes) {
1003
+ currentPositions.set(n.id, { x: n.position.x, y: n.position.y });
1004
+ }
1005
+ // Collect measured node dimensions when available
1006
+ const nodeDimensions = new Map();
1007
+ for (const n of workflow.nodes) {
1008
+ const w = n.measured?.width ?? n.width;
1009
+ const h = n.measured?.height ?? n.height;
1010
+ if (w != null && h != null) {
1011
+ nodeDimensions.set(n.id, { width: w, height: h });
1012
+ }
1013
+ }
1014
+ const positions = computeBeautifyLayout(currentPositions, {}, nodeDimensions.size > 0 ? nodeDimensions : undefined);
1015
+ // Apply positions
1016
+ const updatedNodes = workflow.nodes.map((n) => {
1017
+ const pos = positions.get(n.id);
1018
+ if (!pos)
1019
+ return n;
1020
+ return { ...n, position: pos };
1021
+ });
1022
+ context.dispatch.batchUpdate({ nodes: updatedNodes });
1023
+ return {
1024
+ ok: true,
1025
+ message: `Beautified layout for ${workflow.nodes.length} nodes`
1026
+ };
1027
+ }
1028
+ // ============================================================================
1029
+ // Canvas Viewport Commands
1030
+ // ============================================================================
1031
+ function emitCanvasAction(context, action, successMessage) {
1032
+ if (context.dispatch.emitUIAction) {
1033
+ context.dispatch.emitUIAction(action);
1034
+ return { ok: true, message: successMessage };
1035
+ }
1036
+ return {
1037
+ ok: true,
1038
+ message: `${successMessage} (no UI handler)`,
1039
+ uiActionPending: true
1040
+ };
1041
+ }
1042
+ function executeCanvasFitView(context) {
1043
+ return emitCanvasAction(context, { type: 'canvas_fit_view' }, 'Fit view applied');
1044
+ }
1045
+ function executeCanvasZoomIn(context) {
1046
+ return emitCanvasAction(context, { type: 'canvas_zoom_in' }, 'Zoomed in');
1047
+ }
1048
+ function executeCanvasZoomOut(context) {
1049
+ return emitCanvasAction(context, { type: 'canvas_zoom_out' }, 'Zoomed out');
1050
+ }
1051
+ function executeCanvasZoomTo(command, context) {
1052
+ return emitCanvasAction(context, { type: 'canvas_zoom_to', level: command.level }, `Zoom set to ${command.level}`);
1053
+ }
1054
+ function executeCanvasPanTo(command, context) {
1055
+ return emitCanvasAction(context, { type: 'canvas_pan_to', position: command.position }, `Panned to (${command.position.x}, ${command.position.y})`);
1056
+ }
1057
+ function executeCanvasResetView(context) {
1058
+ return emitCanvasAction(context, { type: 'canvas_reset_view' }, 'Viewport reset');
1059
+ }
1060
+ // ============================================================================
1061
+ // Public API
1062
+ // ============================================================================
1063
+ /**
1064
+ * Execute a parsed command against a workflow context.
1065
+ */
1066
+ export function executeCommand(command, context) {
1067
+ switch (command.type) {
1068
+ case 'add_node':
1069
+ return executeAddNode(command, context);
1070
+ case 'delete_node':
1071
+ return executeDeleteNode(command, context);
1072
+ case 'rename_node':
1073
+ return executeRenameNode(command, context);
1074
+ case 'set_config':
1075
+ return executeSetConfig(command, context);
1076
+ case 'get_config':
1077
+ return executeGetConfig(command, context);
1078
+ case 'info':
1079
+ return executeInfo(command, context);
1080
+ case 'connect':
1081
+ return executeConnect(command, context);
1082
+ case 'disconnect_ports':
1083
+ return executeDisconnectPorts(command, context);
1084
+ case 'disconnect_node':
1085
+ return executeDisconnectNode(command, context);
1086
+ case 'list_nodes':
1087
+ return executeListNodes(context);
1088
+ case 'list_edges':
1089
+ return executeListEdges(context);
1090
+ case 'list_types':
1091
+ return executeListTypes(context);
1092
+ case 'help':
1093
+ return executeHelp(command);
1094
+ case 'undo':
1095
+ return executeUndo(context);
1096
+ case 'redo':
1097
+ return executeRedo(context);
1098
+ case 'clear':
1099
+ return executeClear(context);
1100
+ case 'config_open':
1101
+ return executeConfigOpen(command, context);
1102
+ case 'select_node':
1103
+ return executeSelectNode(command, context);
1104
+ case 'swap_node':
1105
+ return executeSwapNode(command, context);
1106
+ case 'move_node':
1107
+ return executeMoveNode(command, context);
1108
+ case 'auto_layout':
1109
+ return executeAutoLayout(command, context);
1110
+ case 'beautify_layout':
1111
+ return executeBeautifyLayout(command, context);
1112
+ case 'canvas_fit_view':
1113
+ return executeCanvasFitView(context);
1114
+ case 'canvas_zoom_in':
1115
+ return executeCanvasZoomIn(context);
1116
+ case 'canvas_zoom_out':
1117
+ return executeCanvasZoomOut(context);
1118
+ case 'canvas_zoom_to':
1119
+ return executeCanvasZoomTo(command, context);
1120
+ case 'canvas_pan_to':
1121
+ return executeCanvasPanTo(command, context);
1122
+ case 'canvas_reset_view':
1123
+ return executeCanvasResetView(context);
1124
+ default: {
1125
+ const _exhaustive = command;
1126
+ return {
1127
+ ok: false,
1128
+ error: `Command not yet implemented: ${_exhaustive.type}`,
1129
+ code: 'UNKNOWN_COMMAND'
1130
+ };
1131
+ }
1132
+ }
1133
+ }