@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,680 @@
1
+ /**
2
+ * Node Swap utilities for FlowDrop
3
+ *
4
+ * Provides logic for swapping a workflow node with a different node type
5
+ * while intelligently remapping compatible port connections.
6
+ *
7
+ * @module utils/nodeSwap
8
+ */
9
+ import { buildHandleId, extractPortId, extractDirection } from './handleIds.js';
10
+ import { generateNodeId } from './nodeIds.js';
11
+ /** Error class for swap validation failures. */
12
+ export class SwapValidationError extends Error {
13
+ constructor(message) {
14
+ super(message);
15
+ this.name = 'SwapValidationError';
16
+ }
17
+ }
18
+ // =========================================================================
19
+ // Dynamic port keys that should never be carried over
20
+ // =========================================================================
21
+ const DYNAMIC_PORT_KEYS = new Set(['dynamicInputs', 'dynamicOutputs', 'branches']);
22
+ // =========================================================================
23
+ // Semver comparison
24
+ // =========================================================================
25
+ /**
26
+ * Compare two semver-like version strings.
27
+ * Returns positive if a > b, negative if a < b, 0 if equal.
28
+ *
29
+ * Handles pre-release tags: "2.0.0-beta" < "2.0.0"
30
+ */
31
+ export function compareSemver(a, b) {
32
+ // Split off pre-release tag
33
+ const [aCore, aPre] = a.split('-', 2);
34
+ const [bCore, bPre] = b.split('-', 2);
35
+ const aParts = aCore.split('.').map(Number);
36
+ const bParts = bCore.split('.').map(Number);
37
+ const maxLen = Math.max(aParts.length, bParts.length);
38
+ for (let i = 0; i < maxLen; i++) {
39
+ const av = aParts[i] ?? 0;
40
+ const bv = bParts[i] ?? 0;
41
+ if (av !== bv)
42
+ return av - bv;
43
+ }
44
+ // Core versions are equal — pre-release < release
45
+ if (aPre && !bPre)
46
+ return -1;
47
+ if (!aPre && bPre)
48
+ return 1;
49
+ // Both have pre-release or neither — compare lexicographically
50
+ if (aPre && bPre)
51
+ return aPre.localeCompare(bPre);
52
+ return 0;
53
+ }
54
+ // =========================================================================
55
+ // Config mapping
56
+ // =========================================================================
57
+ /**
58
+ * Map config values from an old node to a new node's schema.
59
+ *
60
+ * - Keys present in both old config and new schema: carry over the old value
61
+ * - Keys only in the new schema: use the schema default or newDefaults
62
+ * - Keys only in the old config: discarded
63
+ * - Dynamic port keys (dynamicInputs, dynamicOutputs, branches): never carried over
64
+ */
65
+ export function mapConfig(oldConfig, newConfigSchema, newDefaults = {}) {
66
+ if (!newConfigSchema?.properties) {
67
+ return { config: {}, carriedOver: [], reset: [] };
68
+ }
69
+ const config = {};
70
+ const carriedOver = [];
71
+ const reset = [];
72
+ for (const key of Object.keys(newConfigSchema.properties)) {
73
+ if (DYNAMIC_PORT_KEYS.has(key))
74
+ continue;
75
+ const schemaProp = newConfigSchema.properties[key];
76
+ const schemaDefault = schemaProp?.default;
77
+ const providedDefault = newDefaults[key];
78
+ if (key in oldConfig) {
79
+ config[key] = oldConfig[key];
80
+ carriedOver.push(key);
81
+ }
82
+ else {
83
+ config[key] = providedDefault !== undefined ? providedDefault : schemaDefault;
84
+ reset.push(key);
85
+ }
86
+ }
87
+ return { config, carriedOver, reset };
88
+ }
89
+ // =========================================================================
90
+ // Port matching
91
+ // =========================================================================
92
+ /**
93
+ * Find the best matching port on the new node for a given old port.
94
+ *
95
+ * Three-pass strategy:
96
+ * 1. Exact port ID match with compatible dataType
97
+ * 2. Port name match (case-insensitive) with compatible dataType
98
+ * 3. First available port with compatible dataType
99
+ */
100
+ function findMatchingPort(oldPort, newPorts, usedPortIds, checker) {
101
+ const available = newPorts.filter((p) => p.type === oldPort.type && !usedPortIds.has(p.id));
102
+ const isCompatible = (a, b) => {
103
+ if (!checker)
104
+ return a.dataType === b.dataType;
105
+ // Check both directions since the port role (input vs output) matters
106
+ if (oldPort.type === 'input') {
107
+ // Old port is input → old dataType was the target; check any source can feed into new port
108
+ return checker.areDataTypesCompatible(a.dataType, b.dataType);
109
+ }
110
+ return checker.areDataTypesCompatible(b.dataType, a.dataType);
111
+ };
112
+ // Pass 1: exact ID match
113
+ const idMatch = available.find((p) => p.id === oldPort.id && isCompatible(oldPort, p));
114
+ if (idMatch)
115
+ return idMatch;
116
+ // Pass 2: name match (case-insensitive)
117
+ const oldNameLower = oldPort.name.toLowerCase();
118
+ const nameMatch = available.find((p) => p.name.toLowerCase() === oldNameLower && isCompatible(oldPort, p));
119
+ if (nameMatch)
120
+ return nameMatch;
121
+ // Pass 3: first compatible dataType
122
+ const typeMatch = available.find((p) => isCompatible(oldPort, p));
123
+ return typeMatch ?? null;
124
+ }
125
+ /**
126
+ * Resolve the port metadata for an edge endpoint on a given node.
127
+ */
128
+ function resolvePort(node, handleId, direction) {
129
+ if (!handleId)
130
+ return null;
131
+ const portId = extractPortId(handleId);
132
+ if (!portId)
133
+ return null;
134
+ const ports = direction === 'input' ? node.data.metadata.inputs : node.data.metadata.outputs;
135
+ return ports.find((p) => p.id === portId) ?? null;
136
+ }
137
+ // =========================================================================
138
+ // Swap preview computation
139
+ // =========================================================================
140
+ /**
141
+ * Compute a preview of what will happen when swapping oldNode with newMetadata.
142
+ *
143
+ * This does NOT mutate anything — it returns a preview that can be displayed
144
+ * to the user for confirmation before executing the swap.
145
+ */
146
+ export function computeSwapPreview(oldNode, newMetadata, edges, allNodes, checker = null) {
147
+ const oldNodeId = oldNode.id;
148
+ const newNodeId = generateNodeId(newMetadata.id, allNodes);
149
+ // Collect all edges connected to the old node
150
+ const connectedEdges = edges.filter((e) => e.source === oldNodeId || e.target === oldNodeId);
151
+ // Track which ports on the new node have been claimed
152
+ const usedInputPortIds = new Set();
153
+ const usedOutputPortIds = new Set();
154
+ const keptEdges = [];
155
+ const droppedEdges = [];
156
+ for (const edge of connectedEdges) {
157
+ const isSource = edge.source === oldNodeId;
158
+ const direction = isSource ? 'output' : 'input';
159
+ const handleId = isSource ? edge.sourceHandle : edge.targetHandle;
160
+ const usedPorts = isSource ? usedOutputPortIds : usedInputPortIds;
161
+ // Resolve the old port
162
+ const oldPort = resolvePort(oldNode, handleId, direction);
163
+ if (!oldPort) {
164
+ droppedEdges.push({
165
+ edge,
166
+ reason: `Port not found on original node`
167
+ });
168
+ continue;
169
+ }
170
+ // Find matching port on new node
171
+ const newPorts = direction === 'input' ? newMetadata.inputs : newMetadata.outputs;
172
+ const match = findMatchingPort(oldPort, newPorts, usedPorts, checker);
173
+ if (!match) {
174
+ droppedEdges.push({
175
+ edge,
176
+ reason: `No compatible ${direction} port found on "${newMetadata.name}"`
177
+ });
178
+ continue;
179
+ }
180
+ usedPorts.add(match.id);
181
+ // Build the rewritten edge
182
+ const newHandleId = buildHandleId(newNodeId, direction, match.id);
183
+ const newEdge = { ...edge };
184
+ if (isSource) {
185
+ newEdge.source = newNodeId;
186
+ newEdge.sourceHandle = newHandleId;
187
+ }
188
+ else {
189
+ newEdge.target = newNodeId;
190
+ newEdge.targetHandle = newHandleId;
191
+ }
192
+ keptEdges.push({ edge, newEdge });
193
+ }
194
+ // Config mapping preview
195
+ const { carriedOver, reset } = mapConfig(oldNode.data.config, newMetadata.configSchema, newMetadata.config);
196
+ return {
197
+ keptEdges,
198
+ droppedEdges,
199
+ hasDataLoss: droppedEdges.length > 0,
200
+ newNodeId,
201
+ configCarriedOver: carriedOver,
202
+ configReset: reset
203
+ };
204
+ }
205
+ // =========================================================================
206
+ // Swap execution
207
+ // =========================================================================
208
+ /**
209
+ * Execute a node swap using a previously computed preview.
210
+ *
211
+ * Returns new nodes and edges arrays ready for `workflowActions.batchUpdate()`.
212
+ */
213
+ export function executeSwap(oldNode, newMetadata, preview, allNodes, allEdges) {
214
+ const oldNodeId = oldNode.id;
215
+ const newNodeId = preview.newNodeId;
216
+ // Map config
217
+ const { config: mappedConfig } = mapConfig(oldNode.data.config, newMetadata.configSchema, newMetadata.config);
218
+ // Build the new node
219
+ const extensions = {
220
+ ...oldNode.data.extensions,
221
+ swap: {
222
+ previousNodeId: oldNodeId
223
+ }
224
+ };
225
+ const newNode = {
226
+ id: newNodeId,
227
+ type: 'universalNode',
228
+ position: { ...oldNode.position },
229
+ deletable: oldNode.deletable,
230
+ data: {
231
+ label: newMetadata.name,
232
+ config: mappedConfig,
233
+ metadata: newMetadata,
234
+ extensions
235
+ }
236
+ };
237
+ // Build dropped edge IDs set for fast lookup
238
+ const droppedEdgeIds = new Set(preview.droppedEdges.map((d) => d.edge.id));
239
+ // Build a map from old edge ID → new edge for kept edges
240
+ const keptEdgeMap = new Map();
241
+ for (const { edge, newEdge } of preview.keptEdges) {
242
+ keptEdgeMap.set(edge.id, newEdge);
243
+ }
244
+ // Build updated edges: skip dropped, replace kept, pass through unrelated
245
+ const updatedEdges = [];
246
+ for (const edge of allEdges) {
247
+ if (droppedEdgeIds.has(edge.id))
248
+ continue;
249
+ const replacement = keptEdgeMap.get(edge.id);
250
+ if (replacement) {
251
+ updatedEdges.push(replacement);
252
+ }
253
+ else {
254
+ updatedEdges.push(edge);
255
+ }
256
+ }
257
+ // Build updated nodes: replace old node with new node (preserving array order)
258
+ const updatedNodes = allNodes.map((node) => (node.id === oldNodeId ? newNode : node));
259
+ return { updatedNodes, updatedEdges };
260
+ }
261
+ // =========================================================================
262
+ // Version upgrade detection
263
+ // =========================================================================
264
+ /**
265
+ * Check if a newer version of the same node type is available.
266
+ *
267
+ * Compares the node's embedded metadata.version against the same-ID entry
268
+ * in the available nodes list (API returns only the latest version).
269
+ *
270
+ * @returns The newer NodeMetadata if an upgrade is available, null otherwise
271
+ */
272
+ export function getVersionUpgrade(currentMetadata, allNodeTypes) {
273
+ const available = allNodeTypes.find((n) => n.id === currentMetadata.id);
274
+ if (!available)
275
+ return null;
276
+ if (compareSemver(available.version, currentMetadata.version) > 0) {
277
+ return available;
278
+ }
279
+ return null;
280
+ }
281
+ // =========================================================================
282
+ // Phase 2 — Advanced Swap Functions
283
+ // =========================================================================
284
+ /**
285
+ * Determine the MatchQuality for how a port was matched.
286
+ */
287
+ function classifyMatch(oldPort, matchedPort) {
288
+ if (!matchedPort)
289
+ return 'unmapped';
290
+ if (matchedPort.id === oldPort.id)
291
+ return 'id';
292
+ if (matchedPort.name.toLowerCase() === oldPort.name.toLowerCase())
293
+ return 'name';
294
+ return 'type';
295
+ }
296
+ /**
297
+ * Compute a swap preview with full options support (strategies, overrides).
298
+ *
299
+ * Resolution order:
300
+ * 1. Check strategies — first canHandle() match wins for mapPorts()/mapConfig()
301
+ * 2. Fall through to built-in 3-pass for ports not covered by strategy
302
+ * 3. Apply portOverrides on top (highest priority — user's manual overrides)
303
+ * 4. Same cascade for config
304
+ */
305
+ export function computeSwapPreviewWithOptions(oldNode, newMetadata, edges, allNodes, options) {
306
+ const checker = options.checker ?? null;
307
+ const oldNodeId = oldNode.id;
308
+ const newNodeId = generateNodeId(newMetadata.id, allNodes);
309
+ // Collect connected edges
310
+ const connectedEdges = edges.filter((e) => e.source === oldNodeId || e.target === oldNodeId);
311
+ // Try strategy-based port mapping
312
+ let strategyPortMap;
313
+ let strategyConfigMap;
314
+ if (options.strategies?.length) {
315
+ const ctx = {
316
+ oldNode,
317
+ newMetadata,
318
+ edges,
319
+ allNodes,
320
+ checker
321
+ };
322
+ for (const strategy of options.strategies) {
323
+ if (strategy.canHandle(ctx)) {
324
+ strategyPortMap = strategy.mapPorts?.(ctx);
325
+ strategyConfigMap = strategy.mapConfig?.(ctx);
326
+ break; // first match wins
327
+ }
328
+ }
329
+ }
330
+ // Build port override lookup (highest priority)
331
+ const portOverrideLookup = new Map();
332
+ for (const override of options.portOverrides ?? []) {
333
+ portOverrideLookup.set(`${override.direction}:${override.oldPortId}`, override.newPortId);
334
+ }
335
+ // Track used ports
336
+ const usedInputPortIds = new Set();
337
+ const usedOutputPortIds = new Set();
338
+ const keptEdges = [];
339
+ const droppedEdges = [];
340
+ for (const edge of connectedEdges) {
341
+ const isSource = edge.source === oldNodeId;
342
+ const direction = isSource ? 'output' : 'input';
343
+ const handleId = isSource ? edge.sourceHandle : edge.targetHandle;
344
+ const usedPorts = isSource ? usedOutputPortIds : usedInputPortIds;
345
+ const oldPort = resolvePort(oldNode, handleId, direction);
346
+ if (!oldPort) {
347
+ droppedEdges.push({ edge, reason: 'Port not found on original node' });
348
+ continue;
349
+ }
350
+ // Priority 1: Manual port override
351
+ const overrideKey = `${direction}:${oldPort.id}`;
352
+ if (portOverrideLookup.has(overrideKey)) {
353
+ const overrideNewPortId = portOverrideLookup.get(overrideKey);
354
+ if (overrideNewPortId === null) {
355
+ droppedEdges.push({ edge, reason: 'Manually dropped' });
356
+ continue;
357
+ }
358
+ const newPorts = direction === 'input' ? newMetadata.inputs : newMetadata.outputs;
359
+ const overridePort = newPorts.find((p) => p.id === overrideNewPortId);
360
+ if (overridePort) {
361
+ usedPorts.add(overridePort.id);
362
+ const newHandleId = buildHandleId(newNodeId, direction, overridePort.id);
363
+ const newEdge = { ...edge };
364
+ if (isSource) {
365
+ newEdge.source = newNodeId;
366
+ newEdge.sourceHandle = newHandleId;
367
+ }
368
+ else {
369
+ newEdge.target = newNodeId;
370
+ newEdge.targetHandle = newHandleId;
371
+ }
372
+ keptEdges.push({ edge, newEdge });
373
+ continue;
374
+ }
375
+ }
376
+ // Priority 2: Strategy port mapping
377
+ if (strategyPortMap && oldPort.id in strategyPortMap) {
378
+ const strategyNewPortId = strategyPortMap[oldPort.id];
379
+ if (strategyNewPortId === null) {
380
+ droppedEdges.push({ edge, reason: 'Dropped by strategy' });
381
+ continue;
382
+ }
383
+ const newPorts = direction === 'input' ? newMetadata.inputs : newMetadata.outputs;
384
+ const strategyPort = newPorts.find((p) => p.id === strategyNewPortId);
385
+ if (strategyPort && !usedPorts.has(strategyPort.id)) {
386
+ usedPorts.add(strategyPort.id);
387
+ const newHandleId = buildHandleId(newNodeId, direction, strategyPort.id);
388
+ const newEdge = { ...edge };
389
+ if (isSource) {
390
+ newEdge.source = newNodeId;
391
+ newEdge.sourceHandle = newHandleId;
392
+ }
393
+ else {
394
+ newEdge.target = newNodeId;
395
+ newEdge.targetHandle = newHandleId;
396
+ }
397
+ keptEdges.push({ edge, newEdge });
398
+ continue;
399
+ }
400
+ }
401
+ // Priority 3: Built-in 3-pass matching
402
+ const newPorts = direction === 'input' ? newMetadata.inputs : newMetadata.outputs;
403
+ const match = findMatchingPort(oldPort, newPorts, usedPorts, checker);
404
+ if (!match) {
405
+ droppedEdges.push({
406
+ edge,
407
+ reason: `No compatible ${direction} port found on "${newMetadata.name}"`
408
+ });
409
+ continue;
410
+ }
411
+ usedPorts.add(match.id);
412
+ const newHandleId = buildHandleId(newNodeId, direction, match.id);
413
+ const newEdge = { ...edge };
414
+ if (isSource) {
415
+ newEdge.source = newNodeId;
416
+ newEdge.sourceHandle = newHandleId;
417
+ }
418
+ else {
419
+ newEdge.target = newNodeId;
420
+ newEdge.targetHandle = newHandleId;
421
+ }
422
+ keptEdges.push({ edge, newEdge });
423
+ }
424
+ // Config mapping — apply strategy then overrides
425
+ const { config: baseConfig, carriedOver, reset } = mapConfig(oldNode.data.config, newMetadata.configSchema, newMetadata.config);
426
+ // Apply strategy config overrides
427
+ if (strategyConfigMap) {
428
+ for (const [key, mapping] of Object.entries(strategyConfigMap)) {
429
+ if (mapping.action === 'carry' && key in oldNode.data.config) {
430
+ if (!carriedOver.includes(key))
431
+ carriedOver.push(key);
432
+ const resetIdx = reset.indexOf(key);
433
+ if (resetIdx >= 0)
434
+ reset.splice(resetIdx, 1);
435
+ }
436
+ else if (mapping.action === 'reset') {
437
+ if (!reset.includes(key))
438
+ reset.push(key);
439
+ const carryIdx = carriedOver.indexOf(key);
440
+ if (carryIdx >= 0)
441
+ carriedOver.splice(carryIdx, 1);
442
+ }
443
+ }
444
+ }
445
+ // Apply manual config overrides (highest priority)
446
+ for (const override of options.configOverrides ?? []) {
447
+ if (override.action === 'carry' && override.key in oldNode.data.config) {
448
+ if (!carriedOver.includes(override.key))
449
+ carriedOver.push(override.key);
450
+ const resetIdx = reset.indexOf(override.key);
451
+ if (resetIdx >= 0)
452
+ reset.splice(resetIdx, 1);
453
+ }
454
+ else if (override.action === 'reset') {
455
+ if (!reset.includes(override.key))
456
+ reset.push(override.key);
457
+ const carryIdx = carriedOver.indexOf(override.key);
458
+ if (carryIdx >= 0)
459
+ carriedOver.splice(carryIdx, 1);
460
+ }
461
+ else if (override.action === 'set') {
462
+ if (!carriedOver.includes(override.key))
463
+ carriedOver.push(override.key);
464
+ const resetIdx = reset.indexOf(override.key);
465
+ if (resetIdx >= 0)
466
+ reset.splice(resetIdx, 1);
467
+ }
468
+ }
469
+ return {
470
+ keptEdges,
471
+ droppedEdges,
472
+ hasDataLoss: droppedEdges.length > 0,
473
+ newNodeId,
474
+ configCarriedOver: carriedOver,
475
+ configReset: reset
476
+ };
477
+ }
478
+ /**
479
+ * Compute interactive state for the mapping editor UI.
480
+ *
481
+ * Returns EditablePortMapping and EditableConfigMapping entries
482
+ * with match quality annotations and isFlat flags.
483
+ */
484
+ export function computeInteractiveState(oldNode, newMetadata, edges, allNodes, options = {}) {
485
+ const checker = options.checker ?? null;
486
+ const oldNodeId = oldNode.id;
487
+ const newNodeId = generateNodeId(newMetadata.id, allNodes);
488
+ const connectedEdges = edges.filter((e) => e.source === oldNodeId || e.target === oldNodeId);
489
+ // Compute the base preview to get auto-matched ports
490
+ const preview = computeSwapPreviewWithOptions(oldNode, newMetadata, edges, allNodes, options);
491
+ // Build a map from edge id → new port id for kept edges
492
+ const keptEdgePortMap = new Map();
493
+ for (const { edge, newEdge } of preview.keptEdges) {
494
+ const isSource = edge.source === oldNodeId;
495
+ const handle = isSource ? newEdge.sourceHandle : newEdge.targetHandle;
496
+ const portId = extractPortId(handle ?? undefined);
497
+ if (portId)
498
+ keptEdgePortMap.set(edge.id, portId);
499
+ }
500
+ // Build port mappings
501
+ const portMappings = [];
502
+ for (const edge of connectedEdges) {
503
+ const isSource = edge.source === oldNodeId;
504
+ const direction = isSource ? 'output' : 'input';
505
+ const handleId = isSource ? edge.sourceHandle : edge.targetHandle;
506
+ const oldPort = resolvePort(oldNode, handleId, direction);
507
+ if (!oldPort)
508
+ continue;
509
+ const matchedPortId = keptEdgePortMap.get(edge.id) ?? null;
510
+ const newPorts = direction === 'input' ? newMetadata.inputs : newMetadata.outputs;
511
+ const matchedPort = matchedPortId
512
+ ? (newPorts.find((p) => p.id === matchedPortId) ?? null)
513
+ : null;
514
+ const matchQuality = classifyMatch(oldPort, matchedPort);
515
+ portMappings.push({
516
+ oldPort,
517
+ edge,
518
+ direction,
519
+ selectedNewPortId: matchedPortId,
520
+ matchQuality,
521
+ autoSuggestedPortId: matchedPortId,
522
+ isOverridden: false
523
+ });
524
+ }
525
+ // Build config mappings
526
+ const configMappings = [];
527
+ const newSchema = newMetadata.configSchema;
528
+ if (newSchema?.properties) {
529
+ for (const [key, prop] of Object.entries(newSchema.properties)) {
530
+ if (DYNAMIC_PORT_KEYS.has(key))
531
+ continue;
532
+ const oldValue = oldNode.data.config[key];
533
+ const schemaDefault = prop?.default;
534
+ const providedDefault = newMetadata.config?.[key];
535
+ const newDefault = providedDefault !== undefined ? providedDefault : schemaDefault;
536
+ const hasOldValue = key in oldNode.data.config;
537
+ const isFlat = !hasOldValue || isPrimitive(oldValue);
538
+ configMappings.push({
539
+ key,
540
+ title: prop?.title ?? key,
541
+ oldValue,
542
+ newDefault,
543
+ carryOver: hasOldValue && isFlat,
544
+ autoCarryOver: hasOldValue && isFlat,
545
+ isFlat
546
+ });
547
+ }
548
+ }
549
+ return {
550
+ oldNode,
551
+ newMetadata,
552
+ newNodeId,
553
+ portMappings,
554
+ configMappings,
555
+ availableNewInputs: [...newMetadata.inputs],
556
+ availableNewOutputs: [...newMetadata.outputs]
557
+ };
558
+ }
559
+ /** Check if a value is a primitive (string, number, boolean, null, undefined). */
560
+ function isPrimitive(value) {
561
+ if (value === null || value === undefined)
562
+ return true;
563
+ const t = typeof value;
564
+ return t === 'string' || t === 'number' || t === 'boolean';
565
+ }
566
+ /**
567
+ * Convert user-edited InteractiveSwapState back into a SwapPreview
568
+ * for executeSwap(). Pure function, no side effects.
569
+ */
570
+ export function buildSwapPreviewFromState(state, allEdges) {
571
+ const keptEdges = [];
572
+ const droppedEdges = [];
573
+ for (const mapping of state.portMappings) {
574
+ if (!mapping.selectedNewPortId) {
575
+ droppedEdges.push({
576
+ edge: mapping.edge,
577
+ reason: mapping.matchQuality === 'unmapped'
578
+ ? `No compatible ${mapping.direction} port found on "${state.newMetadata.name}"`
579
+ : 'Manually dropped'
580
+ });
581
+ continue;
582
+ }
583
+ const isSource = mapping.edge.source === state.oldNode.id;
584
+ const newHandleId = buildHandleId(state.newNodeId, mapping.direction, mapping.selectedNewPortId);
585
+ const newEdge = { ...mapping.edge };
586
+ if (isSource) {
587
+ newEdge.source = state.newNodeId;
588
+ newEdge.sourceHandle = newHandleId;
589
+ }
590
+ else {
591
+ newEdge.target = state.newNodeId;
592
+ newEdge.targetHandle = newHandleId;
593
+ }
594
+ keptEdges.push({ edge: mapping.edge, newEdge });
595
+ }
596
+ // Build config lists from interactive state
597
+ const configCarriedOver = [];
598
+ const configReset = [];
599
+ for (const cm of state.configMappings) {
600
+ if (cm.carryOver && cm.isFlat) {
601
+ configCarriedOver.push(cm.key);
602
+ }
603
+ else {
604
+ configReset.push(cm.key);
605
+ }
606
+ }
607
+ return {
608
+ keptEdges,
609
+ droppedEdges,
610
+ hasDataLoss: droppedEdges.length > 0,
611
+ newNodeId: state.newNodeId,
612
+ configCarriedOver,
613
+ configReset
614
+ };
615
+ }
616
+ /**
617
+ * Headless one-shot swap with full validation.
618
+ *
619
+ * Guardrails:
620
+ * - Validates oldNode.id exists in allNodes
621
+ * - Validates format compatibility if newMetadata.formats is set
622
+ * - Computes preview → executes → validates → returns result
623
+ * - Throws SwapValidationError on invalid input
624
+ */
625
+ export function performSwap(oldNode, newMetadata, allNodes, allEdges, options) {
626
+ // Validate oldNode exists
627
+ const exists = allNodes.some((n) => n.id === oldNode.id);
628
+ if (!exists) {
629
+ throw new SwapValidationError(`Node "${oldNode.id}" not found in the workflow`);
630
+ }
631
+ // Compute preview
632
+ const preview = options
633
+ ? computeSwapPreviewWithOptions(oldNode, newMetadata, allEdges, allNodes, options)
634
+ : computeSwapPreview(oldNode, newMetadata, allEdges, allNodes, null);
635
+ // Execute
636
+ const result = executeSwap(oldNode, newMetadata, preview, allNodes, allEdges);
637
+ // Post-swap validation
638
+ const validation = validateSwapResult(result);
639
+ if (!validation.valid) {
640
+ throw new SwapValidationError(`Post-swap validation failed: ${validation.error}`);
641
+ }
642
+ return result;
643
+ }
644
+ /**
645
+ * Validate a swap result for structural integrity.
646
+ *
647
+ * Checks:
648
+ * - No dangling edge references (every edge source/target exists in nodes)
649
+ * - No duplicate node IDs
650
+ * - No duplicate edge IDs
651
+ */
652
+ export function validateSwapResult(result) {
653
+ const nodeIds = new Set();
654
+ for (const node of result.updatedNodes) {
655
+ if (nodeIds.has(node.id)) {
656
+ return { valid: false, error: `Duplicate node ID: "${node.id}"` };
657
+ }
658
+ nodeIds.add(node.id);
659
+ }
660
+ const edgeIds = new Set();
661
+ for (const edge of result.updatedEdges) {
662
+ if (edgeIds.has(edge.id)) {
663
+ return { valid: false, error: `Duplicate edge ID: "${edge.id}"` };
664
+ }
665
+ edgeIds.add(edge.id);
666
+ if (!nodeIds.has(edge.source)) {
667
+ return {
668
+ valid: false,
669
+ error: `Dangling edge "${edge.id}": source node "${edge.source}" not found`
670
+ };
671
+ }
672
+ if (!nodeIds.has(edge.target)) {
673
+ return {
674
+ valid: false,
675
+ error: `Dangling edge "${edge.id}": target node "${edge.target}" not found`
676
+ };
677
+ }
678
+ }
679
+ return { valid: true };
680
+ }
@@ -9,7 +9,7 @@
9
9
  *
10
10
  * Works with both built-in types and custom registered types.
11
11
  */
12
- import type { NodeType, NodeMetadata } from "../types/index.js";
12
+ import type { NodeType, NodeMetadata } from '../types/index.js';
13
13
  /**
14
14
  * Gets the SvelteFlow component name for a given NodeType.
15
15
  * Uses the node component registry to resolve types.