@flowdrop/flowdrop 1.5.0 → 1.7.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 (435) hide show
  1. package/README.md +46 -47
  2. package/dist/adapters/WorkflowAdapter.d.ts +1 -1
  3. package/dist/adapters/WorkflowAdapter.js +26 -26
  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 +1 -1
  9. package/dist/adapters/agentspec/autoLayout.js +7 -9
  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.js +6 -6
  21. package/dist/chat/index.d.ts +5 -5
  22. package/dist/chat/index.js +4 -4
  23. package/dist/chat/responseParser.d.ts +6 -6
  24. package/dist/chat/responseParser.js +28 -24
  25. package/dist/commands/batch.d.ts +1 -1
  26. package/dist/commands/batch.js +5 -7
  27. package/dist/commands/executor.d.ts +2 -2
  28. package/dist/commands/executor.js +320 -231
  29. package/dist/commands/index.d.ts +6 -6
  30. package/dist/commands/index.js +5 -5
  31. package/dist/commands/parser.d.ts +1 -1
  32. package/dist/commands/parser.js +91 -74
  33. package/dist/commands/positioner.d.ts +2 -2
  34. package/dist/commands/positioner.js +1 -1
  35. package/dist/commands/storeIntegration.svelte.d.ts +2 -2
  36. package/dist/commands/storeIntegration.svelte.js +5 -5
  37. package/dist/commands/types.d.ts +42 -42
  38. package/dist/commands/types.js +2 -2
  39. package/dist/components/App.svelte +280 -303
  40. package/dist/components/App.svelte.d.ts +11 -9
  41. package/dist/components/CanvasBanner.stories.svelte +10 -16
  42. package/dist/components/CanvasBanner.stories.svelte.d.ts +1 -1
  43. package/dist/components/CanvasBanner.svelte +2 -2
  44. package/dist/components/CanvasBanner.svelte.d.ts +1 -1
  45. package/dist/components/CanvasController.svelte +3 -4
  46. package/dist/components/ConfigForm.svelte +118 -256
  47. package/dist/components/ConfigForm.svelte.d.ts +2 -2
  48. package/dist/components/ConfigMappingRow.svelte +7 -9
  49. package/dist/components/ConfigMappingRow.svelte.d.ts +1 -1
  50. package/dist/components/ConfigModal.svelte +3 -3
  51. package/dist/components/ConfigModal.svelte.d.ts +1 -1
  52. package/dist/components/ConfigPanel.stories.svelte +19 -19
  53. package/dist/components/ConfigPanel.stories.svelte.d.ts +1 -1
  54. package/dist/components/ConfigPanel.svelte +9 -20
  55. package/dist/components/ConfigPanel.svelte.d.ts +1 -1
  56. package/dist/components/ConnectionLine.svelte +4 -4
  57. package/dist/components/EdgeRefresher.svelte +1 -1
  58. package/dist/components/FlowDropEdge.stories.svelte +110 -110
  59. package/dist/components/FlowDropEdge.svelte +9 -9
  60. package/dist/components/FlowDropEdge.svelte.d.ts +1 -1
  61. package/dist/components/FlowDropZone.svelte +6 -9
  62. package/dist/components/FlowDropZone.svelte.d.ts +1 -1
  63. package/dist/components/LoadingSpinner.stories.svelte +13 -13
  64. package/dist/components/LoadingSpinner.stories.svelte.d.ts +1 -1
  65. package/dist/components/LoadingSpinner.svelte +3 -3
  66. package/dist/components/LoadingSpinner.svelte.d.ts +1 -1
  67. package/dist/components/Logo.stories.svelte +4 -4
  68. package/dist/components/Logo.stories.svelte.d.ts +1 -1
  69. package/dist/components/Logo.svelte +3 -9
  70. package/dist/components/LogsSidebar.svelte +41 -48
  71. package/dist/components/LogsSidebar.svelte.d.ts +1 -1
  72. package/dist/components/MarkdownDisplay.stories.svelte +10 -14
  73. package/dist/components/MarkdownDisplay.stories.svelte.d.ts +1 -1
  74. package/dist/components/MarkdownDisplay.svelte +4 -6
  75. package/dist/components/Navbar.stories.svelte +19 -19
  76. package/dist/components/Navbar.stories.svelte.d.ts +1 -1
  77. package/dist/components/Navbar.svelte +28 -49
  78. package/dist/components/Navbar.svelte.d.ts +2 -2
  79. package/dist/components/NodeSidebar.svelte +42 -88
  80. package/dist/components/NodeSidebar.svelte.d.ts +1 -1
  81. package/dist/components/NodeStatusOverlay.stories.svelte +19 -31
  82. package/dist/components/NodeStatusOverlay.stories.svelte.d.ts +1 -1
  83. package/dist/components/NodeStatusOverlay.svelte +40 -55
  84. package/dist/components/NodeStatusOverlay.svelte.d.ts +3 -3
  85. package/dist/components/NodeSwapPicker.svelte +20 -64
  86. package/dist/components/NodeSwapPicker.svelte.d.ts +1 -1
  87. package/dist/components/PipelineStatus.svelte +63 -89
  88. package/dist/components/PipelineStatus.svelte.d.ts +4 -4
  89. package/dist/components/PortCoordinateTracker.svelte +5 -7
  90. package/dist/components/PortCoordinateTracker.svelte.d.ts +1 -1
  91. package/dist/components/PortMappingRow.svelte +20 -24
  92. package/dist/components/PortMappingRow.svelte.d.ts +2 -2
  93. package/dist/components/ReadOnlyDetails.svelte +1 -1
  94. package/dist/components/SchemaForm.stories.svelte +53 -53
  95. package/dist/components/SchemaForm.stories.svelte.d.ts +1 -1
  96. package/dist/components/SchemaForm.svelte +24 -51
  97. package/dist/components/SchemaForm.svelte.d.ts +2 -2
  98. package/dist/components/SettingsModal.svelte +6 -9
  99. package/dist/components/SettingsModal.svelte.d.ts +1 -1
  100. package/dist/components/SettingsPanel.svelte +138 -158
  101. package/dist/components/SettingsPanel.svelte.d.ts +1 -1
  102. package/dist/components/StatusIcon.stories.svelte +16 -29
  103. package/dist/components/StatusIcon.stories.svelte.d.ts +1 -1
  104. package/dist/components/StatusIcon.svelte +19 -19
  105. package/dist/components/StatusIcon.svelte.d.ts +2 -2
  106. package/dist/components/StatusLabel.stories.svelte +8 -8
  107. package/dist/components/StatusLabel.stories.svelte.d.ts +1 -1
  108. package/dist/components/SwapMappingEditor.svelte +35 -56
  109. package/dist/components/SwapMappingEditor.svelte.d.ts +2 -2
  110. package/dist/components/ThemeToggle.stories.svelte +10 -10
  111. package/dist/components/ThemeToggle.stories.svelte.d.ts +1 -1
  112. package/dist/components/ThemeToggle.svelte +22 -33
  113. package/dist/components/ThemeToggle.svelte.d.ts +1 -1
  114. package/dist/components/UniversalNode.svelte +29 -41
  115. package/dist/components/UniversalNode.svelte.d.ts +3 -3
  116. package/dist/components/WorkflowEditor.svelte +113 -168
  117. package/dist/components/WorkflowEditor.svelte.d.ts +4 -4
  118. package/dist/components/chat/AIChatPanel.svelte +272 -133
  119. package/dist/components/chat/AIChatPanel.svelte.d.ts +3 -3
  120. package/dist/components/chat/CommandPreview.svelte +74 -24
  121. package/dist/components/chat/CommandPreview.svelte.d.ts +1 -1
  122. package/dist/components/console/CommandConsole.stories.svelte +71 -53
  123. package/dist/components/console/CommandConsole.stories.svelte.d.ts +1 -1
  124. package/dist/components/console/CommandConsole.svelte +39 -35
  125. package/dist/components/console/CommandConsole.svelte.d.ts +2 -2
  126. package/dist/components/console/ConsoleAutocomplete.svelte +6 -3
  127. package/dist/components/console/ConsoleInput.svelte +148 -89
  128. package/dist/components/console/ConsoleInput.svelte.d.ts +1 -1
  129. package/dist/components/console/ConsoleOutput.svelte +5 -10
  130. package/dist/components/console/ConsoleOutput.svelte.d.ts +1 -1
  131. package/dist/components/console/formatters.d.ts +1 -1
  132. package/dist/components/console/formatters.js +27 -29
  133. package/dist/components/form/FormArray.svelte +75 -132
  134. package/dist/components/form/FormArray.svelte.d.ts +1 -1
  135. package/dist/components/form/FormAutocomplete.svelte +65 -108
  136. package/dist/components/form/FormAutocomplete.svelte.d.ts +1 -1
  137. package/dist/components/form/FormCheckboxGroup.stories.svelte +13 -16
  138. package/dist/components/form/FormCheckboxGroup.stories.svelte.d.ts +1 -1
  139. package/dist/components/form/FormCheckboxGroup.svelte +2 -2
  140. package/dist/components/form/FormCodeEditor.svelte +46 -59
  141. package/dist/components/form/FormField.svelte +79 -90
  142. package/dist/components/form/FormField.svelte.d.ts +2 -2
  143. package/dist/components/form/FormFieldLight.svelte +72 -88
  144. package/dist/components/form/FormFieldLight.svelte.d.ts +1 -1
  145. package/dist/components/form/FormFieldWrapper.stories.svelte +14 -14
  146. package/dist/components/form/FormFieldWrapper.stories.svelte.d.ts +1 -1
  147. package/dist/components/form/FormFieldWrapper.svelte +2 -9
  148. package/dist/components/form/FormFieldWrapper.svelte.d.ts +1 -1
  149. package/dist/components/form/FormFieldset.svelte +3 -3
  150. package/dist/components/form/FormFieldset.svelte.d.ts +2 -2
  151. package/dist/components/form/FormMarkdownEditor.svelte +123 -156
  152. package/dist/components/form/FormNumberField.stories.svelte +18 -18
  153. package/dist/components/form/FormNumberField.stories.svelte.d.ts +1 -1
  154. package/dist/components/form/FormNumberField.svelte +6 -6
  155. package/dist/components/form/FormRangeField.stories.svelte +13 -13
  156. package/dist/components/form/FormRangeField.stories.svelte.d.ts +1 -1
  157. package/dist/components/form/FormRangeField.svelte +4 -12
  158. package/dist/components/form/FormSelect.stories.svelte +21 -21
  159. package/dist/components/form/FormSelect.stories.svelte.d.ts +1 -1
  160. package/dist/components/form/FormSelect.svelte +5 -5
  161. package/dist/components/form/FormSelect.svelte.d.ts +1 -1
  162. package/dist/components/form/FormTemplateEditor.svelte +126 -175
  163. package/dist/components/form/FormTemplateEditor.svelte.d.ts +1 -1
  164. package/dist/components/form/FormTextField.stories.svelte +17 -23
  165. package/dist/components/form/FormTextField.stories.svelte.d.ts +1 -1
  166. package/dist/components/form/FormTextField.svelte +4 -4
  167. package/dist/components/form/FormTextarea.stories.svelte +18 -21
  168. package/dist/components/form/FormTextarea.stories.svelte.d.ts +1 -1
  169. package/dist/components/form/FormTextarea.svelte +4 -4
  170. package/dist/components/form/FormToggle.stories.svelte +13 -16
  171. package/dist/components/form/FormToggle.stories.svelte.d.ts +1 -1
  172. package/dist/components/form/FormToggle.svelte +3 -3
  173. package/dist/components/form/FormUISchemaRenderer.svelte +12 -19
  174. package/dist/components/form/FormUISchemaRenderer.svelte.d.ts +3 -3
  175. package/dist/components/form/index.d.ts +19 -19
  176. package/dist/components/form/index.js +18 -18
  177. package/dist/components/form/templateAutocomplete.d.ts +2 -2
  178. package/dist/components/form/templateAutocomplete.js +55 -64
  179. package/dist/components/form/types.d.ts +6 -6
  180. package/dist/components/form/types.js +4 -9
  181. package/dist/components/icons/AlertCircleIcon.svelte +1 -6
  182. package/dist/components/icons/CogIcon.svelte +1 -6
  183. package/dist/components/interrupt/ChoicePrompt.stories.svelte +27 -27
  184. package/dist/components/interrupt/ChoicePrompt.stories.svelte.d.ts +1 -1
  185. package/dist/components/interrupt/ChoicePrompt.svelte +17 -41
  186. package/dist/components/interrupt/ChoicePrompt.svelte.d.ts +1 -1
  187. package/dist/components/interrupt/ConfirmationPrompt.stories.svelte +17 -17
  188. package/dist/components/interrupt/ConfirmationPrompt.stories.svelte.d.ts +1 -1
  189. package/dist/components/interrupt/ConfirmationPrompt.svelte +10 -16
  190. package/dist/components/interrupt/ConfirmationPrompt.svelte.d.ts +1 -1
  191. package/dist/components/interrupt/FormPrompt.svelte +10 -15
  192. package/dist/components/interrupt/FormPrompt.svelte.d.ts +1 -1
  193. package/dist/components/interrupt/InterruptBubble.svelte +87 -121
  194. package/dist/components/interrupt/InterruptBubble.svelte.d.ts +2 -2
  195. package/dist/components/interrupt/ReviewPrompt.stories.svelte +37 -37
  196. package/dist/components/interrupt/ReviewPrompt.stories.svelte.d.ts +1 -1
  197. package/dist/components/interrupt/ReviewPrompt.svelte +55 -75
  198. package/dist/components/interrupt/ReviewPrompt.svelte.d.ts +1 -1
  199. package/dist/components/interrupt/TextInputPrompt.stories.svelte +16 -17
  200. package/dist/components/interrupt/TextInputPrompt.stories.svelte.d.ts +1 -1
  201. package/dist/components/interrupt/TextInputPrompt.svelte +13 -18
  202. package/dist/components/interrupt/TextInputPrompt.svelte.d.ts +1 -1
  203. package/dist/components/interrupt/index.d.ts +6 -6
  204. package/dist/components/interrupt/index.js +6 -6
  205. package/dist/components/layouts/MainLayout.svelte +46 -84
  206. package/dist/components/layouts/MainLayout.svelte.d.ts +6 -6
  207. package/dist/components/nodes/GatewayNode.stories.svelte +64 -65
  208. package/dist/components/nodes/GatewayNode.svelte +37 -70
  209. package/dist/components/nodes/GatewayNode.svelte.d.ts +3 -3
  210. package/dist/components/nodes/IdeaNode.stories.svelte +25 -26
  211. package/dist/components/nodes/IdeaNode.svelte +22 -36
  212. package/dist/components/nodes/IdeaNode.svelte.d.ts +1 -1
  213. package/dist/components/nodes/NotesNode.stories.svelte +37 -38
  214. package/dist/components/nodes/NotesNode.svelte +28 -39
  215. package/dist/components/nodes/NotesNode.svelte.d.ts +1 -1
  216. package/dist/components/nodes/SimpleNode.stories.svelte +137 -138
  217. package/dist/components/nodes/SimpleNode.svelte +51 -81
  218. package/dist/components/nodes/SimpleNode.svelte.d.ts +1 -1
  219. package/dist/components/nodes/SquareNode.stories.svelte +75 -75
  220. package/dist/components/nodes/SquareNode.svelte +42 -68
  221. package/dist/components/nodes/SquareNode.svelte.d.ts +1 -1
  222. package/dist/components/nodes/TerminalNode.stories.svelte +10 -10
  223. package/dist/components/nodes/TerminalNode.svelte +74 -112
  224. package/dist/components/nodes/TerminalNode.svelte.d.ts +1 -1
  225. package/dist/components/nodes/ToolNode.stories.svelte +115 -116
  226. package/dist/components/nodes/ToolNode.svelte +31 -64
  227. package/dist/components/nodes/ToolNode.svelte.d.ts +1 -1
  228. package/dist/components/nodes/WorkflowNode.stories.svelte +84 -89
  229. package/dist/components/nodes/WorkflowNode.svelte +50 -103
  230. package/dist/components/nodes/WorkflowNode.svelte.d.ts +3 -3
  231. package/dist/components/playground/ChatPanel.svelte +47 -103
  232. package/dist/components/playground/ExecutionLogs.svelte +45 -68
  233. package/dist/components/playground/InputCollector.svelte +32 -51
  234. package/dist/components/playground/MessageBubble.stories.svelte +25 -25
  235. package/dist/components/playground/MessageBubble.stories.svelte.d.ts +1 -1
  236. package/dist/components/playground/MessageBubble.svelte +54 -70
  237. package/dist/components/playground/MessageBubble.svelte.d.ts +1 -1
  238. package/dist/components/playground/Playground.svelte +60 -91
  239. package/dist/components/playground/Playground.svelte.d.ts +3 -3
  240. package/dist/components/playground/PlaygroundModal.svelte +8 -12
  241. package/dist/components/playground/PlaygroundModal.svelte.d.ts +3 -3
  242. package/dist/components/playground/SessionManager.svelte +34 -40
  243. package/dist/components/playground/SessionManager.svelte.d.ts +1 -1
  244. package/dist/config/agentSpecEndpoints.d.ts +1 -1
  245. package/dist/config/agentSpecEndpoints.js +20 -20
  246. package/dist/config/constants.js +2 -2
  247. package/dist/config/defaultCategories.d.ts +1 -1
  248. package/dist/config/defaultCategories.js +86 -86
  249. package/dist/config/defaultPortConfig.d.ts +1 -1
  250. package/dist/config/defaultPortConfig.js +144 -144
  251. package/dist/config/endpoints.d.ts +4 -4
  252. package/dist/config/endpoints.js +68 -68
  253. package/dist/config/runtimeConfig.d.ts +2 -2
  254. package/dist/config/runtimeConfig.js +8 -8
  255. package/dist/core/index.d.ts +68 -68
  256. package/dist/core/index.js +38 -38
  257. package/dist/display/index.d.ts +2 -2
  258. package/dist/display/index.js +2 -2
  259. package/dist/editor/index.d.ts +64 -64
  260. package/dist/editor/index.js +54 -54
  261. package/dist/form/code.d.ts +5 -5
  262. package/dist/form/code.js +14 -14
  263. package/dist/form/fieldRegistry.d.ts +3 -3
  264. package/dist/form/fieldRegistry.js +9 -11
  265. package/dist/form/full.d.ts +8 -8
  266. package/dist/form/full.js +9 -9
  267. package/dist/form/index.d.ts +18 -18
  268. package/dist/form/index.js +16 -16
  269. package/dist/form/markdown.d.ts +4 -4
  270. package/dist/form/markdown.js +8 -8
  271. package/dist/helpers/proximityConnect.d.ts +3 -3
  272. package/dist/helpers/proximityConnect.js +32 -34
  273. package/dist/helpers/workflowEditorHelper.d.ts +6 -6
  274. package/dist/helpers/workflowEditorHelper.js +64 -68
  275. package/dist/index.d.ts +6 -6
  276. package/dist/index.js +6 -6
  277. package/dist/mocks/app-environment.js +2 -2
  278. package/dist/mocks/app-forms.js +1 -1
  279. package/dist/mocks/app-navigation.js +2 -2
  280. package/dist/mocks/app-stores.js +3 -3
  281. package/dist/playground/index.d.ts +19 -19
  282. package/dist/playground/index.js +16 -16
  283. package/dist/playground/mount.d.ts +3 -3
  284. package/dist/playground/mount.js +24 -24
  285. package/dist/registry/builtinFormats.js +13 -13
  286. package/dist/registry/builtinNodes.d.ts +2 -2
  287. package/dist/registry/builtinNodes.js +77 -77
  288. package/dist/registry/index.d.ts +4 -4
  289. package/dist/registry/index.js +4 -4
  290. package/dist/registry/nodeComponentRegistry.d.ts +8 -8
  291. package/dist/registry/nodeComponentRegistry.js +9 -11
  292. package/dist/registry/plugin.d.ts +2 -2
  293. package/dist/registry/plugin.js +11 -11
  294. package/dist/registry/workflowFormatRegistry.d.ts +3 -3
  295. package/dist/registry/workflowFormatRegistry.js +2 -2
  296. package/dist/schema/index.d.ts +1 -1
  297. package/dist/schema/index.js +2 -2
  298. package/dist/schemas/v1/workflow.schema.json +5 -0
  299. package/dist/services/agentSpecExecutionService.d.ts +3 -3
  300. package/dist/services/agentSpecExecutionService.js +55 -56
  301. package/dist/services/api.d.ts +2 -2
  302. package/dist/services/api.js +37 -37
  303. package/dist/services/apiVariableService.d.ts +1 -1
  304. package/dist/services/apiVariableService.js +34 -41
  305. package/dist/services/autoSaveService.js +8 -8
  306. package/dist/services/categoriesApi.d.ts +2 -2
  307. package/dist/services/categoriesApi.js +8 -8
  308. package/dist/services/chatService.d.ts +1 -1
  309. package/dist/services/chatService.js +18 -18
  310. package/dist/services/draftStorage.d.ts +1 -1
  311. package/dist/services/draftStorage.js +11 -11
  312. package/dist/services/dynamicSchemaService.d.ts +1 -1
  313. package/dist/services/dynamicSchemaService.js +39 -41
  314. package/dist/services/globalSave.d.ts +2 -2
  315. package/dist/services/globalSave.js +38 -41
  316. package/dist/services/historyService.d.ts +1 -1
  317. package/dist/services/historyService.js +10 -10
  318. package/dist/services/interruptService.d.ts +1 -1
  319. package/dist/services/interruptService.js +29 -35
  320. package/dist/services/nodeExecutionService.d.ts +1 -1
  321. package/dist/services/nodeExecutionService.js +44 -45
  322. package/dist/services/playgroundService.d.ts +1 -1
  323. package/dist/services/playgroundService.js +29 -29
  324. package/dist/services/portConfigApi.d.ts +2 -2
  325. package/dist/services/portConfigApi.js +8 -8
  326. package/dist/services/settingsService.d.ts +2 -2
  327. package/dist/services/settingsService.js +19 -25
  328. package/dist/services/toastService.d.ts +4 -4
  329. package/dist/services/toastService.js +33 -33
  330. package/dist/services/variableService.d.ts +1 -1
  331. package/dist/services/variableService.js +36 -36
  332. package/dist/services/workflowStorage.d.ts +2 -2
  333. package/dist/services/workflowStorage.js +13 -13
  334. package/dist/settings/index.d.ts +7 -7
  335. package/dist/settings/index.js +6 -6
  336. package/dist/skins/default.d.ts +1 -1
  337. package/dist/skins/default.js +1 -1
  338. package/dist/skins/index.d.ts +3 -3
  339. package/dist/skins/index.js +7 -7
  340. package/dist/skins/slate.d.ts +1 -1
  341. package/dist/skins/slate.js +69 -69
  342. package/dist/stores/categoriesStore.svelte.d.ts +1 -1
  343. package/dist/stores/categoriesStore.svelte.js +5 -5
  344. package/dist/stores/editorStateMachine.svelte.d.ts +2 -2
  345. package/dist/stores/editorStateMachine.svelte.js +34 -34
  346. package/dist/stores/historyStore.svelte.d.ts +4 -4
  347. package/dist/stores/historyStore.svelte.js +4 -4
  348. package/dist/stores/interruptStore.svelte.d.ts +3 -3
  349. package/dist/stores/interruptStore.svelte.js +21 -21
  350. package/dist/stores/playgroundStore.svelte.d.ts +2 -2
  351. package/dist/stores/playgroundStore.svelte.js +18 -21
  352. package/dist/stores/portCoordinateStore.svelte.d.ts +2 -2
  353. package/dist/stores/portCoordinateStore.svelte.js +10 -13
  354. package/dist/stores/settingsStore.svelte.d.ts +2 -2
  355. package/dist/stores/settingsStore.svelte.js +57 -62
  356. package/dist/stores/workflowStore.svelte.d.ts +4 -3
  357. package/dist/stores/workflowStore.svelte.js +47 -47
  358. package/dist/stories/CanvasDecorator.svelte +7 -10
  359. package/dist/stories/CanvasDecorator.svelte.d.ts +2 -2
  360. package/dist/stories/EdgeDecorator.svelte +28 -31
  361. package/dist/stories/EdgeDecorator.svelte.d.ts +1 -1
  362. package/dist/stories/NodeDecorator.svelte +14 -20
  363. package/dist/stories/NodeDecorator.svelte.d.ts +1 -1
  364. package/dist/stories/utils.d.ts +2 -2
  365. package/dist/stories/utils.js +89 -93
  366. package/dist/styles/base.css +16 -50
  367. package/dist/styles/tokens.css +10 -28
  368. package/dist/svelte-app.d.ts +10 -10
  369. package/dist/svelte-app.js +39 -39
  370. package/dist/themes/default.d.ts +1 -1
  371. package/dist/themes/default.js +4 -4
  372. package/dist/themes/index.d.ts +3 -3
  373. package/dist/themes/index.js +11 -11
  374. package/dist/themes/minimal.d.ts +1 -1
  375. package/dist/themes/minimal.js +5 -5
  376. package/dist/types/agentspec.d.ts +18 -18
  377. package/dist/types/agentspec.js +2 -2
  378. package/dist/types/auth.d.ts +1 -1
  379. package/dist/types/auth.js +6 -6
  380. package/dist/types/chat.d.ts +2 -2
  381. package/dist/types/config.d.ts +6 -6
  382. package/dist/types/events.d.ts +3 -3
  383. package/dist/types/events.js +2 -2
  384. package/dist/types/index.d.ts +34 -32
  385. package/dist/types/index.js +6 -6
  386. package/dist/types/interrupt.d.ts +6 -6
  387. package/dist/types/interrupt.js +21 -21
  388. package/dist/types/interruptState.d.ts +12 -12
  389. package/dist/types/interruptState.js +66 -66
  390. package/dist/types/playground.d.ts +7 -7
  391. package/dist/types/playground.js +14 -14
  392. package/dist/types/settings.d.ts +7 -5
  393. package/dist/types/settings.js +19 -24
  394. package/dist/types/skin.d.ts +1 -1
  395. package/dist/types/theme.d.ts +2 -2
  396. package/dist/types/uischema.d.ts +4 -4
  397. package/dist/types/uischema.js +3 -3
  398. package/dist/utils/colors.d.ts +1 -1
  399. package/dist/utils/colors.js +95 -97
  400. package/dist/utils/config.d.ts +2 -2
  401. package/dist/utils/config.js +48 -48
  402. package/dist/utils/connections.d.ts +6 -2
  403. package/dist/utils/connections.js +21 -15
  404. package/dist/utils/edgeStyling.d.ts +2 -2
  405. package/dist/utils/edgeStyling.js +36 -39
  406. package/dist/utils/errors.js +3 -3
  407. package/dist/utils/fetchWithAuth.d.ts +1 -1
  408. package/dist/utils/fetchWithAuth.js +2 -2
  409. package/dist/utils/handleIds.d.ts +2 -2
  410. package/dist/utils/handleIds.js +8 -8
  411. package/dist/utils/handlePositioning.d.ts +1 -1
  412. package/dist/utils/handlePositioning.js +2 -2
  413. package/dist/utils/icons.d.ts +1 -1
  414. package/dist/utils/icons.js +74 -74
  415. package/dist/utils/logger.d.ts +1 -1
  416. package/dist/utils/logger.js +7 -7
  417. package/dist/utils/nodeIds.d.ts +1 -1
  418. package/dist/utils/nodeIds.js +1 -1
  419. package/dist/utils/nodeStatus.d.ts +1 -1
  420. package/dist/utils/nodeStatus.js +48 -48
  421. package/dist/utils/nodeSwap.d.ts +9 -9
  422. package/dist/utils/nodeSwap.js +52 -58
  423. package/dist/utils/nodeTypes.d.ts +1 -1
  424. package/dist/utils/nodeTypes.js +20 -21
  425. package/dist/utils/nodeWrapper.d.ts +7 -7
  426. package/dist/utils/nodeWrapper.js +19 -21
  427. package/dist/utils/performanceUtils.d.ts +1 -1
  428. package/dist/utils/performanceUtils.js +1 -2
  429. package/dist/utils/portUtils.d.ts +2 -2
  430. package/dist/utils/portUtils.js +1 -1
  431. package/dist/utils/sanitize.js +1 -1
  432. package/dist/utils/uischema.d.ts +2 -2
  433. package/dist/utils/uischema.js +8 -8
  434. package/dist/utils/validation.js +8 -8
  435. package/package.json +7 -11
@@ -5,71 +5,66 @@
5
5
  -->
6
6
 
7
7
  <script lang="ts">
8
- import { onMount, tick } from "svelte";
9
- import MainLayout from "./layouts/MainLayout.svelte";
10
- import WorkflowEditor from "./WorkflowEditor.svelte";
11
- import NodeSidebar from "./NodeSidebar.svelte";
12
- import Icon from "@iconify/svelte";
13
- import ConfigForm from "./ConfigForm.svelte";
14
- import ConfigPanel from "./ConfigPanel.svelte";
15
- import CommandConsole from "./console/CommandConsole.svelte";
16
- import AIChatPanel from "./chat/AIChatPanel.svelte";
17
- import type { UIAction } from "../commands/index.js";
18
- import NodeSwapPicker from "./NodeSwapPicker.svelte";
19
- import SwapMappingEditor from "./SwapMappingEditor.svelte";
20
- import Navbar from "./Navbar.svelte";
21
- import { api, setEndpointConfig } from "../services/api.js";
22
- import { EnhancedFlowDropApiClient } from "../api/enhanced-client.js";
8
+ import { onMount, tick } from 'svelte';
9
+ import MainLayout from './layouts/MainLayout.svelte';
10
+ import WorkflowEditor from './WorkflowEditor.svelte';
11
+ import NodeSidebar from './NodeSidebar.svelte';
12
+ import Icon from '@iconify/svelte';
13
+ import ConfigForm from './ConfigForm.svelte';
14
+ import ConfigPanel from './ConfigPanel.svelte';
15
+ import CommandConsole from './console/CommandConsole.svelte';
16
+ import AIChatPanel from './chat/AIChatPanel.svelte';
17
+ import type { UIAction } from '../commands/index.js';
18
+ import NodeSwapPicker from './NodeSwapPicker.svelte';
19
+ import SwapMappingEditor from './SwapMappingEditor.svelte';
20
+ import Navbar from './Navbar.svelte';
21
+ import { api, setEndpointConfig } from '../services/api.js';
22
+ import { EnhancedFlowDropApiClient } from '../api/enhanced-client.js';
23
23
  import type {
24
24
  NodeMetadata,
25
25
  Workflow,
26
26
  WorkflowNode,
27
27
  ConfigSchema,
28
- NodeUIExtensions,
29
- } from "../types/index.js";
30
- import type { InteractiveSwapState, SwapEventContext } from "../utils/nodeSwap.js";
28
+ NodeUIExtensions
29
+ } from '../types/index.js';
30
+ import type { InteractiveSwapState, SwapEventContext } from '../utils/nodeSwap.js';
31
31
  import {
32
32
  computeInteractiveState,
33
33
  buildSwapPreviewFromState,
34
34
  executeSwap,
35
- validateSwapResult,
36
- } from "../utils/nodeSwap.js";
37
- import type { SwapStrategy } from "../utils/nodeSwap.js";
38
- import { DEFAULT_WORKFLOW_FORMAT } from "../types/index.js";
39
- import { createEndpointConfig } from "../config/endpoints.js";
40
- import type { EndpointConfig } from "../config/endpoints.js";
41
- import type { AuthProvider } from "../types/auth.js";
42
- import type {
43
- FlowDropEventHandlers,
44
- FlowDropFeatures,
45
- } from "../types/events.js";
46
- import { mergeFeatures } from "../types/events.js";
47
- import type { FlowDropTheme, FlowDropThemeName } from "../types/theme.js";
48
- import type { FlowDropSkinTokens } from "../types/skin.js";
49
- import { resolveTheme } from "../themes/index.js";
35
+ validateSwapResult
36
+ } from '../utils/nodeSwap.js';
37
+ import type { SwapStrategy } from '../utils/nodeSwap.js';
38
+ import { DEFAULT_WORKFLOW_FORMAT } from '../types/index.js';
39
+ import { createEndpointConfig } from '../config/endpoints.js';
40
+ import type { EndpointConfig } from '../config/endpoints.js';
41
+ import type { AuthProvider } from '../types/auth.js';
42
+ import type { FlowDropEventHandlers, FlowDropFeatures } from '../types/events.js';
43
+ import { mergeFeatures } from '../types/events.js';
44
+ import type { FlowDropTheme, FlowDropThemeName } from '../types/theme.js';
45
+ import type { FlowDropSkinTokens } from '../types/skin.js';
46
+ import { resolveTheme } from '../themes/index.js';
50
47
  import {
51
48
  getWorkflowStore,
52
49
  workflowActions,
53
50
  getWorkflowName,
54
51
  getWorkflowFormat,
55
- markAsSaved,
56
- } from "../stores/workflowStore.svelte.js";
57
- import {
58
- globalSaveWorkflow,
59
- globalExportWorkflow,
60
- } from "../services/globalSave.js";
61
- import { apiToasts, dismissToast } from "../services/toastService.js";
62
- import { initAutoSave } from "../services/autoSaveService.js";
52
+ markAsSaved
53
+ } from '../stores/workflowStore.svelte.js';
54
+ import { globalSaveWorkflow, globalExportWorkflow } from '../services/globalSave.js';
55
+ import { apiToasts, dismissToast } from '../services/toastService.js';
56
+ import { initAutoSave } from '../services/autoSaveService.js';
57
+ import { getUiSettings, updateSettings } from '../stores/settingsStore.svelte.js';
63
58
  import {
64
- getUiSettings,
65
- updateSettings,
66
- } from "../stores/settingsStore.svelte.js";
67
- import { initializePortCompatibility, getPortCompatibilityChecker } from "../utils/connections.js";
68
- import { DEFAULT_PORT_CONFIG } from "../config/defaultPortConfig.js";
69
- import { workflowFormatRegistry } from "../registry/workflowFormatRegistry.js";
70
- import { logger } from "../utils/logger.js";
71
- import { validateWorkflowData } from "../utils/validation.js";
72
- import type { SettingsCategory } from "../types/settings.js";
59
+ initializePortCompatibility,
60
+ getPortCompatibilityChecker,
61
+ isPortCompatibilityInitialized
62
+ } from '../utils/connections.js';
63
+ import { DEFAULT_PORT_CONFIG } from '../config/defaultPortConfig.js';
64
+ import { workflowFormatRegistry } from '../registry/workflowFormatRegistry.js';
65
+ import { logger } from '../utils/logger.js';
66
+ import { validateWorkflowData } from '../utils/validation.js';
67
+ import type { SettingsCategory } from '../types/settings.js';
73
68
 
74
69
  /**
75
70
  * Configuration props for runtime customization
@@ -92,10 +87,7 @@
92
87
  /** Read-only mode */
93
88
  readOnly?: boolean;
94
89
  /** Node execution statuses */
95
- nodeStatuses?: Record<
96
- string,
97
- "pending" | "running" | "completed" | "error"
98
- >;
90
+ nodeStatuses?: Record<string, 'pending' | 'running' | 'completed' | 'error'>;
99
91
  /** Pipeline ID for fetching node execution info */
100
92
  pipelineId?: string;
101
93
  /** Custom navbar title */
@@ -105,7 +97,7 @@
105
97
  label: string;
106
98
  href: string;
107
99
  icon?: string;
108
- variant?: "primary" | "secondary" | "outline";
100
+ variant?: 'primary' | 'secondary' | 'outline';
109
101
  onclick?: (event: Event) => void;
110
102
  }>;
111
103
  /** Show settings gear icon in navbar */
@@ -130,13 +122,15 @@
130
122
  showSettingsResetButton?: boolean;
131
123
  /** Pluggable swap strategies — instance-scoped, checked in order */
132
124
  swapStrategies?: SwapStrategy[];
125
+ /** Additional JSON Schema properties to show in the Workflow Settings panel. Values are persisted in workflow.config. */
126
+ workflowSettingsSchema?: ConfigSchema;
133
127
  }
134
128
 
135
129
  let {
136
130
  workflow: initialWorkflow,
137
131
  nodes: propNodes,
138
- height = "100vh",
139
- width = "100%",
132
+ height = '100vh',
133
+ width = '100%',
140
134
  showNavbar = false,
141
135
  disableSidebar = false,
142
136
  lockWorkflow = false,
@@ -156,6 +150,7 @@
156
150
  showSettingsSyncButton,
157
151
  showSettingsResetButton,
158
152
  swapStrategies,
153
+ workflowSettingsSchema
159
154
  }: Props = $props();
160
155
 
161
156
  // svelte-ignore state_referenced_locally — feature flags don't change at runtime
@@ -163,9 +158,7 @@
163
158
 
164
159
  // Theme system — resolve named theme or custom object, inject CSS tokens from skin
165
160
  // Explicit prop wins; falls back to user's persisted theme preference from settings
166
- let resolvedTheme = $derived(
167
- resolveTheme(themeProp ?? getUiSettings().theme),
168
- );
161
+ let resolvedTheme = $derived(resolveTheme(themeProp ?? getUiSettings().theme));
169
162
  let themeConfig = $derived(resolvedTheme.config);
170
163
 
171
164
  // Inject skin tokens as a style tag so light/dark palettes can coexist.
@@ -176,19 +169,19 @@
176
169
  const skin = resolvedTheme.skin;
177
170
  const tokens = skin?.tokens;
178
171
  const darkTokens = skin?.darkTokens;
179
- if ((!tokens && !darkTokens) || typeof document === "undefined") return;
172
+ if ((!tokens && !darkTokens) || typeof document === 'undefined') return;
180
173
 
181
174
  const toRules = (dict: FlowDropSkinTokens) =>
182
175
  Object.entries(dict)
183
176
  .map(([k, v]) => ` --fd-${k}: ${v};`)
184
- .join("\n");
177
+ .join('\n');
185
178
 
186
- let css = "";
179
+ let css = '';
187
180
  if (tokens) css += `:root {\n${toRules(tokens)}\n}\n`;
188
181
  if (darkTokens) css += `[data-theme='dark'] {\n${toRules(darkTokens)}\n}\n`;
189
182
 
190
- const style = document.createElement("style");
191
- style.id = "fd-skin-tokens";
183
+ const style = document.createElement('style');
184
+ style.id = 'fd-skin-tokens';
192
185
  document.head.appendChild(style);
193
186
  style.textContent = css;
194
187
 
@@ -203,8 +196,8 @@
203
196
  }
204
197
  // Default workflow title logic
205
198
  const wfName = getWorkflowName();
206
- if (!wfName || wfName === "Untitled Workflow") {
207
- return "Workflow / New Workflow";
199
+ if (!wfName || wfName === 'Untitled Workflow') {
200
+ return 'Workflow / New Workflow';
208
201
  }
209
202
  return `Workflow / ${wfName}`;
210
203
  });
@@ -230,43 +223,64 @@
230
223
  let isWorkflowSettingsOpen = $state(false);
231
224
 
232
225
  // Node swap state
233
- let swapMode = $state<"idle" | "picking" | "mapping">("idle");
226
+ let swapMode = $state<'idle' | 'picking' | 'mapping'>('idle');
234
227
  let swapTargetMetadata = $state<NodeMetadata | null>(null);
235
228
  let swapInteractiveState = $state<InteractiveSwapState | null>(null);
236
229
 
230
+ // Built-in workflow settings field names — consumer schemas must not reuse these.
231
+ const WORKFLOW_SETTINGS_RESERVED = new Set(['name', 'description', 'format']);
232
+
237
233
  // Workflow configuration schema (derived to pick up dynamic format options)
238
- let workflowConfigSchema: ConfigSchema = $derived({
239
- type: "object" as const,
240
- properties: {
241
- name: {
242
- type: "string",
243
- title: "Workflow Name",
244
- description: "The name of the workflow",
245
- default: "",
246
- },
247
- description: {
248
- type: "string",
249
- title: "Description",
250
- description: "A description of the workflow",
251
- format: "multiline",
252
- default: "",
253
- },
254
- format: {
255
- type: "string",
256
- title: "Workflow Format",
257
- description: "The specification format for this workflow",
258
- oneOf: workflowFormatRegistry.getOneOfOptions(),
259
- default: "flowdrop",
234
+ let workflowConfigSchema: ConfigSchema = $derived.by(() => {
235
+ const extraProps = Object.fromEntries(
236
+ Object.entries(workflowSettingsSchema?.properties ?? {}).filter(([k]) => {
237
+ if (WORKFLOW_SETTINGS_RESERVED.has(k)) {
238
+ logger.warn(
239
+ `workflowSettingsSchema: property "${k}" is reserved and will be ignored. Choose a different key.`
240
+ );
241
+ return false;
242
+ }
243
+ return true;
244
+ })
245
+ );
246
+ const extraRequired = (workflowSettingsSchema?.required ?? []).filter(
247
+ (k) => !WORKFLOW_SETTINGS_RESERVED.has(k)
248
+ );
249
+ return {
250
+ type: 'object' as const,
251
+ properties: {
252
+ name: {
253
+ type: 'string',
254
+ title: 'Workflow Name',
255
+ description: 'The name of the workflow',
256
+ default: ''
257
+ },
258
+ description: {
259
+ type: 'string',
260
+ title: 'Description',
261
+ description: 'A description of the workflow',
262
+ format: 'multiline',
263
+ default: ''
264
+ },
265
+ format: {
266
+ type: 'string',
267
+ title: 'Workflow Format',
268
+ description: 'The specification format for this workflow',
269
+ oneOf: workflowFormatRegistry.getOneOfOptions(),
270
+ default: 'flowdrop'
271
+ },
272
+ ...extraProps
260
273
  },
261
- },
262
- required: ["name"],
274
+ required: ['name', ...extraRequired]
275
+ };
263
276
  });
264
277
 
265
278
  // Workflow configuration values
266
279
  let workflowConfigValues = $derived({
267
- name: getWorkflowName() || "",
268
- description: getWorkflowStore()?.description || "",
269
- format: getWorkflowStore()?.metadata?.format || "flowdrop",
280
+ name: getWorkflowName() || '',
281
+ description: getWorkflowStore()?.description || '',
282
+ format: getWorkflowStore()?.metadata?.format || 'flowdrop',
283
+ ...(getWorkflowStore()?.config ?? {})
270
284
  });
271
285
 
272
286
  // Get the current node from the workflow store
@@ -291,18 +305,14 @@
291
305
  // Merge format-provided nodes with prop nodes (deduplicate by ID, props take priority)
292
306
  const formatNodes = workflowFormatRegistry.getAllFormatNodes();
293
307
  const existingIds = new Set(propNodes.map((n) => n.id));
294
- const uniqueFormatNodes = formatNodes.filter(
295
- (n) => !existingIds.has(n.id),
296
- );
308
+ const uniqueFormatNodes = formatNodes.filter((n) => !existingIds.has(n.id));
297
309
  nodes = [...propNodes, ...uniqueFormatNodes];
298
310
  nodeTypesLoading = false;
299
311
  return;
300
312
  }
301
313
 
302
314
  // Show loading toast (if toasts are enabled)
303
- const loadingToast = features.showToasts
304
- ? apiToasts.loading("Loading node types")
305
- : null;
315
+ const loadingToast = features.showToasts ? apiToasts.loading('Loading node types') : null;
306
316
  try {
307
317
  error = null;
308
318
 
@@ -317,9 +327,7 @@
317
327
  // Merge format-provided nodes with API nodes (deduplicate by ID, API takes priority)
318
328
  const formatNodes = workflowFormatRegistry.getAllFormatNodes();
319
329
  const existingIds = new Set(fetchedNodes.map((n) => n.id));
320
- const uniqueFormatNodes = formatNodes.filter(
321
- (n) => !existingIds.has(n.id),
322
- );
330
+ const uniqueFormatNodes = formatNodes.filter((n) => !existingIds.has(n.id));
323
331
  nodes = [...fetchedNodes, ...uniqueFormatNodes];
324
332
  error = null;
325
333
  nodeTypesLoading = false;
@@ -334,13 +342,13 @@
334
342
  dismissToast(loadingToast);
335
343
  }
336
344
 
337
- const errorMessage = err instanceof Error ? err.message : "Unknown error";
345
+ const errorMessage = err instanceof Error ? err.message : 'Unknown error';
338
346
 
339
347
  // Notify parent via event handler
340
348
  if (eventHandlers?.onApiError) {
341
349
  const suppressToast = eventHandlers.onApiError(
342
350
  err instanceof Error ? err : new Error(errorMessage),
343
- "fetchNodes",
351
+ 'fetchNodes'
344
352
  );
345
353
  if (suppressToast) {
346
354
  // Parent handled the error, keep nodes empty
@@ -353,7 +361,7 @@
353
361
  // Show error and set empty nodes array (no fallback to sample data)
354
362
  error = `API Error: ${errorMessage}. No node types available.`;
355
363
  if (features.showToasts) {
356
- apiToasts.error("Load node types", errorMessage);
364
+ apiToasts.error('Load node types', errorMessage);
357
365
  }
358
366
 
359
367
  // Set empty nodes array instead of fallback data
@@ -374,22 +382,19 @@
374
382
  */
375
383
  async function testApiConnection(): Promise<void> {
376
384
  try {
377
- const baseUrl = endpointConfig?.baseUrl || apiBaseUrl || "/api/flowdrop";
385
+ const baseUrl = endpointConfig?.baseUrl || apiBaseUrl || '/api/flowdrop';
378
386
  const testUrl = `${baseUrl}/nodes`;
379
387
 
380
388
  const response = await fetch(testUrl);
381
389
  const data = await response.json();
382
390
 
383
391
  if (response.ok && data.success) {
384
- apiToasts.success("API connection test", "Connection successful");
392
+ apiToasts.success('API connection test', 'Connection successful');
385
393
  } else {
386
- apiToasts.error("API connection test", "Connection failed");
394
+ apiToasts.error('API connection test', 'Connection failed');
387
395
  }
388
396
  } catch (err) {
389
- apiToasts.error(
390
- "API connection test",
391
- err instanceof Error ? err.message : "Unknown error",
392
- );
397
+ apiToasts.error('API connection test', err instanceof Error ? err.message : 'Unknown error');
393
398
  }
394
399
  }
395
400
 
@@ -405,16 +410,13 @@
405
410
 
406
411
  // Create enhanced API client with authProvider support if provided
407
412
  if (authProvider) {
408
- apiClient = new EnhancedFlowDropApiClient(
409
- propEndpointConfig,
410
- authProvider,
411
- );
413
+ apiClient = new EnhancedFlowDropApiClient(propEndpointConfig, authProvider);
412
414
  }
413
415
  return;
414
416
  }
415
417
 
416
418
  // Second priority: Check if endpoint config is already set (e.g., by parent layout)
417
- const { getEndpointConfig } = await import("../services/api.js");
419
+ const { getEndpointConfig } = await import('../services/api.js');
418
420
  const existingConfig = getEndpointConfig();
419
421
 
420
422
  // If config already exists and no override provided, use existing
@@ -429,19 +431,19 @@
429
431
  }
430
432
 
431
433
  // Third priority: Use provided apiBaseUrl or default
432
- const baseUrl = apiBaseUrl || "/api/flowdrop";
434
+ const baseUrl = apiBaseUrl || '/api/flowdrop';
433
435
 
434
436
  const config = createEndpointConfig(baseUrl, {
435
437
  auth: {
436
- type: "none", // No authentication for now
438
+ type: 'none' // No authentication for now
437
439
  },
438
440
  timeout: 10000, // 10 second timeout
439
441
  retry: {
440
442
  enabled: true,
441
443
  maxAttempts: 2,
442
444
  delay: 1000,
443
- backoff: "exponential",
444
- },
445
+ backoff: 'exponential'
446
+ }
445
447
  });
446
448
 
447
449
  setEndpointConfig(config);
@@ -466,7 +468,7 @@
466
468
  selectedNodeId = node.id;
467
469
  isConfigSidebarOpen = true;
468
470
  // Reset swap state when switching nodes
469
- swapMode = "idle";
471
+ swapMode = 'idle';
470
472
  swapTargetMetadata = null;
471
473
  swapInteractiveState = null;
472
474
  }
@@ -475,7 +477,7 @@
475
477
  isConfigSidebarOpen = false;
476
478
  selectedNodeId = null;
477
479
  // Reset swap state when closing
478
- swapMode = "idle";
480
+ swapMode = 'idle';
479
481
  swapTargetMetadata = null;
480
482
  swapInteractiveState = null;
481
483
  }
@@ -495,7 +497,7 @@
495
497
  * Start swap mode — transitions the right sidebar to the node picker
496
498
  */
497
499
  function startSwap(): void {
498
- swapMode = "picking";
500
+ swapMode = 'picking';
499
501
  swapTargetMetadata = null;
500
502
  swapInteractiveState = null;
501
503
  }
@@ -517,24 +519,21 @@
517
519
  }
518
520
 
519
521
  // Get port compatibility checker (may be null if not initialized)
520
- let checker: import("../utils/connections.js").PortCompatibilityChecker | null = null;
522
+ let checker: import('../utils/connections.js').PortCompatibilityChecker | null = null;
521
523
  try {
522
524
  checker = getPortCompatibilityChecker();
523
525
  } catch {
524
526
  // Checker not initialized — computeSwapPreview will use exact dataType matching
525
527
  }
526
528
 
527
- const interactive = computeInteractiveState(
528
- node,
529
- metadata,
530
- wf.edges,
531
- wf.nodes,
532
- { checker, strategies: swapStrategies },
533
- );
529
+ const interactive = computeInteractiveState(node, metadata, wf.edges, wf.nodes, {
530
+ checker,
531
+ strategies: swapStrategies
532
+ });
534
533
 
535
534
  swapTargetMetadata = metadata;
536
535
  swapInteractiveState = interactive;
537
- swapMode = "mapping";
536
+ swapMode = 'mapping';
538
537
  }
539
538
 
540
539
  /**
@@ -554,18 +553,12 @@
554
553
  const preview = buildSwapPreviewFromState(state, wf.edges);
555
554
 
556
555
  // Execute the swap
557
- const result = executeSwap(
558
- state.oldNode,
559
- state.newMetadata,
560
- preview,
561
- wf.nodes,
562
- wf.edges,
563
- );
556
+ const result = executeSwap(state.oldNode, state.newMetadata, preview, wf.nodes, wf.edges);
564
557
 
565
558
  // Post-swap validation
566
559
  const validation = validateSwapResult(result);
567
560
  if (!validation.valid) {
568
- logger.error("Swap validation failed:", validation.error);
561
+ logger.error('Swap validation failed:', validation.error);
569
562
  return;
570
563
  }
571
564
 
@@ -576,7 +569,7 @@
576
569
  newMetadata: state.newMetadata,
577
570
  preview,
578
571
  portOverrides: [],
579
- configOverrides: [],
572
+ configOverrides: []
580
573
  };
581
574
  const shouldProceed = await eventHandlers.onBeforeSwap(swapEventCtx);
582
575
  if (shouldProceed === false) return;
@@ -586,7 +579,7 @@
586
579
  workflowActions.swapNode({
587
580
  nodes: result.updatedNodes,
588
581
  edges: result.updatedEdges,
589
- description: `Swap node: ${oldLabel} → ${newLabel}`,
582
+ description: `Swap node: ${oldLabel} → ${newLabel}`
590
583
  });
591
584
 
592
585
  // onAfterSwap hook (fire-and-forget — swap is already applied)
@@ -594,7 +587,7 @@
594
587
  try {
595
588
  eventHandlers.onAfterSwap(result, state.oldNode, state.newNodeId);
596
589
  } catch (err) {
597
- logger.error("onAfterSwap hook error:", err);
590
+ logger.error('onAfterSwap hook error:', err);
598
591
  }
599
592
  }
600
593
 
@@ -603,7 +596,7 @@
603
596
  selectedNodeId = newNodeId;
604
597
 
605
598
  // Reset swap state
606
- swapMode = "idle";
599
+ swapMode = 'idle';
607
600
  swapTargetMetadata = null;
608
601
  swapInteractiveState = null;
609
602
 
@@ -624,7 +617,7 @@
624
617
  * Cancel swap and return to normal config view
625
618
  */
626
619
  function cancelSwap(): void {
627
- swapMode = "idle";
620
+ swapMode = 'idle';
628
621
  swapTargetMetadata = null;
629
622
  swapInteractiveState = null;
630
623
  }
@@ -632,14 +625,12 @@
632
625
  /**
633
626
  * Handle workflow configuration save
634
627
  */
635
- async function handleWorkflowSave(
636
- config: Record<string, unknown>,
637
- ): Promise<void> {
628
+ async function handleWorkflowSave(config: Record<string, unknown>): Promise<void> {
638
629
  // Update the workflow store
639
630
  if (getWorkflowStore()) {
640
631
  workflowActions.batchUpdate({
641
632
  name: config.name as string | undefined,
642
- description: config.description as string | undefined,
633
+ description: config.description as string | undefined
643
634
  });
644
635
  }
645
636
 
@@ -650,7 +641,7 @@
650
641
  try {
651
642
  await saveWorkflow();
652
643
  } catch (error) {
653
- logger.error("Failed to save workflow to backend:", error);
644
+ logger.error('Failed to save workflow to backend:', error);
654
645
  // Note: We don't throw the error here to avoid breaking the UI flow
655
646
  // The user can still manually save via the main Save button if needed
656
647
  }
@@ -667,7 +658,7 @@
667
658
  apiClient: apiClient ?? undefined,
668
659
  eventHandlers,
669
660
  features,
670
- onMarkAsSaved: markAsSaved,
661
+ onMarkAsSaved: markAsSaved
671
662
  });
672
663
  }
673
664
 
@@ -691,45 +682,38 @@
691
682
  reader.onload = (event) => {
692
683
  try {
693
684
  const text = event.target?.result;
694
- if (typeof text !== "string") {
695
- throw new Error("Could not read file contents.");
685
+ if (typeof text !== 'string') {
686
+ throw new Error('Could not read file contents.');
696
687
  }
697
688
  const data = JSON.parse(text);
698
689
  const validation = validateWorkflowData(data);
699
690
  if (!validation.valid) {
700
691
  if (features.showToasts) {
701
- apiToasts.error(
702
- "Import workflow",
703
- validation.error ?? "Invalid workflow JSON",
704
- );
692
+ apiToasts.error('Import workflow', validation.error ?? 'Invalid workflow JSON');
705
693
  }
706
- logger.warn("Workflow import validation failed:", validation.error);
694
+ logger.warn('Workflow import validation failed:', validation.error);
707
695
  return;
708
696
  }
709
697
  workflowActions.initialize(data as Workflow);
710
698
  if (features.showToasts) {
711
- apiToasts.success(
712
- "Import workflow",
713
- "Workflow imported successfully",
714
- );
699
+ apiToasts.success('Import workflow', 'Workflow imported successfully');
715
700
  }
716
701
  if (eventHandlers?.onWorkflowLoad) {
717
702
  eventHandlers.onWorkflowLoad(data as Workflow);
718
703
  }
719
704
  } catch (error) {
720
- const errorObj =
721
- error instanceof Error ? error : new Error("Unknown error occurred");
722
- logger.error("Workflow import failed:", errorObj);
705
+ const errorObj = error instanceof Error ? error : new Error('Unknown error occurred');
706
+ logger.error('Workflow import failed:', errorObj);
723
707
  if (features.showToasts) {
724
- apiToasts.error("Import workflow", errorObj.message);
708
+ apiToasts.error('Import workflow', errorObj.message);
725
709
  }
726
710
  }
727
711
  };
728
712
  reader.onerror = () => {
729
- const message = "Failed to read the selected file.";
713
+ const message = 'Failed to read the selected file.';
730
714
  logger.error(message);
731
715
  if (features.showToasts) {
732
- apiToasts.error("Import workflow", message);
716
+ apiToasts.error('Import workflow', message);
733
717
  }
734
718
  };
735
719
  reader.readAsText(file);
@@ -745,15 +729,13 @@
745
729
  importWorkflow(file);
746
730
  }
747
731
  // Reset input so same file can be re-imported
748
- input.value = "";
732
+ input.value = '';
749
733
  }
750
734
 
751
735
  // Function to handle clicks outside the sidebar
752
736
  function handleCanvasClick(event: MouseEvent): void {
753
737
  // Check if the click is outside the right sidebar
754
- const rightSidebar = document.querySelector(
755
- ".flowdrop-main-layout__sidebar--right",
756
- );
738
+ const rightSidebar = document.querySelector('.flowdrop-main-layout__sidebar--right');
757
739
  if (rightSidebar && !rightSidebar.contains(event.target as Node)) {
758
740
  // Close sidebar when clicking outside of it
759
741
  if (isConfigSidebarOpen) {
@@ -770,7 +752,10 @@
770
752
 
771
753
  // Ensure port compatibility checker is initialized (needed for proximity connect, etc.)
772
754
  // mountFlowDropApp initializes this before mounting, but SvelteKit routes need it here.
773
- initializePortCompatibility(DEFAULT_PORT_CONFIG);
755
+ // Only initialize with defaults if not already set — preserves custom port configs.
756
+ if (!isPortCompatibilityInitialized()) {
757
+ initializePortCompatibility(DEFAULT_PORT_CONFIG);
758
+ }
774
759
 
775
760
  await fetchNodeTypes();
776
761
 
@@ -786,21 +771,21 @@
786
771
  // Initialize with a default empty workflow so the editor is functional
787
772
  // (e.g., drag-and-drop requires a non-null workflow in the store)
788
773
  const defaultWorkflow: Workflow = {
789
- id: "",
790
- name: "Untitled Workflow",
774
+ id: '',
775
+ name: 'Untitled Workflow',
791
776
  nodes: [],
792
777
  edges: [],
793
778
  metadata: {
794
- version: "1.0.0",
779
+ version: '1.0.0',
795
780
  format: DEFAULT_WORKFLOW_FORMAT,
796
781
  createdAt: new Date().toISOString(),
797
- updatedAt: new Date().toISOString(),
798
- },
782
+ updatedAt: new Date().toISOString()
783
+ }
799
784
  };
800
785
  workflowActions.initialize(defaultWorkflow);
801
786
  }
802
787
  } catch (error) {
803
- logger.error("Failed to initialize editor:", error);
788
+ logger.error('Failed to initialize editor:', error);
804
789
  }
805
790
  })();
806
791
 
@@ -809,10 +794,7 @@
809
794
  toggleWorkflowSettings();
810
795
  };
811
796
 
812
- window.addEventListener(
813
- "workflow-settings-toggle",
814
- handleWorkflowSettingsToggle,
815
- );
797
+ window.addEventListener('workflow-settings-toggle', handleWorkflowSettingsToggle);
816
798
 
817
799
  // Initialize auto-save based on user settings
818
800
  const cleanupAutoSave = initAutoSave({
@@ -821,18 +803,15 @@
821
803
  },
822
804
  onError: (error) => {
823
805
  // Don't show toast for auto-save errors to avoid noise
824
- logger.warn("Auto-save failed:", error);
806
+ logger.warn('Auto-save failed:', error);
825
807
  },
826
808
  onSuccess: () => {
827
- logger.debug("Auto-saved workflow");
828
- },
809
+ logger.debug('Auto-saved workflow');
810
+ }
829
811
  });
830
812
 
831
813
  return () => {
832
- window.removeEventListener(
833
- "workflow-settings-toggle",
834
- handleWorkflowSettingsToggle,
835
- );
814
+ window.removeEventListener('workflow-settings-toggle', handleWorkflowSettingsToggle);
836
815
  cleanupAutoSave();
837
816
  };
838
817
  });
@@ -842,9 +821,7 @@
842
821
  * Config panel always appears on the right side
843
822
  */
844
823
  const hasConfigPanelOpen = $derived(
845
- isWorkflowSettingsOpen ||
846
- !!selectedNodeForConfig ||
847
- swapMode !== "idle",
824
+ isWorkflowSettingsOpen || !!selectedNodeForConfig || swapMode !== 'idle'
848
825
  );
849
826
  const showRightPanel = $derived(!disableSidebar && hasConfigPanelOpen);
850
827
 
@@ -853,7 +830,7 @@
853
830
  * When collapsed, use 0; otherwise use user-configured width
854
831
  */
855
832
  const leftSidebarWidth = $derived(
856
- getUiSettings().sidebarCollapsed ? 0 : getUiSettings().sidebarWidth,
833
+ getUiSettings().sidebarCollapsed ? 0 : getUiSettings().sidebarWidth
857
834
  );
858
835
 
859
836
  /** Whether the sidebar is collapsed */
@@ -862,7 +839,7 @@
862
839
  /** Toggle sidebar collapsed state */
863
840
  function toggleSidebar(): void {
864
841
  updateSettings({
865
- ui: { sidebarCollapsed: !getUiSettings().sidebarCollapsed },
842
+ ui: { sidebarCollapsed: !getUiSettings().sidebarCollapsed }
866
843
  });
867
844
  }
868
845
 
@@ -875,16 +852,14 @@
875
852
  */
876
853
  function handleGlobalKeydown(event: KeyboardEvent): void {
877
854
  // Dead key on international keyboards — do not intercept
878
- if (event.key === "Dead") return;
855
+ if (event.key === 'Dead') return;
879
856
 
880
- if (event.key !== "`") return;
857
+ if (event.key !== '`') return;
881
858
 
882
859
  // Don't intercept when user is typing in an input, textarea, or contenteditable
883
860
  const target = event.target as HTMLElement;
884
861
  const isInputElement =
885
- target.tagName === "INPUT" ||
886
- target.tagName === "TEXTAREA" ||
887
- target.isContentEditable;
862
+ target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable;
888
863
 
889
864
  if (isInputElement) return;
890
865
 
@@ -893,24 +868,24 @@
893
868
  }
894
869
 
895
870
  function handleConsoleUIAction(action: UIAction): void {
896
- if (action.type === "open_config") {
871
+ if (action.type === 'open_config') {
897
872
  const wf = getWorkflowStore();
898
873
  if (!wf) return;
899
874
  const node = wf.nodes.find((n) => n.id === action.nodeId);
900
875
  if (node) openConfigSidebar(node);
901
- } else if (action.type === "select_node") {
876
+ } else if (action.type === 'select_node') {
902
877
  selectedNodeId = action.nodeId;
903
- } else if (action.type === "canvas_fit_view") {
878
+ } else if (action.type === 'canvas_fit_view') {
904
879
  workflowEditorRef?.canvasFitView();
905
- } else if (action.type === "canvas_zoom_in") {
880
+ } else if (action.type === 'canvas_zoom_in') {
906
881
  workflowEditorRef?.canvasZoomIn();
907
- } else if (action.type === "canvas_zoom_out") {
882
+ } else if (action.type === 'canvas_zoom_out') {
908
883
  workflowEditorRef?.canvasZoomOut();
909
- } else if (action.type === "canvas_zoom_to") {
884
+ } else if (action.type === 'canvas_zoom_to') {
910
885
  workflowEditorRef?.canvasZoomTo(action.level);
911
- } else if (action.type === "canvas_pan_to") {
886
+ } else if (action.type === 'canvas_pan_to') {
912
887
  workflowEditorRef?.canvasPanTo(action.position.x, action.position.y);
913
- } else if (action.type === "canvas_reset_view") {
888
+ } else if (action.type === 'canvas_reset_view') {
914
889
  workflowEditorRef?.canvasResetView();
915
890
  }
916
891
  }
@@ -923,13 +898,12 @@
923
898
  tick().then(() => {
924
899
  if (currentOpen) {
925
900
  // Console was open, now closing — focus the canvas
926
- const canvas = document.querySelector<HTMLElement>(".flowdrop-editor-main");
901
+ const canvas = document.querySelector<HTMLElement>('.flowdrop-editor-main');
927
902
  canvas?.focus();
928
903
  } else {
929
904
  // Console was closed, now opening — focus first focusable element inside console
930
- const consoleEl = document.querySelector<HTMLElement>(".command-console");
931
- const focusTarget =
932
- consoleEl?.querySelector<HTMLElement>("input, button, [tabindex]");
905
+ const consoleEl = document.querySelector<HTMLElement>('.command-console');
906
+ const focusTarget = consoleEl?.querySelector<HTMLElement>('input, button, [tabindex]');
933
907
  focusTarget?.focus();
934
908
  }
935
909
  });
@@ -940,10 +914,7 @@
940
914
 
941
915
  <svelte:head>
942
916
  <title>FlowDrop - Visual Workflow Manager</title>
943
- <meta
944
- name="description"
945
- content="A modern drag-and-drop workflow editor for LLM applications"
946
- />
917
+ <meta name="description" content="A modern drag-and-drop workflow editor for LLM applications" />
947
918
  </svelte:head>
948
919
 
949
920
  <!-- Hidden file input for workflow JSON import -->
@@ -983,45 +954,45 @@
983
954
  ? navbarActions
984
955
  : [
985
956
  {
986
- label: "Save",
987
- href: "#save",
988
- icon: "heroicons:document-arrow-down",
989
- variant: "primary",
957
+ label: 'Save',
958
+ href: '#save',
959
+ icon: 'heroicons:document-arrow-down',
960
+ variant: 'primary',
990
961
  onclick: (e) => {
991
962
  e.preventDefault();
992
963
  saveWorkflow();
993
- },
964
+ }
994
965
  },
995
966
  {
996
- label: "Export",
997
- href: "#export",
998
- icon: "heroicons:arrow-down-tray",
999
- variant: "outline",
967
+ label: 'Export',
968
+ href: '#export',
969
+ icon: 'heroicons:arrow-down-tray',
970
+ variant: 'outline',
1000
971
  onclick: (e) => {
1001
972
  e.preventDefault();
1002
973
  exportWorkflow();
1003
- },
974
+ }
1004
975
  },
1005
976
  {
1006
- label: "Import",
1007
- href: "#import",
1008
- icon: "heroicons:arrow-up-tray",
1009
- variant: "outline",
977
+ label: 'Import',
978
+ href: '#import',
979
+ icon: 'heroicons:arrow-up-tray',
980
+ variant: 'outline',
1010
981
  onclick: (e) => {
1011
982
  e.preventDefault();
1012
983
  fileInputRef?.click();
1013
- },
984
+ }
1014
985
  },
1015
986
  {
1016
- label: "Workflow Settings",
1017
- href: "#settings",
1018
- icon: "heroicons:cog-6-tooth",
1019
- variant: "outline",
987
+ label: 'Workflow Settings',
988
+ href: '#settings',
989
+ icon: 'heroicons:cog-6-tooth',
990
+ variant: 'outline',
1020
991
  onclick: (e) => {
1021
992
  e.preventDefault();
1022
993
  toggleWorkflowSettings();
1023
- },
1024
- },
994
+ }
995
+ }
1025
996
  ]}
1026
997
  showStatus={true}
1027
998
  {showSettings}
@@ -1037,23 +1008,31 @@
1037
1008
  {nodes}
1038
1009
  loading={nodeTypesLoading}
1039
1010
  activeFormat={getWorkflowFormat()}
1040
- categoriesDefaultOpen={themeConfig?.sidebar?.categoriesDefaultOpen ??
1041
- false}
1011
+ categoriesDefaultOpen={themeConfig?.sidebar?.categoriesDefaultOpen ?? false}
1042
1012
  />
1043
1013
  {/snippet}
1044
1014
 
1045
1015
  <!-- Right Sidebar: Configuration, Swap, or Workflow Settings -->
1046
1016
  {#snippet rightSidebar()}
1047
- {#if swapMode === "mapping" && swapInteractiveState && selectedNodeForConfig}
1048
- {@const swapChecker = (() => { try { return getPortCompatibilityChecker(); } catch { return null; } })()}
1017
+ {#if swapMode === 'mapping' && swapInteractiveState && selectedNodeForConfig}
1018
+ {@const swapChecker = (() => {
1019
+ try {
1020
+ return getPortCompatibilityChecker();
1021
+ } catch {
1022
+ return null;
1023
+ }
1024
+ })()}
1049
1025
  <SwapMappingEditor
1050
1026
  interactiveState={swapInteractiveState}
1051
1027
  checker={swapChecker}
1052
1028
  onConfirm={executeNodeSwap}
1053
1029
  onCancel={cancelSwap}
1054
- onBack={() => { swapMode = "picking"; swapInteractiveState = null; }}
1030
+ onBack={() => {
1031
+ swapMode = 'picking';
1032
+ swapInteractiveState = null;
1033
+ }}
1055
1034
  />
1056
- {:else if swapMode === "picking" && selectedNodeForConfig}
1035
+ {:else if swapMode === 'picking' && selectedNodeForConfig}
1057
1036
  <NodeSwapPicker
1058
1037
  currentNode={selectedNodeForConfig}
1059
1038
  availableNodes={nodes}
@@ -1067,13 +1046,13 @@
1067
1046
  id={getWorkflowStore()?.id}
1068
1047
  details={[
1069
1048
  {
1070
- label: "Nodes",
1071
- value: String(getWorkflowStore()?.nodes?.length ?? 0),
1049
+ label: 'Nodes',
1050
+ value: String(getWorkflowStore()?.nodes?.length ?? 0)
1072
1051
  },
1073
1052
  {
1074
- label: "Connections",
1075
- value: String(getWorkflowStore()?.edges?.length ?? 0),
1076
- },
1053
+ label: 'Connections',
1054
+ value: String(getWorkflowStore()?.edges?.length ?? 0)
1055
+ }
1077
1056
  ]}
1078
1057
  configTitle="Settings"
1079
1058
  onClose={() => (isWorkflowSettingsOpen = false)}
@@ -1087,36 +1066,33 @@
1087
1066
  // Sync workflow settings changes immediately on field blur
1088
1067
  const wf = getWorkflowStore();
1089
1068
  if (wf) {
1090
- const newFormat =
1091
- (config.format as string) || DEFAULT_WORKFLOW_FORMAT;
1092
- const currentFormat =
1093
- wf.metadata?.format || DEFAULT_WORKFLOW_FORMAT;
1069
+ const newFormat = (config.format as string) || DEFAULT_WORKFLOW_FORMAT;
1070
+ const currentFormat = wf.metadata?.format || DEFAULT_WORKFLOW_FORMAT;
1094
1071
 
1095
1072
  // Warn about incompatible nodes when format changes
1096
1073
  if (newFormat !== currentFormat) {
1097
1074
  const incompatibleNodes = wf.nodes?.filter((node) => {
1098
1075
  const formats = node.data?.metadata?.formats;
1099
- return (
1100
- formats &&
1101
- formats.length > 0 &&
1102
- !formats.includes(newFormat)
1103
- );
1076
+ return formats && formats.length > 0 && !formats.includes(newFormat);
1104
1077
  });
1105
1078
  if (incompatibleNodes && incompatibleNodes.length > 0) {
1106
1079
  logger.warn(
1107
1080
  `Format changed to '${newFormat}'. ${incompatibleNodes.length} node(s) are not compatible with this format and may not export correctly:`,
1108
- incompatibleNodes.map((n) => n.data?.label || n.type),
1081
+ incompatibleNodes.map((n) => n.data?.label || n.type)
1109
1082
  );
1110
1083
  }
1111
1084
  }
1112
1085
 
1086
+ // Extract built-in fields; everything else belongs in workflow.config
1087
+ const { name, description, format: _format, ...customConfig } = config;
1113
1088
  workflowActions.batchUpdate({
1114
- name: config.name as string,
1115
- description: config.description as string | undefined,
1089
+ name: name as string,
1090
+ description: description as string | undefined,
1116
1091
  metadata: {
1117
1092
  ...wf.metadata,
1118
- format: newFormat,
1093
+ format: newFormat
1119
1094
  },
1095
+ ...(workflowSettingsSchema && { config: customConfig as Record<string, unknown> })
1120
1096
  });
1121
1097
  }
1122
1098
  }}
@@ -1127,17 +1103,16 @@
1127
1103
  <ConfigPanel
1128
1104
  title={currentNode.data.label}
1129
1105
  id={currentNode.id}
1130
- description={currentNode.data.metadata?.description ||
1131
- "Node configuration"}
1106
+ description={currentNode.data.metadata?.description || 'Node configuration'}
1132
1107
  details={[
1133
1108
  {
1134
- label: "Type",
1135
- value: currentNode.data.metadata?.type || currentNode.type,
1109
+ label: 'Type',
1110
+ value: currentNode.data.metadata?.type || currentNode.type
1136
1111
  },
1137
1112
  {
1138
- label: "Category",
1139
- value: currentNode.data.metadata?.category || "general",
1140
- },
1113
+ label: 'Category',
1114
+ value: currentNode.data.metadata?.category || 'general'
1115
+ }
1141
1116
  ]}
1142
1117
  onClose={closeConfigSidebar}
1143
1118
  onSwap={!readOnly && !lockWorkflow && features.enableNodeSwap ? startSwap : undefined}
@@ -1154,20 +1129,20 @@
1154
1129
  // Build the updated node data
1155
1130
  const updatedData = {
1156
1131
  ...currentNode.data,
1157
- config: updatedConfig,
1132
+ config: updatedConfig
1158
1133
  };
1159
1134
 
1160
1135
  // Include UI extensions if provided
1161
1136
  if (uiExtensions) {
1162
1137
  updatedData.extensions = {
1163
1138
  ...currentNode.data.extensions,
1164
- ui: uiExtensions,
1139
+ ui: uiExtensions
1165
1140
  };
1166
1141
  }
1167
1142
 
1168
1143
  // Update the node in the workflow store
1169
1144
  const nodeUpdates: Record<string, unknown> = {
1170
- data: updatedData,
1145
+ data: updatedData
1171
1146
  };
1172
1147
 
1173
1148
  workflowActions.updateNode(selectedNodeId, nodeUpdates);
@@ -1190,24 +1165,39 @@
1190
1165
  <div class="bottom-panel-tabs">
1191
1166
  <div class="bottom-panel-tabs__bar">
1192
1167
  <button
1193
- class="bottom-panel-tabs__tab {getUiSettings().bottomPanelTab === 'console' ? 'bottom-panel-tabs__tab--active' : ''}"
1168
+ class="bottom-panel-tabs__tab {getUiSettings().bottomPanelTab === 'console'
1169
+ ? 'bottom-panel-tabs__tab--active'
1170
+ : ''}"
1194
1171
  onclick={() => updateSettings({ ui: { bottomPanelTab: 'console' } })}
1195
1172
  >
1196
1173
  Console
1197
1174
  </button>
1198
1175
  <button
1199
- class="bottom-panel-tabs__tab {getUiSettings().bottomPanelTab === 'chat' ? 'bottom-panel-tabs__tab--active' : ''}"
1176
+ class="bottom-panel-tabs__tab {getUiSettings().bottomPanelTab === 'chat'
1177
+ ? 'bottom-panel-tabs__tab--active'
1178
+ : ''}"
1200
1179
  onclick={() => updateSettings({ ui: { bottomPanelTab: 'chat' } })}
1201
1180
  >
1202
1181
  AI Chat
1203
1182
  </button>
1204
1183
  </div>
1205
1184
  <div class="bottom-panel-tabs__content">
1206
- <div class="bottom-panel-tabs__panel" style:display={getUiSettings().bottomPanelTab === 'console' ? 'contents' : 'none'}>
1185
+ <div
1186
+ class="bottom-panel-tabs__panel"
1187
+ style:display={getUiSettings().bottomPanelTab === 'console' ? 'contents' : 'none'}
1188
+ >
1207
1189
  <CommandConsole nodeTypes={nodes} onUIAction={handleConsoleUIAction} />
1208
1190
  </div>
1209
- <div class="bottom-panel-tabs__panel" style:display={getUiSettings().bottomPanelTab === 'chat' ? 'flex' : 'none'}>
1210
- <AIChatPanel nodeTypes={nodes} workflowId={getWorkflowStore()?.id} onUIAction={handleConsoleUIAction} endpointConfig={endpointConfig} />
1191
+ <div
1192
+ class="bottom-panel-tabs__panel"
1193
+ style:display={getUiSettings().bottomPanelTab === 'chat' ? 'flex' : 'none'}
1194
+ >
1195
+ <AIChatPanel
1196
+ nodeTypes={nodes}
1197
+ workflowId={getWorkflowStore()?.id}
1198
+ onUIAction={handleConsoleUIAction}
1199
+ {endpointConfig}
1200
+ />
1211
1201
  </div>
1212
1202
  </div>
1213
1203
  </div>
@@ -1216,19 +1206,11 @@
1216
1206
  <!-- Main Content: Workflow Editor with Error Status -->
1217
1207
  <!-- Status Display: aria-live announces API errors dynamically without requiring focus -->
1218
1208
  {#if error}
1219
- <div
1220
- class="flowdrop-status flowdrop-status--error"
1221
- aria-live="polite"
1222
- aria-atomic="true"
1223
- >
1209
+ <div class="flowdrop-status flowdrop-status--error" aria-live="polite" aria-atomic="true">
1224
1210
  <div class="flowdrop-status__content">
1225
1211
  <div class="flowdrop-flex flowdrop-gap--3">
1226
- <div
1227
- class="flowdrop-status__indicator flowdrop-status__indicator--error"
1228
- ></div>
1229
- <span class="flowdrop-text--sm flowdrop-font--medium"
1230
- >Error: {error}</span
1231
- >
1212
+ <div class="flowdrop-status__indicator flowdrop-status__indicator--error"></div>
1213
+ <span class="flowdrop-text--sm flowdrop-font--medium">Error: {error}</span>
1232
1214
  </div>
1233
1215
  <div class="flowdrop-flex flowdrop-gap--2">
1234
1216
  <button
@@ -1241,8 +1223,8 @@
1241
1223
  <button
1242
1224
  class="flowdrop-btn flowdrop-btn--sm flowdrop-btn--outline"
1243
1225
  onclick={() => {
1244
- const defaultUrl = "/api/flowdrop";
1245
- const newUrl = prompt("Enter Backend API URL:", defaultUrl);
1226
+ const defaultUrl = '/api/flowdrop';
1227
+ const newUrl = prompt('Enter Backend API URL:', defaultUrl);
1246
1228
  if (newUrl) {
1247
1229
  const endpointConfig = createEndpointConfig(newUrl);
1248
1230
  setEndpointConfig(endpointConfig);
@@ -1277,11 +1259,9 @@
1277
1259
  <div
1278
1260
  class="flowdrop-editor-main"
1279
1261
  class:pipeline-view={!!pipelineId}
1280
- style="--fd-canvas-left-offset: {!disableSidebar
1281
- ? leftSidebarWidth + 'px'
1282
- : '0px'}"
1262
+ style="--fd-canvas-left-offset: {!disableSidebar ? leftSidebarWidth + 'px' : '0px'}"
1283
1263
  onclick={handleCanvasClick}
1284
- onkeydown={(e) => e.key === "Escape" && closeConfigSidebar()}
1264
+ onkeydown={(e) => e.key === 'Escape' && closeConfigSidebar()}
1285
1265
  role="region"
1286
1266
  aria-label="Workflow canvas"
1287
1267
  >
@@ -1290,12 +1270,10 @@
1290
1270
  <button
1291
1271
  class="flowdrop-sidebar-fab"
1292
1272
  onclick={toggleSidebar}
1293
- aria-label={isSidebarCollapsed
1294
- ? "Expand sidebar"
1295
- : "Collapse sidebar"}
1296
- title={isSidebarCollapsed ? "Expand sidebar" : "Collapse sidebar"}
1273
+ aria-label={isSidebarCollapsed ? 'Expand sidebar' : 'Collapse sidebar'}
1274
+ title={isSidebarCollapsed ? 'Expand sidebar' : 'Collapse sidebar'}
1297
1275
  >
1298
- <Icon icon={isSidebarCollapsed ? "mdi:menu" : "mdi:menu-open"} />
1276
+ <Icon icon={isSidebarCollapsed ? 'mdi:menu' : 'mdi:menu-open'} />
1299
1277
  </button>
1300
1278
  {/if}
1301
1279
 
@@ -1306,7 +1284,7 @@
1306
1284
  {width}
1307
1285
  endpointConfig={endpointConfig ?? undefined}
1308
1286
  {isConfigSidebarOpen}
1309
- selectedNodeForConfig={selectedNodeForConfig}
1287
+ {selectedNodeForConfig}
1310
1288
  {openConfigSidebar}
1311
1289
  {closeConfigSidebar}
1312
1290
  {lockWorkflow}
@@ -1520,5 +1498,4 @@
1520
1498
  overflow: hidden;
1521
1499
  flex-direction: column;
1522
1500
  }
1523
-
1524
1501
  </style>