@stigmer/react 0.5.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (625) hide show
  1. package/activity/group-activity.d.ts +13 -0
  2. package/activity/group-activity.d.ts.map +1 -0
  3. package/activity/group-activity.js +54 -0
  4. package/activity/group-activity.js.map +1 -0
  5. package/activity/index.d.ts +4 -0
  6. package/activity/index.d.ts.map +1 -0
  7. package/activity/index.js +3 -0
  8. package/activity/index.js.map +1 -0
  9. package/activity/types.d.ts +34 -0
  10. package/activity/types.d.ts.map +1 -0
  11. package/activity/types.js +2 -0
  12. package/activity/types.js.map +1 -0
  13. package/activity/useRecentActivity.d.ts +35 -0
  14. package/activity/useRecentActivity.d.ts.map +1 -0
  15. package/activity/useRecentActivity.js +73 -0
  16. package/activity/useRecentActivity.js.map +1 -0
  17. package/agent/AgentPicker.d.ts.map +1 -1
  18. package/agent/AgentPicker.js +4 -2
  19. package/agent/AgentPicker.js.map +1 -1
  20. package/billing/BillingSection.d.ts.map +1 -1
  21. package/billing/BillingSection.js +1 -1
  22. package/billing/BillingSection.js.map +1 -1
  23. package/composer/ComposerToolbar.d.ts +5 -1
  24. package/composer/ComposerToolbar.d.ts.map +1 -1
  25. package/composer/ComposerToolbar.js +4 -3
  26. package/composer/ComposerToolbar.js.map +1 -1
  27. package/composer/InteractionModePicker.d.ts +40 -0
  28. package/composer/InteractionModePicker.d.ts.map +1 -0
  29. package/composer/InteractionModePicker.js +76 -0
  30. package/composer/InteractionModePicker.js.map +1 -0
  31. package/composer/SessionComposer.d.ts +53 -64
  32. package/composer/SessionComposer.d.ts.map +1 -1
  33. package/composer/SessionComposer.js +20 -8
  34. package/composer/SessionComposer.js.map +1 -1
  35. package/composer/__tests__/SessionComposer-memo.test.js +10 -5
  36. package/composer/__tests__/SessionComposer-memo.test.js.map +1 -1
  37. package/composer/index.d.ts +3 -1
  38. package/composer/index.d.ts.map +1 -1
  39. package/composer/index.js +1 -0
  40. package/composer/index.js.map +1 -1
  41. package/dashboard/DashboardFailedRuns.d.ts +19 -0
  42. package/dashboard/DashboardFailedRuns.d.ts.map +1 -0
  43. package/dashboard/DashboardFailedRuns.js +35 -0
  44. package/dashboard/DashboardFailedRuns.js.map +1 -0
  45. package/dashboard/DashboardKPICards.d.ts +19 -0
  46. package/dashboard/DashboardKPICards.d.ts.map +1 -0
  47. package/dashboard/DashboardKPICards.js +80 -0
  48. package/dashboard/DashboardKPICards.js.map +1 -0
  49. package/dashboard/OperationalDashboard.d.ts +37 -0
  50. package/dashboard/OperationalDashboard.d.ts.map +1 -0
  51. package/dashboard/OperationalDashboard.js +48 -0
  52. package/dashboard/OperationalDashboard.js.map +1 -0
  53. package/dashboard/index.d.ts +8 -0
  54. package/dashboard/index.d.ts.map +1 -0
  55. package/dashboard/index.js +9 -0
  56. package/dashboard/index.js.map +1 -0
  57. package/dashboard/types.d.ts +49 -0
  58. package/dashboard/types.d.ts.map +1 -0
  59. package/dashboard/types.js +2 -0
  60. package/dashboard/types.js.map +1 -0
  61. package/dashboard/useAgentExecutionSummary.d.ts +33 -0
  62. package/dashboard/useAgentExecutionSummary.d.ts.map +1 -0
  63. package/dashboard/useAgentExecutionSummary.js +32 -0
  64. package/dashboard/useAgentExecutionSummary.js.map +1 -0
  65. package/dashboard/useDashboardFailedRuns.d.ts +18 -0
  66. package/dashboard/useDashboardFailedRuns.d.ts.map +1 -0
  67. package/dashboard/useDashboardFailedRuns.js +86 -0
  68. package/dashboard/useDashboardFailedRuns.js.map +1 -0
  69. package/dashboard/useDashboardSummary.d.ts +32 -0
  70. package/dashboard/useDashboardSummary.d.ts.map +1 -0
  71. package/dashboard/useDashboardSummary.js +67 -0
  72. package/dashboard/useDashboardSummary.js.map +1 -0
  73. package/execution/ContextGauge.d.ts +45 -0
  74. package/execution/ContextGauge.d.ts.map +1 -0
  75. package/execution/ContextGauge.js +82 -0
  76. package/execution/ContextGauge.js.map +1 -0
  77. package/execution/InteractionModeBadge.d.ts +24 -0
  78. package/execution/InteractionModeBadge.d.ts.map +1 -0
  79. package/execution/InteractionModeBadge.js +29 -0
  80. package/execution/InteractionModeBadge.js.map +1 -0
  81. package/execution/MessageThread.d.ts +33 -3
  82. package/execution/MessageThread.d.ts.map +1 -1
  83. package/execution/MessageThread.js +51 -9
  84. package/execution/MessageThread.js.map +1 -1
  85. package/execution/PlanCompletionCard.d.ts +23 -0
  86. package/execution/PlanCompletionCard.d.ts.map +1 -0
  87. package/execution/PlanCompletionCard.js +28 -0
  88. package/execution/PlanCompletionCard.js.map +1 -0
  89. package/execution/SummarizationBadge.d.ts +30 -0
  90. package/execution/SummarizationBadge.d.ts.map +1 -0
  91. package/execution/SummarizationBadge.js +61 -0
  92. package/execution/SummarizationBadge.js.map +1 -0
  93. package/execution/SummarizationCard.d.ts +27 -0
  94. package/execution/SummarizationCard.d.ts.map +1 -0
  95. package/execution/SummarizationCard.js +47 -0
  96. package/execution/SummarizationCard.js.map +1 -0
  97. package/execution/__tests__/PlanCompletionCard.test.d.ts +2 -0
  98. package/execution/__tests__/PlanCompletionCard.test.d.ts.map +1 -0
  99. package/execution/__tests__/PlanCompletionCard.test.js +53 -0
  100. package/execution/__tests__/PlanCompletionCard.test.js.map +1 -0
  101. package/execution/__tests__/buildThreadItems-plan-completion.test.d.ts +2 -0
  102. package/execution/__tests__/buildThreadItems-plan-completion.test.d.ts.map +1 -0
  103. package/execution/__tests__/buildThreadItems-plan-completion.test.js +137 -0
  104. package/execution/__tests__/buildThreadItems-plan-completion.test.js.map +1 -0
  105. package/execution/__tests__/useContextWindow.test.d.ts +2 -0
  106. package/execution/__tests__/useContextWindow.test.d.ts.map +1 -0
  107. package/execution/__tests__/useContextWindow.test.js +121 -0
  108. package/execution/__tests__/useContextWindow.test.js.map +1 -0
  109. package/execution/index.d.ts +12 -0
  110. package/execution/index.d.ts.map +1 -1
  111. package/execution/index.js +6 -0
  112. package/execution/index.js.map +1 -1
  113. package/execution/useContextWindow.d.ts +71 -0
  114. package/execution/useContextWindow.d.ts.map +1 -0
  115. package/execution/useContextWindow.js +91 -0
  116. package/execution/useContextWindow.js.map +1 -0
  117. package/execution/useCreateAgentExecution.d.ts +9 -0
  118. package/execution/useCreateAgentExecution.d.ts.map +1 -1
  119. package/execution/useCreateAgentExecution.js +15 -3
  120. package/execution/useCreateAgentExecution.js.map +1 -1
  121. package/index.d.ts +9 -4
  122. package/index.d.ts.map +1 -1
  123. package/index.js +12 -2
  124. package/index.js.map +1 -1
  125. package/internal/VirtualizedThread.d.ts +2 -1
  126. package/internal/VirtualizedThread.d.ts.map +1 -1
  127. package/internal/VirtualizedThread.js +3 -2
  128. package/internal/VirtualizedThread.js.map +1 -1
  129. package/internal/store/index.d.ts +1 -0
  130. package/internal/store/index.d.ts.map +1 -1
  131. package/internal/store/index.js +1 -0
  132. package/internal/store/index.js.map +1 -1
  133. package/internal/store/workflow-execution-event-store.d.ts +92 -0
  134. package/internal/store/workflow-execution-event-store.d.ts.map +1 -0
  135. package/internal/store/workflow-execution-event-store.js +298 -0
  136. package/internal/store/workflow-execution-event-store.js.map +1 -0
  137. package/library/ScopeToggle.d.ts +13 -9
  138. package/library/ScopeToggle.d.ts.map +1 -1
  139. package/library/ScopeToggle.js +43 -22
  140. package/library/ScopeToggle.js.map +1 -1
  141. package/library/VisibilityToggle.js +14 -5
  142. package/library/VisibilityToggle.js.map +1 -1
  143. package/library/index.d.ts +1 -0
  144. package/library/index.d.ts.map +1 -1
  145. package/library/index.js +1 -0
  146. package/library/index.js.map +1 -1
  147. package/library/useExportResource.d.ts +3 -2
  148. package/library/useExportResource.d.ts.map +1 -1
  149. package/library/useExportResource.js +11 -6
  150. package/library/useExportResource.js.map +1 -1
  151. package/mcp-server/McpServerDetailView.d.ts.map +1 -1
  152. package/mcp-server/McpServerDetailView.js +25 -13
  153. package/mcp-server/McpServerDetailView.js.map +1 -1
  154. package/mcp-server/McpServerPicker.d.ts.map +1 -1
  155. package/mcp-server/McpServerPicker.js +4 -2
  156. package/mcp-server/McpServerPicker.js.map +1 -1
  157. package/package.json +16 -5
  158. package/provider.d.ts.map +1 -1
  159. package/provider.js +164 -1
  160. package/provider.js.map +1 -1
  161. package/resource-detail/ResourceDetailShell.d.ts +1 -1
  162. package/resource-detail/ResourceDetailShell.d.ts.map +1 -1
  163. package/resource-detail/ResourceDetailShell.js +6 -6
  164. package/resource-detail/ResourceDetailShell.js.map +1 -1
  165. package/resource-detail/types.d.ts +23 -0
  166. package/resource-detail/types.d.ts.map +1 -1
  167. package/resource-detail/useDeleteResource.d.ts +1 -1
  168. package/resource-detail/useDeleteResource.d.ts.map +1 -1
  169. package/resource-detail/useDeleteResource.js +5 -0
  170. package/resource-detail/useDeleteResource.js.map +1 -1
  171. package/resource-workbench/components/ResourceWorkbench.d.ts.map +1 -1
  172. package/resource-workbench/components/ResourceWorkbench.js +2 -1
  173. package/resource-workbench/components/ResourceWorkbench.js.map +1 -1
  174. package/session/useNewSessionFlow.d.ts.map +1 -1
  175. package/session/useNewSessionFlow.js +1 -0
  176. package/session/useNewSessionFlow.js.map +1 -1
  177. package/session/useSessionConversation.d.ts +7 -0
  178. package/session/useSessionConversation.d.ts.map +1 -1
  179. package/session/useSessionConversation.js +1 -0
  180. package/session/useSessionConversation.js.map +1 -1
  181. package/session/useSessionPageFlow.d.ts.map +1 -1
  182. package/session/useSessionPageFlow.js +1 -0
  183. package/session/useSessionPageFlow.js.map +1 -1
  184. package/session/useSessionUsage.d.ts.map +1 -1
  185. package/session/useSessionUsage.js +65 -4
  186. package/session/useSessionUsage.js.map +1 -1
  187. package/settings/UsageSection.d.ts.map +1 -1
  188. package/settings/UsageSection.js +1 -4
  189. package/settings/UsageSection.js.map +1 -1
  190. package/skill/SkillPicker.d.ts.map +1 -1
  191. package/skill/SkillPicker.js +4 -2
  192. package/skill/SkillPicker.js.map +1 -1
  193. package/src/activity/group-activity.ts +65 -0
  194. package/src/activity/index.ts +13 -0
  195. package/src/activity/types.ts +35 -0
  196. package/src/activity/useRecentActivity.ts +131 -0
  197. package/src/agent/AgentPicker.tsx +6 -1
  198. package/src/billing/BillingSection.tsx +3 -2
  199. package/src/composer/ComposerToolbar.tsx +19 -1
  200. package/src/composer/InteractionModePicker.tsx +189 -0
  201. package/src/composer/SessionComposer.tsx +85 -8
  202. package/src/composer/__tests__/SessionComposer-memo.test.ts +11 -6
  203. package/src/composer/index.ts +7 -0
  204. package/src/dashboard/DashboardFailedRuns.tsx +109 -0
  205. package/src/dashboard/DashboardKPICards.tsx +128 -0
  206. package/src/dashboard/OperationalDashboard.tsx +96 -0
  207. package/src/dashboard/index.ts +37 -0
  208. package/src/dashboard/types.ts +50 -0
  209. package/src/dashboard/useAgentExecutionSummary.ts +71 -0
  210. package/src/dashboard/useDashboardFailedRuns.ts +122 -0
  211. package/src/dashboard/useDashboardSummary.ts +109 -0
  212. package/src/execution/ContextGauge.tsx +243 -0
  213. package/src/execution/InteractionModeBadge.tsx +70 -0
  214. package/src/execution/MessageThread.tsx +88 -3
  215. package/src/execution/PlanCompletionCard.tsx +105 -0
  216. package/src/execution/SummarizationBadge.tsx +188 -0
  217. package/src/execution/SummarizationCard.tsx +126 -0
  218. package/src/execution/__tests__/PlanCompletionCard.test.tsx +67 -0
  219. package/src/execution/__tests__/buildThreadItems-plan-completion.test.ts +197 -0
  220. package/src/execution/__tests__/useContextWindow.test.ts +167 -0
  221. package/src/execution/index.ts +22 -0
  222. package/src/execution/useContextWindow.ts +148 -0
  223. package/src/execution/useCreateAgentExecution.ts +26 -3
  224. package/src/index.ts +222 -0
  225. package/src/internal/VirtualizedThread.tsx +4 -1
  226. package/src/internal/store/index.ts +6 -0
  227. package/src/internal/store/workflow-execution-event-store.ts +391 -0
  228. package/src/library/ScopeToggle.tsx +88 -20
  229. package/src/library/VisibilityToggle.tsx +54 -13
  230. package/src/library/index.ts +2 -0
  231. package/src/library/useExportResource.ts +12 -9
  232. package/src/mcp-server/McpServerDetailView.tsx +80 -148
  233. package/src/mcp-server/McpServerPicker.tsx +6 -1
  234. package/src/provider.tsx +195 -8
  235. package/src/resource-detail/ResourceDetailShell.tsx +21 -4
  236. package/src/resource-detail/types.ts +25 -0
  237. package/src/resource-detail/useDeleteResource.ts +6 -1
  238. package/src/resource-workbench/components/ResourceWorkbench.tsx +4 -0
  239. package/src/session/useNewSessionFlow.ts +1 -0
  240. package/src/session/useSessionConversation.ts +8 -0
  241. package/src/session/useSessionPageFlow.ts +1 -0
  242. package/src/session/useSessionUsage.ts +72 -4
  243. package/src/settings/UsageSection.tsx +1 -9
  244. package/src/skill/SkillPicker.tsx +6 -1
  245. package/src/workflow/ApprovalFormBuilder.tsx +1017 -0
  246. package/src/workflow/BranchConditionBuilder.tsx +451 -0
  247. package/src/workflow/CanvasActionsContext.ts +12 -0
  248. package/src/workflow/CanvasContextMenu.tsx +364 -0
  249. package/src/workflow/CanvasTaskNode.tsx +372 -0
  250. package/src/workflow/CanvasTransitionEdge.tsx +122 -0
  251. package/src/workflow/CostByWorkflowChart.tsx +120 -0
  252. package/src/workflow/ExecutionSummaryWidget.tsx +194 -0
  253. package/src/workflow/ExecutionTrendChart.tsx +157 -0
  254. package/src/workflow/FailedRunsWidget.tsx +109 -0
  255. package/src/workflow/PendingApprovalsWidget.tsx +115 -0
  256. package/src/workflow/TaskConfigForm.tsx +618 -0
  257. package/src/workflow/TaskKindRegistryContext.ts +36 -0
  258. package/src/workflow/TaskPickerPopover.tsx +326 -0
  259. package/src/workflow/WorkflowArchitectDialog.tsx +505 -0
  260. package/src/workflow/WorkflowCanvasEditor.tsx +651 -0
  261. package/src/workflow/WorkflowCanvasInner.tsx +160 -0
  262. package/src/workflow/WorkflowDashboard.tsx +124 -0
  263. package/src/workflow/WorkflowDetailView.tsx +527 -0
  264. package/src/workflow/WorkflowEditorView.tsx +547 -0
  265. package/src/workflow/WorkflowExecutionApprovalCard.tsx +129 -0
  266. package/src/workflow/WorkflowExecutionArtifactPanel.tsx +112 -0
  267. package/src/workflow/WorkflowExecutionCostPanel.tsx +131 -0
  268. package/src/workflow/WorkflowExecutionHeader.tsx +194 -0
  269. package/src/workflow/WorkflowExecutionPhaseBadge.tsx +188 -0
  270. package/src/workflow/WorkflowExecutionTaskPanel.tsx +135 -0
  271. package/src/workflow/WorkflowExecutionTimeline.tsx +118 -0
  272. package/src/workflow/WorkflowExecutionTimelineEvent.tsx +488 -0
  273. package/src/workflow/WorkflowExecutionViewer.tsx +248 -0
  274. package/src/workflow/WorkflowInspectorPanel.tsx +568 -0
  275. package/src/workflow/WorkflowRefinePanel.tsx +411 -0
  276. package/src/workflow/WorkflowRepairCard.tsx +433 -0
  277. package/src/workflow/WorkflowRunDialog.tsx +220 -0
  278. package/src/workflow/WorkflowRunForm.tsx +245 -0
  279. package/src/workflow/WorkflowTaskList.tsx +177 -0
  280. package/src/workflow/WorkflowTaskPalette.tsx +248 -0
  281. package/src/workflow/WorkflowTopologyGraph.tsx +250 -0
  282. package/src/workflow/WorkflowYamlEditor.tsx +271 -0
  283. package/src/workflow/__tests__/starter-workflow-yaml.test.ts +57 -0
  284. package/src/workflow/canvas-constants.ts +87 -0
  285. package/src/workflow/canvas-icons.tsx +36 -0
  286. package/src/workflow/extract-workflow-yaml.ts +87 -0
  287. package/src/workflow/graph-commands.ts +675 -0
  288. package/src/workflow/index.ts +375 -0
  289. package/src/workflow/serialize-workflow-yaml.ts +546 -0
  290. package/src/workflow/starter-workflow-yaml.ts +29 -0
  291. package/src/workflow/types.ts +99 -0
  292. package/src/workflow/useCanvasKeyboardShortcuts.ts +134 -0
  293. package/src/workflow/useDiagnoseExecutionFlow.ts +378 -0
  294. package/src/workflow/useGraphHistory.ts +138 -0
  295. package/src/workflow/usePendingApprovals.ts +89 -0
  296. package/src/workflow/useRefineWorkflowFlow.ts +321 -0
  297. package/src/workflow/useResolveAgentExecutionSession.ts +57 -0
  298. package/src/workflow/useRunWorkflowFlow.ts +235 -0
  299. package/src/workflow/useTaskKindRegistry.ts +135 -0
  300. package/src/workflow/useWorkflow.ts +78 -0
  301. package/src/workflow/useWorkflowArchitectFlow.ts +303 -0
  302. package/src/workflow/useWorkflowCanvas.ts +882 -0
  303. package/src/workflow/useWorkflowCount.ts +66 -0
  304. package/src/workflow/useWorkflowDashboardSummary.ts +71 -0
  305. package/src/workflow/useWorkflowEditor.ts +106 -0
  306. package/src/workflow/useWorkflowExecution.ts +67 -0
  307. package/src/workflow/useWorkflowExecutionActions.ts +179 -0
  308. package/src/workflow/useWorkflowExecutionArtifacts.ts +57 -0
  309. package/src/workflow/useWorkflowExecutionEventLog.ts +111 -0
  310. package/src/workflow/useWorkflowExecutionEventStream.ts +244 -0
  311. package/src/workflow/useWorkflowExecutionList.ts +121 -0
  312. package/src/workflow/useWorkflowInstances.ts +62 -0
  313. package/src/workflow/useWorkflowList.ts +79 -0
  314. package/src/workflow/useWorkflowSave.ts +84 -0
  315. package/src/workflow/useWorkflowTopology.ts +229 -0
  316. package/src/workflow/useWorkflowValidation.ts +329 -0
  317. package/src/workflow/useWorkflowYaml.ts +49 -0
  318. package/src/workflow/workflow-graph-conversions.ts +796 -0
  319. package/src/workflow/workflow-graph-model.ts +83 -0
  320. package/src/workflow/workflow-yaml-diff.ts +132 -0
  321. package/styles.css +1 -1
  322. package/workflow/ApprovalFormBuilder.d.ts +24 -0
  323. package/workflow/ApprovalFormBuilder.d.ts.map +1 -0
  324. package/workflow/ApprovalFormBuilder.js +347 -0
  325. package/workflow/ApprovalFormBuilder.js.map +1 -0
  326. package/workflow/BranchConditionBuilder.d.ts +29 -0
  327. package/workflow/BranchConditionBuilder.d.ts.map +1 -0
  328. package/workflow/BranchConditionBuilder.js +170 -0
  329. package/workflow/BranchConditionBuilder.js.map +1 -0
  330. package/workflow/CanvasActionsContext.d.ts +8 -0
  331. package/workflow/CanvasActionsContext.d.ts.map +1 -0
  332. package/workflow/CanvasActionsContext.js +4 -0
  333. package/workflow/CanvasActionsContext.js.map +1 -0
  334. package/workflow/CanvasContextMenu.d.ts +59 -0
  335. package/workflow/CanvasContextMenu.d.ts.map +1 -0
  336. package/workflow/CanvasContextMenu.js +98 -0
  337. package/workflow/CanvasContextMenu.js.map +1 -0
  338. package/workflow/CanvasTaskNode.d.ts +21 -0
  339. package/workflow/CanvasTaskNode.d.ts.map +1 -0
  340. package/workflow/CanvasTaskNode.js +125 -0
  341. package/workflow/CanvasTaskNode.js.map +1 -0
  342. package/workflow/CanvasTransitionEdge.d.ts +24 -0
  343. package/workflow/CanvasTransitionEdge.d.ts.map +1 -0
  344. package/workflow/CanvasTransitionEdge.js +50 -0
  345. package/workflow/CanvasTransitionEdge.js.map +1 -0
  346. package/workflow/CostByWorkflowChart.d.ts +15 -0
  347. package/workflow/CostByWorkflowChart.d.ts.map +1 -0
  348. package/workflow/CostByWorkflowChart.js +45 -0
  349. package/workflow/CostByWorkflowChart.js.map +1 -0
  350. package/workflow/ExecutionSummaryWidget.d.ts +16 -0
  351. package/workflow/ExecutionSummaryWidget.d.ts.map +1 -0
  352. package/workflow/ExecutionSummaryWidget.js +93 -0
  353. package/workflow/ExecutionSummaryWidget.js.map +1 -0
  354. package/workflow/ExecutionTrendChart.d.ts +14 -0
  355. package/workflow/ExecutionTrendChart.d.ts.map +1 -0
  356. package/workflow/ExecutionTrendChart.js +67 -0
  357. package/workflow/ExecutionTrendChart.js.map +1 -0
  358. package/workflow/FailedRunsWidget.d.ts +19 -0
  359. package/workflow/FailedRunsWidget.d.ts.map +1 -0
  360. package/workflow/FailedRunsWidget.js +37 -0
  361. package/workflow/FailedRunsWidget.js.map +1 -0
  362. package/workflow/PendingApprovalsWidget.d.ts +19 -0
  363. package/workflow/PendingApprovalsWidget.d.ts.map +1 -0
  364. package/workflow/PendingApprovalsWidget.js +35 -0
  365. package/workflow/PendingApprovalsWidget.js.map +1 -0
  366. package/workflow/TaskConfigForm.d.ts +29 -0
  367. package/workflow/TaskConfigForm.d.ts.map +1 -0
  368. package/workflow/TaskConfigForm.js +230 -0
  369. package/workflow/TaskConfigForm.js.map +1 -0
  370. package/workflow/TaskKindRegistryContext.d.ts +24 -0
  371. package/workflow/TaskKindRegistryContext.d.ts.map +1 -0
  372. package/workflow/TaskKindRegistryContext.js +25 -0
  373. package/workflow/TaskKindRegistryContext.js.map +1 -0
  374. package/workflow/TaskPickerPopover.d.ts +33 -0
  375. package/workflow/TaskPickerPopover.d.ts.map +1 -0
  376. package/workflow/TaskPickerPopover.js +110 -0
  377. package/workflow/TaskPickerPopover.js.map +1 -0
  378. package/workflow/WorkflowArchitectDialog.d.ts +48 -0
  379. package/workflow/WorkflowArchitectDialog.d.ts.map +1 -0
  380. package/workflow/WorkflowArchitectDialog.js +129 -0
  381. package/workflow/WorkflowArchitectDialog.js.map +1 -0
  382. package/workflow/WorkflowCanvasEditor.d.ts +38 -0
  383. package/workflow/WorkflowCanvasEditor.d.ts.map +1 -0
  384. package/workflow/WorkflowCanvasEditor.js +287 -0
  385. package/workflow/WorkflowCanvasEditor.js.map +1 -0
  386. package/workflow/WorkflowCanvasInner.d.ts +32 -0
  387. package/workflow/WorkflowCanvasInner.d.ts.map +1 -0
  388. package/workflow/WorkflowCanvasInner.js +49 -0
  389. package/workflow/WorkflowCanvasInner.js.map +1 -0
  390. package/workflow/WorkflowDashboard.d.ts +35 -0
  391. package/workflow/WorkflowDashboard.d.ts.map +1 -0
  392. package/workflow/WorkflowDashboard.js +59 -0
  393. package/workflow/WorkflowDashboard.js.map +1 -0
  394. package/workflow/WorkflowDetailView.d.ts +63 -0
  395. package/workflow/WorkflowDetailView.d.ts.map +1 -0
  396. package/workflow/WorkflowDetailView.js +202 -0
  397. package/workflow/WorkflowDetailView.js.map +1 -0
  398. package/workflow/WorkflowEditorView.d.ts +43 -0
  399. package/workflow/WorkflowEditorView.d.ts.map +1 -0
  400. package/workflow/WorkflowEditorView.js +165 -0
  401. package/workflow/WorkflowEditorView.js.map +1 -0
  402. package/workflow/WorkflowExecutionApprovalCard.d.ts +27 -0
  403. package/workflow/WorkflowExecutionApprovalCard.d.ts.map +1 -0
  404. package/workflow/WorkflowExecutionApprovalCard.js +32 -0
  405. package/workflow/WorkflowExecutionApprovalCard.js.map +1 -0
  406. package/workflow/WorkflowExecutionArtifactPanel.d.ts +15 -0
  407. package/workflow/WorkflowExecutionArtifactPanel.d.ts.map +1 -0
  408. package/workflow/WorkflowExecutionArtifactPanel.js +53 -0
  409. package/workflow/WorkflowExecutionArtifactPanel.js.map +1 -0
  410. package/workflow/WorkflowExecutionCostPanel.d.ts +18 -0
  411. package/workflow/WorkflowExecutionCostPanel.d.ts.map +1 -0
  412. package/workflow/WorkflowExecutionCostPanel.js +44 -0
  413. package/workflow/WorkflowExecutionCostPanel.js.map +1 -0
  414. package/workflow/WorkflowExecutionHeader.d.ts +26 -0
  415. package/workflow/WorkflowExecutionHeader.d.ts.map +1 -0
  416. package/workflow/WorkflowExecutionHeader.js +68 -0
  417. package/workflow/WorkflowExecutionHeader.js.map +1 -0
  418. package/workflow/WorkflowExecutionPhaseBadge.d.ts +23 -0
  419. package/workflow/WorkflowExecutionPhaseBadge.d.ts.map +1 -0
  420. package/workflow/WorkflowExecutionPhaseBadge.js +99 -0
  421. package/workflow/WorkflowExecutionPhaseBadge.js.map +1 -0
  422. package/workflow/WorkflowExecutionTaskPanel.d.ts +24 -0
  423. package/workflow/WorkflowExecutionTaskPanel.d.ts.map +1 -0
  424. package/workflow/WorkflowExecutionTaskPanel.js +59 -0
  425. package/workflow/WorkflowExecutionTaskPanel.js.map +1 -0
  426. package/workflow/WorkflowExecutionTimeline.d.ts +27 -0
  427. package/workflow/WorkflowExecutionTimeline.d.ts.map +1 -0
  428. package/workflow/WorkflowExecutionTimeline.js +51 -0
  429. package/workflow/WorkflowExecutionTimeline.js.map +1 -0
  430. package/workflow/WorkflowExecutionTimelineEvent.d.ts +18 -0
  431. package/workflow/WorkflowExecutionTimelineEvent.d.ts.map +1 -0
  432. package/workflow/WorkflowExecutionTimelineEvent.js +210 -0
  433. package/workflow/WorkflowExecutionTimelineEvent.js.map +1 -0
  434. package/workflow/WorkflowExecutionViewer.d.ts +45 -0
  435. package/workflow/WorkflowExecutionViewer.d.ts.map +1 -0
  436. package/workflow/WorkflowExecutionViewer.js +75 -0
  437. package/workflow/WorkflowExecutionViewer.js.map +1 -0
  438. package/workflow/WorkflowInspectorPanel.d.ts +46 -0
  439. package/workflow/WorkflowInspectorPanel.d.ts.map +1 -0
  440. package/workflow/WorkflowInspectorPanel.js +152 -0
  441. package/workflow/WorkflowInspectorPanel.js.map +1 -0
  442. package/workflow/WorkflowRefinePanel.d.ts +30 -0
  443. package/workflow/WorkflowRefinePanel.d.ts.map +1 -0
  444. package/workflow/WorkflowRefinePanel.js +107 -0
  445. package/workflow/WorkflowRefinePanel.js.map +1 -0
  446. package/workflow/WorkflowRepairCard.d.ts +35 -0
  447. package/workflow/WorkflowRepairCard.d.ts.map +1 -0
  448. package/workflow/WorkflowRepairCard.js +113 -0
  449. package/workflow/WorkflowRepairCard.js.map +1 -0
  450. package/workflow/WorkflowRunDialog.d.ts +51 -0
  451. package/workflow/WorkflowRunDialog.d.ts.map +1 -0
  452. package/workflow/WorkflowRunDialog.js +75 -0
  453. package/workflow/WorkflowRunDialog.js.map +1 -0
  454. package/workflow/WorkflowRunForm.d.ts +62 -0
  455. package/workflow/WorkflowRunForm.d.ts.map +1 -0
  456. package/workflow/WorkflowRunForm.js +64 -0
  457. package/workflow/WorkflowRunForm.js.map +1 -0
  458. package/workflow/WorkflowTaskList.d.ts +25 -0
  459. package/workflow/WorkflowTaskList.d.ts.map +1 -0
  460. package/workflow/WorkflowTaskList.js +89 -0
  461. package/workflow/WorkflowTaskList.js.map +1 -0
  462. package/workflow/WorkflowTaskPalette.d.ts +22 -0
  463. package/workflow/WorkflowTaskPalette.d.ts.map +1 -0
  464. package/workflow/WorkflowTaskPalette.js +83 -0
  465. package/workflow/WorkflowTaskPalette.js.map +1 -0
  466. package/workflow/WorkflowTopologyGraph.d.ts +22 -0
  467. package/workflow/WorkflowTopologyGraph.d.ts.map +1 -0
  468. package/workflow/WorkflowTopologyGraph.js +123 -0
  469. package/workflow/WorkflowTopologyGraph.js.map +1 -0
  470. package/workflow/WorkflowYamlEditor.d.ts +43 -0
  471. package/workflow/WorkflowYamlEditor.d.ts.map +1 -0
  472. package/workflow/WorkflowYamlEditor.js +215 -0
  473. package/workflow/WorkflowYamlEditor.js.map +1 -0
  474. package/workflow/__tests__/starter-workflow-yaml.test.d.ts +2 -0
  475. package/workflow/__tests__/starter-workflow-yaml.test.d.ts.map +1 -0
  476. package/workflow/__tests__/starter-workflow-yaml.test.js +44 -0
  477. package/workflow/__tests__/starter-workflow-yaml.test.js.map +1 -0
  478. package/workflow/canvas-constants.d.ts +56 -0
  479. package/workflow/canvas-constants.d.ts.map +1 -0
  480. package/workflow/canvas-constants.js +74 -0
  481. package/workflow/canvas-constants.js.map +1 -0
  482. package/workflow/canvas-icons.d.ts +13 -0
  483. package/workflow/canvas-icons.d.ts.map +1 -0
  484. package/workflow/canvas-icons.js +21 -0
  485. package/workflow/canvas-icons.js.map +1 -0
  486. package/workflow/extract-workflow-yaml.d.ts +22 -0
  487. package/workflow/extract-workflow-yaml.d.ts.map +1 -0
  488. package/workflow/extract-workflow-yaml.js +63 -0
  489. package/workflow/extract-workflow-yaml.js.map +1 -0
  490. package/workflow/graph-commands.d.ts +209 -0
  491. package/workflow/graph-commands.d.ts.map +1 -0
  492. package/workflow/graph-commands.js +516 -0
  493. package/workflow/graph-commands.js.map +1 -0
  494. package/workflow/index.d.ts +66 -0
  495. package/workflow/index.d.ts.map +1 -0
  496. package/workflow/index.js +88 -0
  497. package/workflow/index.js.map +1 -0
  498. package/workflow/serialize-workflow-yaml.d.ts +39 -0
  499. package/workflow/serialize-workflow-yaml.d.ts.map +1 -0
  500. package/workflow/serialize-workflow-yaml.js +413 -0
  501. package/workflow/serialize-workflow-yaml.js.map +1 -0
  502. package/workflow/starter-workflow-yaml.d.ts +12 -0
  503. package/workflow/starter-workflow-yaml.d.ts.map +1 -0
  504. package/workflow/starter-workflow-yaml.js +30 -0
  505. package/workflow/starter-workflow-yaml.js.map +1 -0
  506. package/workflow/types.d.ts +80 -0
  507. package/workflow/types.d.ts.map +1 -0
  508. package/workflow/types.js +2 -0
  509. package/workflow/types.js.map +1 -0
  510. package/workflow/useCanvasKeyboardShortcuts.d.ts +34 -0
  511. package/workflow/useCanvasKeyboardShortcuts.d.ts.map +1 -0
  512. package/workflow/useCanvasKeyboardShortcuts.js +108 -0
  513. package/workflow/useCanvasKeyboardShortcuts.js.map +1 -0
  514. package/workflow/useDiagnoseExecutionFlow.d.ts +87 -0
  515. package/workflow/useDiagnoseExecutionFlow.d.ts.map +1 -0
  516. package/workflow/useDiagnoseExecutionFlow.js +257 -0
  517. package/workflow/useDiagnoseExecutionFlow.js.map +1 -0
  518. package/workflow/useGraphHistory.d.ts +28 -0
  519. package/workflow/useGraphHistory.d.ts.map +1 -0
  520. package/workflow/useGraphHistory.js +106 -0
  521. package/workflow/useGraphHistory.js.map +1 -0
  522. package/workflow/usePendingApprovals.d.ts +35 -0
  523. package/workflow/usePendingApprovals.d.ts.map +1 -0
  524. package/workflow/usePendingApprovals.js +50 -0
  525. package/workflow/usePendingApprovals.js.map +1 -0
  526. package/workflow/useRefineWorkflowFlow.d.ts +75 -0
  527. package/workflow/useRefineWorkflowFlow.d.ts.map +1 -0
  528. package/workflow/useRefineWorkflowFlow.js +216 -0
  529. package/workflow/useRefineWorkflowFlow.js.map +1 -0
  530. package/workflow/useResolveAgentExecutionSession.d.ts +33 -0
  531. package/workflow/useResolveAgentExecutionSession.d.ts.map +1 -0
  532. package/workflow/useResolveAgentExecutionSession.js +37 -0
  533. package/workflow/useResolveAgentExecutionSession.js.map +1 -0
  534. package/workflow/useRunWorkflowFlow.d.ts +82 -0
  535. package/workflow/useRunWorkflowFlow.d.ts.map +1 -0
  536. package/workflow/useRunWorkflowFlow.js +145 -0
  537. package/workflow/useRunWorkflowFlow.js.map +1 -0
  538. package/workflow/useTaskKindRegistry.d.ts +96 -0
  539. package/workflow/useTaskKindRegistry.d.ts.map +1 -0
  540. package/workflow/useTaskKindRegistry.js +75 -0
  541. package/workflow/useTaskKindRegistry.js.map +1 -0
  542. package/workflow/useWorkflow.d.ts +47 -0
  543. package/workflow/useWorkflow.d.ts.map +1 -0
  544. package/workflow/useWorkflow.js +53 -0
  545. package/workflow/useWorkflow.js.map +1 -0
  546. package/workflow/useWorkflowArchitectFlow.d.ts +96 -0
  547. package/workflow/useWorkflowArchitectFlow.d.ts.map +1 -0
  548. package/workflow/useWorkflowArchitectFlow.js +179 -0
  549. package/workflow/useWorkflowArchitectFlow.js.map +1 -0
  550. package/workflow/useWorkflowCanvas.d.ts +66 -0
  551. package/workflow/useWorkflowCanvas.d.ts.map +1 -0
  552. package/workflow/useWorkflowCanvas.js +628 -0
  553. package/workflow/useWorkflowCanvas.js.map +1 -0
  554. package/workflow/useWorkflowCount.d.ts +47 -0
  555. package/workflow/useWorkflowCount.d.ts.map +1 -0
  556. package/workflow/useWorkflowCount.js +26 -0
  557. package/workflow/useWorkflowCount.js.map +1 -0
  558. package/workflow/useWorkflowDashboardSummary.d.ts +34 -0
  559. package/workflow/useWorkflowDashboardSummary.d.ts.map +1 -0
  560. package/workflow/useWorkflowDashboardSummary.js +33 -0
  561. package/workflow/useWorkflowDashboardSummary.js.map +1 -0
  562. package/workflow/useWorkflowEditor.d.ts +45 -0
  563. package/workflow/useWorkflowEditor.d.ts.map +1 -0
  564. package/workflow/useWorkflowEditor.js +52 -0
  565. package/workflow/useWorkflowEditor.js.map +1 -0
  566. package/workflow/useWorkflowExecution.d.ts +37 -0
  567. package/workflow/useWorkflowExecution.d.ts.map +1 -0
  568. package/workflow/useWorkflowExecution.js +43 -0
  569. package/workflow/useWorkflowExecution.js.map +1 -0
  570. package/workflow/useWorkflowExecutionActions.d.ts +41 -0
  571. package/workflow/useWorkflowExecutionActions.d.ts.map +1 -0
  572. package/workflow/useWorkflowExecutionActions.js +86 -0
  573. package/workflow/useWorkflowExecutionActions.js.map +1 -0
  574. package/workflow/useWorkflowExecutionArtifacts.d.ts +26 -0
  575. package/workflow/useWorkflowExecutionArtifacts.d.ts.map +1 -0
  576. package/workflow/useWorkflowExecutionArtifacts.js +29 -0
  577. package/workflow/useWorkflowExecutionArtifacts.js.map +1 -0
  578. package/workflow/useWorkflowExecutionEventLog.d.ts +47 -0
  579. package/workflow/useWorkflowExecutionEventLog.d.ts.map +1 -0
  580. package/workflow/useWorkflowExecutionEventLog.js +59 -0
  581. package/workflow/useWorkflowExecutionEventLog.js.map +1 -0
  582. package/workflow/useWorkflowExecutionEventStream.d.ts +61 -0
  583. package/workflow/useWorkflowExecutionEventStream.d.ts.map +1 -0
  584. package/workflow/useWorkflowExecutionEventStream.js +161 -0
  585. package/workflow/useWorkflowExecutionEventStream.js.map +1 -0
  586. package/workflow/useWorkflowExecutionList.d.ts +49 -0
  587. package/workflow/useWorkflowExecutionList.d.ts.map +1 -0
  588. package/workflow/useWorkflowExecutionList.js +65 -0
  589. package/workflow/useWorkflowExecutionList.js.map +1 -0
  590. package/workflow/useWorkflowInstances.d.ts +30 -0
  591. package/workflow/useWorkflowInstances.d.ts.map +1 -0
  592. package/workflow/useWorkflowInstances.js +33 -0
  593. package/workflow/useWorkflowInstances.js.map +1 -0
  594. package/workflow/useWorkflowList.d.ts +57 -0
  595. package/workflow/useWorkflowList.d.ts.map +1 -0
  596. package/workflow/useWorkflowList.js +29 -0
  597. package/workflow/useWorkflowList.js.map +1 -0
  598. package/workflow/useWorkflowSave.d.ts +25 -0
  599. package/workflow/useWorkflowSave.d.ts.map +1 -0
  600. package/workflow/useWorkflowSave.js +61 -0
  601. package/workflow/useWorkflowSave.js.map +1 -0
  602. package/workflow/useWorkflowTopology.d.ts +40 -0
  603. package/workflow/useWorkflowTopology.d.ts.map +1 -0
  604. package/workflow/useWorkflowTopology.js +163 -0
  605. package/workflow/useWorkflowTopology.js.map +1 -0
  606. package/workflow/useWorkflowValidation.d.ts +27 -0
  607. package/workflow/useWorkflowValidation.d.ts.map +1 -0
  608. package/workflow/useWorkflowValidation.js +253 -0
  609. package/workflow/useWorkflowValidation.js.map +1 -0
  610. package/workflow/useWorkflowYaml.d.ts +26 -0
  611. package/workflow/useWorkflowYaml.d.ts.map +1 -0
  612. package/workflow/useWorkflowYaml.js +26 -0
  613. package/workflow/useWorkflowYaml.js.map +1 -0
  614. package/workflow/workflow-graph-conversions.d.ts +70 -0
  615. package/workflow/workflow-graph-conversions.d.ts.map +1 -0
  616. package/workflow/workflow-graph-conversions.js +634 -0
  617. package/workflow/workflow-graph-conversions.js.map +1 -0
  618. package/workflow/workflow-graph-model.d.ts +83 -0
  619. package/workflow/workflow-graph-model.d.ts.map +1 -0
  620. package/workflow/workflow-graph-model.js +5 -0
  621. package/workflow/workflow-graph-model.js.map +1 -0
  622. package/workflow/workflow-yaml-diff.d.ts +24 -0
  623. package/workflow/workflow-yaml-diff.d.ts.map +1 -0
  624. package/workflow/workflow-yaml-diff.js +96 -0
  625. package/workflow/workflow-yaml-diff.js.map +1 -0
@@ -0,0 +1,882 @@
1
+ "use client";
2
+
3
+ import { useState, useCallback, useMemo, useRef, useEffect } from "react";
4
+ import type { RefObject } from "react";
5
+ import { useNodesState, useEdgesState, useReactFlow } from "@xyflow/react";
6
+ import type {
7
+ Node,
8
+ Edge,
9
+ OnNodesChange,
10
+ OnEdgesChange,
11
+ Connection,
12
+ IsValidConnection,
13
+ } from "@xyflow/react";
14
+ import dagre from "@dagrejs/dagre";
15
+ import type { JsonObject } from "@bufbuild/protobuf";
16
+ import type { WorkflowTaskKind } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/enum_pb";
17
+ import type { WorkflowGraphModel, WorkflowGraphNode } from "./workflow-graph-model";
18
+ import { START_NODE_ID, END_NODE_ID } from "./workflow-graph-model";
19
+ import {
20
+ yamlToGraph,
21
+ toReactFlowElements,
22
+ categorizeKind,
23
+ stringToTaskKind,
24
+ taskKindToString,
25
+ } from "./workflow-graph-conversions";
26
+ import { TASK_KIND_DRAG_MIME } from "./WorkflowTaskPalette";
27
+ import {
28
+ DAGRE_CONFIG,
29
+ CANVAS_NODE_WIDTH,
30
+ CANVAS_NODE_HEIGHT,
31
+ SENTINEL_NODE_WIDTH,
32
+ SENTINEL_NODE_HEIGHT,
33
+ } from "./canvas-constants";
34
+ import type { GraphCommand } from "./graph-commands";
35
+ import {
36
+ AddNodeCommand,
37
+ DeleteNodeCommand,
38
+ AddEdgeCommand,
39
+ DeleteEdgeCommand,
40
+ CompoundCommand,
41
+ UpdateNodeFieldCommand,
42
+ RenameNodeCommand,
43
+ UpdateNodeMetaCommand,
44
+ MigrateBranchHandleCommand,
45
+ DuplicateNodeCommand,
46
+ generateEdgeId,
47
+ generateTaskName,
48
+ createTaskNode,
49
+ isSentinelNode,
50
+ } from "./graph-commands";
51
+ import { graphToYaml } from "./workflow-graph-conversions";
52
+ import { useTaskKindRegistry } from "./useTaskKindRegistry";
53
+ import type { TaskKindDescriptor } from "./types";
54
+ import { useGraphHistory } from "./useGraphHistory";
55
+
56
+ /** Selection state for the canvas inspector. */
57
+ export interface CanvasSelection {
58
+ readonly type: "node" | "edge";
59
+ readonly id: string;
60
+ }
61
+
62
+ /** Return value of {@link useWorkflowCanvas}. */
63
+ export interface UseWorkflowCanvasReturn {
64
+ readonly nodes: Node[];
65
+ readonly edges: Edge[];
66
+ readonly onNodesChange: OnNodesChange;
67
+ readonly onEdgesChange: OnEdgesChange;
68
+ readonly onConnect: (connection: Connection) => void;
69
+ readonly isValidConnection: IsValidConnection;
70
+ readonly onDrop: (event: React.DragEvent) => void;
71
+ readonly onDragOver: (event: React.DragEvent) => void;
72
+ readonly onNodesDelete: (deleted: Node[]) => void;
73
+ readonly onEdgesDelete: (deleted: Edge[]) => void;
74
+ readonly selection: CanvasSelection | null;
75
+ readonly selectNode: (id: string) => void;
76
+ readonly selectEdge: (id: string) => void;
77
+ readonly clearSelection: () => void;
78
+ readonly autoLayout: () => void;
79
+ readonly undo: () => void;
80
+ readonly redo: () => void;
81
+ readonly canUndo: boolean;
82
+ readonly canRedo: boolean;
83
+ readonly isDirty: boolean;
84
+ readonly graph: WorkflowGraphModel | null;
85
+ readonly error: string | null;
86
+ readonly updateNodeField: (nodeId: string, fieldPath: string, value: unknown) => void;
87
+ readonly renameNode: (nodeId: string, newName: string) => void;
88
+ readonly updateNodeExport: (nodeId: string, exportAs: string | undefined) => void;
89
+ readonly updateNodeFlow: (nodeId: string, thenTarget: string | undefined) => void;
90
+ readonly getNodeDescriptor: (nodeId: string) => TaskKindDescriptor | undefined;
91
+ readonly serializeToYaml: () => string | null;
92
+ readonly updateBranchRouting: (
93
+ nodeId: string,
94
+ handleId: string,
95
+ targetTask: string | undefined,
96
+ ) => void;
97
+ readonly migrateBranchHandle: (
98
+ nodeId: string,
99
+ oldHandleId: string,
100
+ newHandleId: string,
101
+ ) => void;
102
+ readonly removeBranchEdges: (nodeId: string, handleId: string) => void;
103
+ readonly insertTaskOnEdge: (edgeId: string, kindString: string) => void;
104
+ readonly addSuccessorTask: (sourceNodeId: string, kindString: string) => void;
105
+ readonly duplicateNode: (nodeId: string) => void;
106
+ readonly addNodeAtPosition: (kindString: string, position: { x: number; y: number }) => void;
107
+ readonly selectAll: () => void;
108
+ }
109
+
110
+ /**
111
+ * Orchestrator hook for the workflow canvas editor.
112
+ *
113
+ * Manages the {@link WorkflowGraphModel} through a command/history pipeline
114
+ * (AD-T15-B2-001). Structural mutations (add/delete nodes and edges) go
115
+ * through {@link GraphCommand}s dispatched to the history. React Flow state
116
+ * is derived from the model after each mutation.
117
+ *
118
+ * @param yaml - The workflow YAML to initialize from. Changes trigger re-parse.
119
+ * @param containerRef - Ref to the canvas container for keyboard shortcut scoping.
120
+ *
121
+ * @since T15 (Visual Canvas Editor)
122
+ */
123
+ export function useWorkflowCanvas(
124
+ yaml: string | null,
125
+ containerRef: RefObject<HTMLDivElement | null>,
126
+ ): UseWorkflowCanvasReturn {
127
+ const [error, setError] = useState<string | null>(null);
128
+ const [selection, setSelection] = useState<CanvasSelection | null>(null);
129
+ const initialModelRef = useRef<WorkflowGraphModel | null>(null);
130
+
131
+ const [nodes, setNodes, onNodesChangeRaw] = useNodesState([] as Node[]);
132
+ const [edges, setEdges, onEdgesChangeRaw] = useEdgesState([] as Edge[]);
133
+ const { screenToFlowPosition } = useReactFlow();
134
+
135
+ // Parse YAML into the initial graph model
136
+ const parsedModel = useMemo<WorkflowGraphModel | null>(() => {
137
+ if (!yaml?.trim()) return null;
138
+ try {
139
+ const parsed = yamlToGraph(yaml);
140
+ return applyDagreLayout(parsed);
141
+ } catch (e) {
142
+ return null;
143
+ }
144
+ }, [yaml]);
145
+
146
+ // Set up graph history with the parsed model
147
+ const history = useGraphHistory(parsedModel, containerRef);
148
+
149
+ // Sync: when YAML changes, reset the history and RF elements
150
+ useEffect(() => {
151
+ if (!yaml?.trim()) {
152
+ setError(null);
153
+ setNodes([]);
154
+ setEdges([]);
155
+ initialModelRef.current = null;
156
+ return;
157
+ }
158
+
159
+ try {
160
+ const parsed = yamlToGraph(yaml);
161
+ const laidOut = applyDagreLayout(parsed);
162
+ history.reset(laidOut);
163
+ initialModelRef.current = laidOut;
164
+ setError(null);
165
+
166
+ const elements = toReactFlowElements(laidOut);
167
+ setNodes(elements.nodes);
168
+ setEdges(elements.edges);
169
+ } catch (e) {
170
+ setError(e instanceof Error ? e.message : "Failed to parse workflow YAML.");
171
+ setNodes([]);
172
+ setEdges([]);
173
+ initialModelRef.current = null;
174
+ }
175
+ }, [yaml]);
176
+
177
+ // Sync React Flow elements whenever the model changes via history
178
+ const syncFromModel = useCallback(
179
+ (model: WorkflowGraphModel) => {
180
+ const elements = toReactFlowElements(model);
181
+ setNodes(elements.nodes);
182
+ setEdges(elements.edges);
183
+ },
184
+ [setNodes, setEdges],
185
+ );
186
+
187
+ const dispatch = useCallback(
188
+ (command: GraphCommand) => {
189
+ const next = history.dispatch(command);
190
+ syncFromModel(next);
191
+ return next;
192
+ },
193
+ [history.dispatch, syncFromModel],
194
+ );
195
+
196
+ // ---------------------------------------------------------------------------
197
+ // Node position changes (drag) — update the model to stay in sync
198
+ // ---------------------------------------------------------------------------
199
+
200
+ const onNodesChange: OnNodesChange = useCallback(
201
+ (changes) => {
202
+ onNodesChangeRaw(changes);
203
+ },
204
+ [onNodesChangeRaw],
205
+ );
206
+
207
+ const onEdgesChange: OnEdgesChange = useCallback(
208
+ (changes) => {
209
+ onEdgesChangeRaw(changes);
210
+ },
211
+ [onEdgesChangeRaw],
212
+ );
213
+
214
+ // ---------------------------------------------------------------------------
215
+ // Connection validation (AD-T15-B2-004)
216
+ // ---------------------------------------------------------------------------
217
+
218
+ const isValidConnection: IsValidConnection = useCallback(
219
+ (connection) => {
220
+ const model = history.currentModel;
221
+ if (!model || !connection.source || !connection.target) return false;
222
+
223
+ // No self-connections
224
+ if (connection.source === connection.target) return false;
225
+
226
+ // Cannot connect to __start__
227
+ if (connection.target === START_NODE_ID) return false;
228
+
229
+ // Cannot connect from __end__
230
+ if (connection.source === END_NODE_ID) return false;
231
+
232
+ // No duplicate edges (same source+target+sourceHandle)
233
+ const hasDuplicate = model.edges.some(
234
+ (e) =>
235
+ e.source === connection.source &&
236
+ e.target === connection.target &&
237
+ (e.sourceHandle ?? null) === (connection.sourceHandle ?? null),
238
+ );
239
+ if (hasDuplicate) return false;
240
+
241
+ return true;
242
+ },
243
+ [history.currentModel],
244
+ );
245
+
246
+ // ---------------------------------------------------------------------------
247
+ // Connection creation
248
+ // ---------------------------------------------------------------------------
249
+
250
+ const onConnect = useCallback(
251
+ (connection: Connection) => {
252
+ if (!connection.source || !connection.target) return;
253
+ const model = history.currentModel;
254
+ if (!model) return;
255
+
256
+ const sourceNode = model.nodes.find((n) => n.id === connection.source);
257
+ if (!sourceNode) return;
258
+
259
+ const kindStr = taskKindToString(sourceNode.kind);
260
+ const isMultiOutput = kindStr === "switch_case" || kindStr === "human_input";
261
+
262
+ const newEdge = {
263
+ id: generateEdgeId(),
264
+ source: connection.source,
265
+ target: connection.target,
266
+ ...(connection.sourceHandle && { sourceHandle: connection.sourceHandle }),
267
+ };
268
+
269
+ // For single-output nodes, replace existing outgoing edge (from default handle)
270
+ if (!isMultiOutput && !connection.sourceHandle) {
271
+ const existingOutgoing = model.edges.find(
272
+ (e) => e.source === connection.source && !e.sourceHandle,
273
+ );
274
+ if (existingOutgoing) {
275
+ dispatch(
276
+ new CompoundCommand("Replace connection", [
277
+ new DeleteEdgeCommand(existingOutgoing.id),
278
+ new AddEdgeCommand(newEdge),
279
+ ]),
280
+ );
281
+ return;
282
+ }
283
+ }
284
+
285
+ dispatch(new AddEdgeCommand(newEdge));
286
+ },
287
+ [history.currentModel, dispatch],
288
+ );
289
+
290
+ // ---------------------------------------------------------------------------
291
+ // Drop handler (drag-to-create from palette)
292
+ // ---------------------------------------------------------------------------
293
+
294
+ const onDrop = useCallback(
295
+ (event: React.DragEvent) => {
296
+ event.preventDefault();
297
+ const kindString = event.dataTransfer.getData(TASK_KIND_DRAG_MIME);
298
+ if (!kindString) return;
299
+
300
+ const model = history.currentModel;
301
+
302
+ const kind = stringToTaskKind(kindString);
303
+ const category = categorizeKind(kindString);
304
+
305
+ const existingNames = new Set(model.nodes.map((n) => n.taskName));
306
+ const taskName = generateTaskName(kindString, existingNames);
307
+
308
+ const position = screenToFlowPosition({
309
+ x: event.clientX,
310
+ y: event.clientY,
311
+ });
312
+
313
+ const node = createTaskNode(taskName, kind, kindString, category, position);
314
+
315
+ // If the graph has no nodes at all (first drop on empty canvas),
316
+ // bootstrap the model with sentinel nodes before adding the task.
317
+ const taskNodes = model.nodes.filter((n) => !isSentinelNode(n.id));
318
+ if (model.nodes.length === 0) {
319
+ const startNode: WorkflowGraphNode = {
320
+ id: START_NODE_ID,
321
+ taskName: "Start",
322
+ kind: 0 as WorkflowTaskKind,
323
+ category: "start",
324
+ config: {} as JsonObject,
325
+ position: { x: 0, y: 0 },
326
+ };
327
+ const endNode: WorkflowGraphNode = {
328
+ id: END_NODE_ID,
329
+ taskName: "End",
330
+ kind: 0 as WorkflowTaskKind,
331
+ category: "end",
332
+ config: {} as JsonObject,
333
+ position: { x: 0, y: 0 },
334
+ };
335
+ const bootstrapModel: WorkflowGraphModel = {
336
+ document: { dsl: "1.0.0", namespace: "", name: "", version: "0.0.1" },
337
+ nodes: [startNode, endNode],
338
+ edges: [],
339
+ };
340
+ history.reset(bootstrapModel);
341
+ initialModelRef.current = bootstrapModel;
342
+
343
+ const autoEdge = {
344
+ id: generateEdgeId(),
345
+ source: START_NODE_ID,
346
+ target: taskName,
347
+ };
348
+ const next = dispatch(new AddNodeCommand(node, autoEdge));
349
+
350
+ requestAnimationFrame(() => {
351
+ const laidOut = applyDagreLayout(next);
352
+ history.reset(laidOut);
353
+ syncFromModel(laidOut);
354
+ });
355
+ } else if (taskNodes.length === 0) {
356
+ const autoEdge = {
357
+ id: generateEdgeId(),
358
+ source: START_NODE_ID,
359
+ target: taskName,
360
+ };
361
+ dispatch(new AddNodeCommand(node, autoEdge));
362
+ } else {
363
+ dispatch(new AddNodeCommand(node, null));
364
+ }
365
+ },
366
+ [history, dispatch, syncFromModel, screenToFlowPosition],
367
+ );
368
+
369
+ const onDragOver = useCallback((event: React.DragEvent) => {
370
+ event.preventDefault();
371
+ event.dataTransfer.dropEffect = "move";
372
+ }, []);
373
+
374
+ // ---------------------------------------------------------------------------
375
+ // Deletion
376
+ // ---------------------------------------------------------------------------
377
+
378
+ const onNodesDelete = useCallback(
379
+ (deleted: Node[]) => {
380
+ const nonSentinels = deleted.filter((n) => !isSentinelNode(n.id));
381
+ if (nonSentinels.length === 0) return;
382
+
383
+ if (nonSentinels.length === 1) {
384
+ const n = nonSentinels[0];
385
+ dispatch(new DeleteNodeCommand(n.id, n.data?.taskName as string ?? n.id));
386
+ } else {
387
+ const commands = nonSentinels.map(
388
+ (n) => new DeleteNodeCommand(n.id, n.data?.taskName as string ?? n.id),
389
+ );
390
+ dispatch(new CompoundCommand(`Delete ${nonSentinels.length} tasks`, commands));
391
+ }
392
+ },
393
+ [dispatch],
394
+ );
395
+
396
+ const onEdgesDelete = useCallback(
397
+ (deleted: Edge[]) => {
398
+ if (deleted.length === 0) return;
399
+
400
+ if (deleted.length === 1) {
401
+ dispatch(new DeleteEdgeCommand(deleted[0].id));
402
+ } else {
403
+ const commands = deleted.map((e) => new DeleteEdgeCommand(e.id));
404
+ dispatch(new CompoundCommand(`Delete ${deleted.length} connections`, commands));
405
+ }
406
+ },
407
+ [dispatch],
408
+ );
409
+
410
+ // ---------------------------------------------------------------------------
411
+ // Task kind registry (for inspector descriptor lookup)
412
+ // ---------------------------------------------------------------------------
413
+
414
+ const registry = useTaskKindRegistry();
415
+
416
+ // ---------------------------------------------------------------------------
417
+ // Inspector mutation methods (AD-T15-B3-001)
418
+ // ---------------------------------------------------------------------------
419
+
420
+ const updateNodeField = useCallback(
421
+ (nodeId: string, fieldPath: string, value: unknown) => {
422
+ const model = history.currentModel;
423
+ if (!model) return;
424
+ const node = model.nodes.find((n) => n.id === nodeId);
425
+ if (!node) return;
426
+ dispatch(new UpdateNodeFieldCommand(nodeId, fieldPath, value, node.taskName));
427
+ },
428
+ [history.currentModel, dispatch],
429
+ );
430
+
431
+ const renameNode = useCallback(
432
+ (nodeId: string, newName: string) => {
433
+ const model = history.currentModel;
434
+ if (!model) return;
435
+ const node = model.nodes.find((n) => n.id === nodeId);
436
+ if (!node || node.taskName === newName) return;
437
+ dispatch(new RenameNodeCommand(node.taskName, newName));
438
+ setSelection({ type: "node", id: newName });
439
+ },
440
+ [history.currentModel, dispatch],
441
+ );
442
+
443
+ const updateNodeExport = useCallback(
444
+ (nodeId: string, exportAs: string | undefined) => {
445
+ const model = history.currentModel;
446
+ if (!model) return;
447
+ const node = model.nodes.find((n) => n.id === nodeId);
448
+ if (!node) return;
449
+ dispatch(new UpdateNodeMetaCommand(nodeId, "export", exportAs, node.taskName));
450
+ },
451
+ [history.currentModel, dispatch],
452
+ );
453
+
454
+ const updateNodeFlow = useCallback(
455
+ (nodeId: string, thenTarget: string | undefined) => {
456
+ const model = history.currentModel;
457
+ if (!model) return;
458
+ const node = model.nodes.find((n) => n.id === nodeId);
459
+ if (!node) return;
460
+ dispatch(new UpdateNodeMetaCommand(nodeId, "flow", thenTarget, node.taskName));
461
+ },
462
+ [history.currentModel, dispatch],
463
+ );
464
+
465
+ const getNodeDescriptor = useCallback(
466
+ (nodeId: string): TaskKindDescriptor | undefined => {
467
+ const model = history.currentModel;
468
+ if (!model) return undefined;
469
+ const node = model.nodes.find((n) => n.id === nodeId);
470
+ if (!node) return undefined;
471
+ const kindStr = taskKindToString(node.kind);
472
+ return registry.getByKind(kindStr);
473
+ },
474
+ [history.currentModel, registry.getByKind],
475
+ );
476
+
477
+ // ---------------------------------------------------------------------------
478
+ // Branch routing methods (AD-T15-B4: edge-config sync for switch_case/human_input)
479
+ // ---------------------------------------------------------------------------
480
+
481
+ const updateBranchRouting = useCallback(
482
+ (nodeId: string, handleId: string, targetTask: string | undefined) => {
483
+ const model = history.currentModel;
484
+ if (!model) return;
485
+
486
+ const existingEdge = model.edges.find(
487
+ (e) => e.source === nodeId && e.sourceHandle === handleId,
488
+ );
489
+
490
+ if (!targetTask) {
491
+ if (existingEdge) {
492
+ dispatch(new DeleteEdgeCommand(existingEdge.id));
493
+ }
494
+ return;
495
+ }
496
+
497
+ if (existingEdge) {
498
+ if (existingEdge.target === targetTask) return;
499
+ const label = handleId.includes("_") ? handleId.split("_").slice(1).join("_") : undefined;
500
+ dispatch(
501
+ new CompoundCommand(`Route ${handleId} to ${targetTask}`, [
502
+ new DeleteEdgeCommand(existingEdge.id),
503
+ new AddEdgeCommand({
504
+ id: generateEdgeId(),
505
+ source: nodeId,
506
+ target: targetTask,
507
+ sourceHandle: handleId,
508
+ label,
509
+ }),
510
+ ]),
511
+ );
512
+ } else {
513
+ const label = handleId.includes("_") ? handleId.split("_").slice(1).join("_") : undefined;
514
+ dispatch(
515
+ new AddEdgeCommand({
516
+ id: generateEdgeId(),
517
+ source: nodeId,
518
+ target: targetTask,
519
+ sourceHandle: handleId,
520
+ label,
521
+ }),
522
+ );
523
+ }
524
+ },
525
+ [history.currentModel, dispatch],
526
+ );
527
+
528
+ const migrateBranchHandle = useCallback(
529
+ (nodeId: string, oldHandleId: string, newHandleId: string) => {
530
+ if (oldHandleId === newHandleId) return;
531
+ dispatch(new MigrateBranchHandleCommand(nodeId, oldHandleId, newHandleId));
532
+ },
533
+ [dispatch],
534
+ );
535
+
536
+ const removeBranchEdges = useCallback(
537
+ (nodeId: string, handleId: string) => {
538
+ const model = history.currentModel;
539
+ if (!model) return;
540
+
541
+ const edgesToRemove = model.edges.filter(
542
+ (e) => e.source === nodeId && e.sourceHandle === handleId,
543
+ );
544
+ if (edgesToRemove.length === 0) return;
545
+
546
+ if (edgesToRemove.length === 1) {
547
+ dispatch(new DeleteEdgeCommand(edgesToRemove[0].id));
548
+ } else {
549
+ dispatch(
550
+ new CompoundCommand(
551
+ `Remove ${edgesToRemove.length} branch edges`,
552
+ edgesToRemove.map((e) => new DeleteEdgeCommand(e.id)),
553
+ ),
554
+ );
555
+ }
556
+ },
557
+ [history.currentModel, dispatch],
558
+ );
559
+
560
+ // ---------------------------------------------------------------------------
561
+ // Insert task on edge (AD-T15-UX: "+" button affordance)
562
+ // ---------------------------------------------------------------------------
563
+
564
+ const insertTaskOnEdge = useCallback(
565
+ (edgeId: string, kindString: string) => {
566
+ const model = history.currentModel;
567
+ if (!model) return;
568
+
569
+ const edge = model.edges.find((e) => e.id === edgeId);
570
+ if (!edge) return;
571
+
572
+ const sourceNode = model.nodes.find((n) => n.id === edge.source);
573
+ const targetNode = model.nodes.find((n) => n.id === edge.target);
574
+ if (!sourceNode || !targetNode) return;
575
+
576
+ const kind = stringToTaskKind(kindString);
577
+ const category = categorizeKind(kindString);
578
+ const existingNames = new Set(model.nodes.map((n) => n.taskName));
579
+ const taskName = generateTaskName(kindString, existingNames);
580
+
581
+ const midPosition = {
582
+ x: (sourceNode.position.x + targetNode.position.x) / 2,
583
+ y: (sourceNode.position.y + targetNode.position.y) / 2 + 40,
584
+ };
585
+
586
+ const node = createTaskNode(taskName, kind, kindString, category, midPosition);
587
+ const edgeToNew = {
588
+ id: generateEdgeId(),
589
+ source: edge.source,
590
+ target: taskName,
591
+ ...(edge.sourceHandle && { sourceHandle: edge.sourceHandle }),
592
+ };
593
+ const edgeFromNew = {
594
+ id: generateEdgeId(),
595
+ source: taskName,
596
+ target: edge.target,
597
+ };
598
+
599
+ const next = dispatch(
600
+ new CompoundCommand(`Insert ${kindString} on edge`, [
601
+ new DeleteEdgeCommand(edgeId),
602
+ new AddNodeCommand(node, edgeToNew),
603
+ new AddEdgeCommand(edgeFromNew),
604
+ ]),
605
+ );
606
+
607
+ setSelection({ type: "node", id: taskName });
608
+
609
+ requestAnimationFrame(() => {
610
+ if (next.nodes.length > 0) {
611
+ const laidOut = applyDagreLayout(next);
612
+ history.reset(laidOut);
613
+ syncFromModel(laidOut);
614
+ }
615
+ });
616
+ },
617
+ [history, dispatch, syncFromModel],
618
+ );
619
+
620
+ // ---------------------------------------------------------------------------
621
+ // Add successor task (AD-T01: "+" button on node)
622
+ // ---------------------------------------------------------------------------
623
+
624
+ const addSuccessorTask = useCallback(
625
+ (sourceNodeId: string, kindString: string) => {
626
+ const model = history.currentModel;
627
+ if (!model) return;
628
+
629
+ const sourceNode = model.nodes.find((n) => n.id === sourceNodeId);
630
+ if (!sourceNode) return;
631
+
632
+ const kind = stringToTaskKind(kindString);
633
+ const category = categorizeKind(kindString);
634
+ const existingNames = new Set(model.nodes.map((n) => n.taskName));
635
+ const taskName = generateTaskName(kindString, existingNames);
636
+
637
+ const position = {
638
+ x: sourceNode.position.x,
639
+ y: sourceNode.position.y + CANVAS_NODE_HEIGHT + DAGRE_CONFIG.ranksep,
640
+ };
641
+
642
+ const node = createTaskNode(taskName, kind, kindString, category, position);
643
+ const edge = {
644
+ id: generateEdgeId(),
645
+ source: sourceNodeId,
646
+ target: taskName,
647
+ };
648
+
649
+ const next = dispatch(
650
+ new CompoundCommand(`Add ${kindString} after "${sourceNode.taskName}"`, [
651
+ new AddNodeCommand(node, null),
652
+ new AddEdgeCommand(edge),
653
+ ]),
654
+ );
655
+
656
+ setSelection({ type: "node", id: taskName });
657
+
658
+ requestAnimationFrame(() => {
659
+ if (next.nodes.length > 0) {
660
+ const laidOut = applyDagreLayout(next);
661
+ history.reset(laidOut);
662
+ syncFromModel(laidOut);
663
+ }
664
+ });
665
+ },
666
+ [history, dispatch, syncFromModel],
667
+ );
668
+
669
+ // ---------------------------------------------------------------------------
670
+ // Duplicate node (AD-T05: context menu duplicate)
671
+ // ---------------------------------------------------------------------------
672
+
673
+ const duplicateNode = useCallback(
674
+ (nodeId: string) => {
675
+ const model = history.currentModel;
676
+ if (!model) return;
677
+
678
+ const sourceNode = model.nodes.find((n) => n.id === nodeId);
679
+ if (!sourceNode || isSentinelNode(nodeId)) return;
680
+
681
+ const kindStr = taskKindToString(sourceNode.kind);
682
+ const existingNames = new Set(model.nodes.map((n) => n.taskName));
683
+ const newName = generateTaskName(kindStr, existingNames);
684
+
685
+ dispatch(new DuplicateNodeCommand(nodeId, newName));
686
+ setSelection({ type: "node", id: newName });
687
+ },
688
+ [history.currentModel, dispatch],
689
+ );
690
+
691
+ // ---------------------------------------------------------------------------
692
+ // Add node at position (AD-T05: pane context menu "Add Task")
693
+ // ---------------------------------------------------------------------------
694
+
695
+ const addNodeAtPosition = useCallback(
696
+ (kindString: string, position: { x: number; y: number }) => {
697
+ const model = history.currentModel;
698
+ if (!model) return;
699
+
700
+ const kind = stringToTaskKind(kindString);
701
+ const category = categorizeKind(kindString);
702
+ const existingNames = new Set(model.nodes.map((n) => n.taskName));
703
+ const taskName = generateTaskName(kindString, existingNames);
704
+
705
+ const node = createTaskNode(taskName, kind, kindString, category, position);
706
+ dispatch(new AddNodeCommand(node, null));
707
+ setSelection({ type: "node", id: taskName });
708
+ },
709
+ [history.currentModel, dispatch],
710
+ );
711
+
712
+ // ---------------------------------------------------------------------------
713
+ // Select all (AD-T05: pane context menu "Select All")
714
+ // ---------------------------------------------------------------------------
715
+
716
+ const selectAll = useCallback(() => {
717
+ const model = history.currentModel;
718
+ if (!model) return;
719
+
720
+ const selectableNodes = model.nodes
721
+ .filter((n) => !isSentinelNode(n.id))
722
+ .map((n) => ({ id: n.id, type: "select" as const, selected: true }));
723
+
724
+ if (selectableNodes.length > 0) {
725
+ onNodesChangeRaw(selectableNodes);
726
+ }
727
+ }, [history.currentModel, onNodesChangeRaw]);
728
+
729
+ // ---------------------------------------------------------------------------
730
+ // Selection
731
+ // ---------------------------------------------------------------------------
732
+
733
+ const selectNode = useCallback((id: string) => {
734
+ setSelection({ type: "node", id });
735
+ }, []);
736
+
737
+ const selectEdge = useCallback((id: string) => {
738
+ setSelection({ type: "edge", id });
739
+ }, []);
740
+
741
+ const clearSelection = useCallback(() => {
742
+ setSelection(null);
743
+ }, []);
744
+
745
+ // ---------------------------------------------------------------------------
746
+ // Auto-layout
747
+ // ---------------------------------------------------------------------------
748
+
749
+ const autoLayout = useCallback(() => {
750
+ const model = history.currentModel;
751
+ if (!model || model.nodes.length === 0) return;
752
+ const laidOut = applyDagreLayout(model);
753
+ history.reset(laidOut);
754
+ syncFromModel(laidOut);
755
+ }, [history, syncFromModel]);
756
+
757
+ // ---------------------------------------------------------------------------
758
+ // Undo / Redo (delegates to history, then syncs RF)
759
+ // ---------------------------------------------------------------------------
760
+
761
+ const undo = useCallback(() => {
762
+ history.undo();
763
+ syncFromModel(history.currentModel);
764
+ }, [history, syncFromModel]);
765
+
766
+ const redo = useCallback(() => {
767
+ history.redo();
768
+ syncFromModel(history.currentModel);
769
+ }, [history, syncFromModel]);
770
+
771
+ // ---------------------------------------------------------------------------
772
+ // Dirty tracking: model reference comparison
773
+ // ---------------------------------------------------------------------------
774
+
775
+ const graph = history.currentModel.nodes.length > 0 ? history.currentModel : null;
776
+ const isDirty = initialModelRef.current !== null && graph !== initialModelRef.current;
777
+
778
+ const serializeToYaml = useCallback((): string | null => {
779
+ if (!graph) return null;
780
+ try {
781
+ return graphToYaml(graph);
782
+ } catch {
783
+ return null;
784
+ }
785
+ }, [graph]);
786
+
787
+ return useMemo(
788
+ () => ({
789
+ nodes,
790
+ edges,
791
+ onNodesChange,
792
+ onEdgesChange,
793
+ onConnect,
794
+ isValidConnection,
795
+ onDrop,
796
+ onDragOver,
797
+ onNodesDelete,
798
+ onEdgesDelete,
799
+ selection,
800
+ selectNode,
801
+ selectEdge,
802
+ clearSelection,
803
+ autoLayout,
804
+ undo,
805
+ redo,
806
+ canUndo: history.canUndo,
807
+ canRedo: history.canRedo,
808
+ isDirty,
809
+ graph,
810
+ error,
811
+ updateNodeField,
812
+ renameNode,
813
+ updateNodeExport,
814
+ updateNodeFlow,
815
+ getNodeDescriptor,
816
+ serializeToYaml,
817
+ updateBranchRouting,
818
+ migrateBranchHandle,
819
+ removeBranchEdges,
820
+ insertTaskOnEdge,
821
+ addSuccessorTask,
822
+ duplicateNode,
823
+ addNodeAtPosition,
824
+ selectAll,
825
+ }),
826
+ [
827
+ nodes, edges, onNodesChange, onEdgesChange, onConnect,
828
+ isValidConnection, onDrop, onDragOver, onNodesDelete, onEdgesDelete,
829
+ selection, selectNode, selectEdge, clearSelection, autoLayout,
830
+ undo, redo, history.canUndo, history.canRedo, isDirty, graph, error,
831
+ updateNodeField, renameNode, updateNodeExport, updateNodeFlow,
832
+ getNodeDescriptor, serializeToYaml,
833
+ updateBranchRouting, migrateBranchHandle, removeBranchEdges,
834
+ insertTaskOnEdge, addSuccessorTask,
835
+ duplicateNode, addNodeAtPosition, selectAll,
836
+ ],
837
+ );
838
+ }
839
+
840
+ // ---------------------------------------------------------------------------
841
+ // Dagre layout
842
+ // ---------------------------------------------------------------------------
843
+
844
+ function applyDagreLayout(graph: WorkflowGraphModel): WorkflowGraphModel {
845
+ const g = new dagre.graphlib.Graph();
846
+ g.setGraph({
847
+ rankdir: DAGRE_CONFIG.rankdir,
848
+ ranksep: DAGRE_CONFIG.ranksep,
849
+ nodesep: DAGRE_CONFIG.nodesep,
850
+ });
851
+ g.setDefaultEdgeLabel(() => ({}));
852
+
853
+ for (const node of graph.nodes) {
854
+ const isSentinel = node.id === START_NODE_ID || node.id === END_NODE_ID;
855
+ g.setNode(node.id, {
856
+ width: isSentinel ? SENTINEL_NODE_WIDTH : CANVAS_NODE_WIDTH,
857
+ height: isSentinel ? SENTINEL_NODE_HEIGHT : CANVAS_NODE_HEIGHT,
858
+ });
859
+ }
860
+
861
+ for (const edge of graph.edges) {
862
+ g.setEdge(edge.source, edge.target);
863
+ }
864
+
865
+ dagre.layout(g);
866
+
867
+ const layoutNodes: WorkflowGraphNode[] = graph.nodes.map((node) => {
868
+ const dagreNode = g.node(node.id);
869
+ const isSentinel = node.id === START_NODE_ID || node.id === END_NODE_ID;
870
+ const w = isSentinel ? SENTINEL_NODE_WIDTH : CANVAS_NODE_WIDTH;
871
+ const h = isSentinel ? SENTINEL_NODE_HEIGHT : CANVAS_NODE_HEIGHT;
872
+ return {
873
+ ...node,
874
+ position: {
875
+ x: (dagreNode?.x ?? 0) - w / 2,
876
+ y: (dagreNode?.y ?? 0) - h / 2,
877
+ },
878
+ };
879
+ });
880
+
881
+ return { ...graph, nodes: layoutNodes };
882
+ }