@synergenius/flow-weaver 0.2.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 (466) hide show
  1. package/LICENSE +122 -0
  2. package/README.md +315 -0
  3. package/dist/annotation-generator.d.ts +45 -0
  4. package/dist/annotation-generator.js +557 -0
  5. package/dist/api/builder.d.ts +223 -0
  6. package/dist/api/builder.js +345 -0
  7. package/dist/api/compile.d.ts +92 -0
  8. package/dist/api/compile.js +149 -0
  9. package/dist/api/extract-types.d.ts +29 -0
  10. package/dist/api/extract-types.js +57 -0
  11. package/dist/api/generate-in-place.d.ts +73 -0
  12. package/dist/api/generate-in-place.js +1353 -0
  13. package/dist/api/generate.d.ts +83 -0
  14. package/dist/api/generate.js +510 -0
  15. package/dist/api/helpers.d.ts +248 -0
  16. package/dist/api/helpers.js +285 -0
  17. package/dist/api/index.d.ts +46 -0
  18. package/dist/api/index.js +45 -0
  19. package/dist/api/inline-runtime.d.ts +27 -0
  20. package/dist/api/inline-runtime.js +551 -0
  21. package/dist/api/manipulation/connections.d.ts +79 -0
  22. package/dist/api/manipulation/connections.js +151 -0
  23. package/dist/api/manipulation/index.d.ts +34 -0
  24. package/dist/api/manipulation/index.js +41 -0
  25. package/dist/api/manipulation/node-types.d.ts +123 -0
  26. package/dist/api/manipulation/node-types.js +200 -0
  27. package/dist/api/manipulation/nodes.d.ts +144 -0
  28. package/dist/api/manipulation/nodes.js +333 -0
  29. package/dist/api/manipulation/ports.d.ts +59 -0
  30. package/dist/api/manipulation/ports.js +228 -0
  31. package/dist/api/manipulation/scopes.d.ts +52 -0
  32. package/dist/api/manipulation/scopes.js +156 -0
  33. package/dist/api/manipulation/validation.d.ts +6 -0
  34. package/dist/api/manipulation/validation.js +6 -0
  35. package/dist/api/manipulation/workflow.d.ts +81 -0
  36. package/dist/api/manipulation/workflow.js +116 -0
  37. package/dist/api/manipulation.d.ts +8 -0
  38. package/dist/api/manipulation.js +8 -0
  39. package/dist/api/parse.d.ts +48 -0
  40. package/dist/api/parse.js +110 -0
  41. package/dist/api/patterns.d.ts +112 -0
  42. package/dist/api/patterns.js +306 -0
  43. package/dist/api/query.d.ts +429 -0
  44. package/dist/api/query.js +816 -0
  45. package/dist/api/templates.d.ts +98 -0
  46. package/dist/api/templates.js +117 -0
  47. package/dist/api/transform.d.ts +31 -0
  48. package/dist/api/transform.js +40 -0
  49. package/dist/api/validate.d.ts +25 -0
  50. package/dist/api/validate.js +39 -0
  51. package/dist/api/workflow-file-operations.d.ts +29 -0
  52. package/dist/api/workflow-file-operations.js +180 -0
  53. package/dist/ast/builder.d.ts +210 -0
  54. package/dist/ast/builder.js +395 -0
  55. package/dist/ast/index.d.ts +5 -0
  56. package/dist/ast/index.js +5 -0
  57. package/dist/ast/serialization-node.d.ts +6 -0
  58. package/dist/ast/serialization-node.js +30 -0
  59. package/dist/ast/serialization.d.ts +43 -0
  60. package/dist/ast/serialization.js +134 -0
  61. package/dist/ast/types.d.ts +852 -0
  62. package/dist/ast/types.js +2 -0
  63. package/dist/ast/workflow-utils.d.ts +54 -0
  64. package/dist/ast/workflow-utils.js +114 -0
  65. package/dist/body-generator.d.ts +31 -0
  66. package/dist/body-generator.js +35 -0
  67. package/dist/built-in-nodes/delay.d.ts +11 -0
  68. package/dist/built-in-nodes/delay.js +29 -0
  69. package/dist/built-in-nodes/index.d.ts +5 -0
  70. package/dist/built-in-nodes/index.js +4 -0
  71. package/dist/built-in-nodes/invoke-workflow.d.ts +13 -0
  72. package/dist/built-in-nodes/invoke-workflow.js +25 -0
  73. package/dist/built-in-nodes/mock-types.d.ts +18 -0
  74. package/dist/built-in-nodes/mock-types.js +12 -0
  75. package/dist/built-in-nodes/wait-for-event.d.ts +13 -0
  76. package/dist/built-in-nodes/wait-for-event.js +25 -0
  77. package/dist/chevrotain-parser/connect-parser.d.ts +24 -0
  78. package/dist/chevrotain-parser/connect-parser.js +98 -0
  79. package/dist/chevrotain-parser/grammar-diagrams.d.ts +29 -0
  80. package/dist/chevrotain-parser/grammar-diagrams.js +264 -0
  81. package/dist/chevrotain-parser/index.d.ts +25 -0
  82. package/dist/chevrotain-parser/index.js +27 -0
  83. package/dist/chevrotain-parser/map-parser.d.ts +33 -0
  84. package/dist/chevrotain-parser/map-parser.js +130 -0
  85. package/dist/chevrotain-parser/node-parser.d.ts +36 -0
  86. package/dist/chevrotain-parser/node-parser.js +466 -0
  87. package/dist/chevrotain-parser/path-parser.d.ts +28 -0
  88. package/dist/chevrotain-parser/path-parser.js +118 -0
  89. package/dist/chevrotain-parser/port-parser.d.ts +36 -0
  90. package/dist/chevrotain-parser/port-parser.js +442 -0
  91. package/dist/chevrotain-parser/position-parser.d.ts +20 -0
  92. package/dist/chevrotain-parser/position-parser.js +83 -0
  93. package/dist/chevrotain-parser/scope-parser.d.ts +19 -0
  94. package/dist/chevrotain-parser/scope-parser.js +104 -0
  95. package/dist/chevrotain-parser/tokens.d.ts +78 -0
  96. package/dist/chevrotain-parser/tokens.js +384 -0
  97. package/dist/chevrotain-parser/trigger-cancel-parser.d.ts +50 -0
  98. package/dist/chevrotain-parser/trigger-cancel-parser.js +282 -0
  99. package/dist/cli/commands/changelog.d.ts +13 -0
  100. package/dist/cli/commands/changelog.js +135 -0
  101. package/dist/cli/commands/compile.d.ts +64 -0
  102. package/dist/cli/commands/compile.js +278 -0
  103. package/dist/cli/commands/create.d.ts +33 -0
  104. package/dist/cli/commands/create.js +147 -0
  105. package/dist/cli/commands/describe.d.ts +68 -0
  106. package/dist/cli/commands/describe.js +377 -0
  107. package/dist/cli/commands/dev.d.ts +32 -0
  108. package/dist/cli/commands/dev.js +384 -0
  109. package/dist/cli/commands/diagram.d.ts +13 -0
  110. package/dist/cli/commands/diagram.js +33 -0
  111. package/dist/cli/commands/diff.d.ts +11 -0
  112. package/dist/cli/commands/diff.js +59 -0
  113. package/dist/cli/commands/doctor.d.ts +57 -0
  114. package/dist/cli/commands/doctor.js +719 -0
  115. package/dist/cli/commands/export.d.ts +57 -0
  116. package/dist/cli/commands/export.js +163 -0
  117. package/dist/cli/commands/grammar.d.ts +9 -0
  118. package/dist/cli/commands/grammar.js +39 -0
  119. package/dist/cli/commands/init.d.ts +59 -0
  120. package/dist/cli/commands/init.js +435 -0
  121. package/dist/cli/commands/listen.d.ts +16 -0
  122. package/dist/cli/commands/listen.js +39 -0
  123. package/dist/cli/commands/market.d.ts +52 -0
  124. package/dist/cli/commands/market.js +436 -0
  125. package/dist/cli/commands/migrate.d.ts +13 -0
  126. package/dist/cli/commands/migrate.js +89 -0
  127. package/dist/cli/commands/openapi.d.ts +37 -0
  128. package/dist/cli/commands/openapi.js +67 -0
  129. package/dist/cli/commands/pattern.d.ts +34 -0
  130. package/dist/cli/commands/pattern.js +185 -0
  131. package/dist/cli/commands/plugin.d.ts +16 -0
  132. package/dist/cli/commands/plugin.js +176 -0
  133. package/dist/cli/commands/run.d.ts +49 -0
  134. package/dist/cli/commands/run.js +191 -0
  135. package/dist/cli/commands/serve.d.ts +45 -0
  136. package/dist/cli/commands/serve.js +81 -0
  137. package/dist/cli/commands/templates.d.ts +8 -0
  138. package/dist/cli/commands/templates.js +54 -0
  139. package/dist/cli/commands/ui.d.ts +16 -0
  140. package/dist/cli/commands/ui.js +130 -0
  141. package/dist/cli/commands/validate.d.ts +12 -0
  142. package/dist/cli/commands/validate.js +247 -0
  143. package/dist/cli/commands/watch.d.ts +9 -0
  144. package/dist/cli/commands/watch.js +70 -0
  145. package/dist/cli/flow-weaver.mjs +92924 -0
  146. package/dist/cli/index.d.ts +9 -0
  147. package/dist/cli/index.js +742 -0
  148. package/dist/cli/templates/ai/mock-provider.d.ts +7 -0
  149. package/dist/cli/templates/ai/mock-provider.js +64 -0
  150. package/dist/cli/templates/ai/types.d.ts +47 -0
  151. package/dist/cli/templates/ai/types.js +5 -0
  152. package/dist/cli/templates/approvals/index.d.ts +15 -0
  153. package/dist/cli/templates/approvals/index.js +241 -0
  154. package/dist/cli/templates/index.d.ts +102 -0
  155. package/dist/cli/templates/index.js +101 -0
  156. package/dist/cli/templates/nodes/agent-router.d.ts +3 -0
  157. package/dist/cli/templates/nodes/agent-router.js +114 -0
  158. package/dist/cli/templates/nodes/aggregator.d.ts +7 -0
  159. package/dist/cli/templates/nodes/aggregator.js +63 -0
  160. package/dist/cli/templates/nodes/conversation-memory.d.ts +3 -0
  161. package/dist/cli/templates/nodes/conversation-memory.js +85 -0
  162. package/dist/cli/templates/nodes/http.d.ts +7 -0
  163. package/dist/cli/templates/nodes/http.js +80 -0
  164. package/dist/cli/templates/nodes/human-approval.d.ts +3 -0
  165. package/dist/cli/templates/nodes/human-approval.js +110 -0
  166. package/dist/cli/templates/nodes/json-extractor.d.ts +3 -0
  167. package/dist/cli/templates/nodes/json-extractor.js +119 -0
  168. package/dist/cli/templates/nodes/llm-call.d.ts +3 -0
  169. package/dist/cli/templates/nodes/llm-call.js +106 -0
  170. package/dist/cli/templates/nodes/prompt-template.d.ts +3 -0
  171. package/dist/cli/templates/nodes/prompt-template.js +52 -0
  172. package/dist/cli/templates/nodes/rag-retriever.d.ts +3 -0
  173. package/dist/cli/templates/nodes/rag-retriever.js +128 -0
  174. package/dist/cli/templates/nodes/tool-executor.d.ts +3 -0
  175. package/dist/cli/templates/nodes/tool-executor.js +108 -0
  176. package/dist/cli/templates/nodes/transformer.d.ts +7 -0
  177. package/dist/cli/templates/nodes/transformer.js +68 -0
  178. package/dist/cli/templates/nodes/validator.d.ts +7 -0
  179. package/dist/cli/templates/nodes/validator.js +62 -0
  180. package/dist/cli/templates/providers/index.d.ts +14 -0
  181. package/dist/cli/templates/providers/index.js +239 -0
  182. package/dist/cli/templates/shared/approval-types.d.ts +9 -0
  183. package/dist/cli/templates/shared/approval-types.js +31 -0
  184. package/dist/cli/templates/shared/llm-types.d.ts +15 -0
  185. package/dist/cli/templates/shared/llm-types.js +104 -0
  186. package/dist/cli/templates/workflows/aggregator.d.ts +7 -0
  187. package/dist/cli/templates/workflows/aggregator.js +104 -0
  188. package/dist/cli/templates/workflows/ai-agent-durable.d.ts +8 -0
  189. package/dist/cli/templates/workflows/ai-agent-durable.js +338 -0
  190. package/dist/cli/templates/workflows/ai-agent.d.ts +31 -0
  191. package/dist/cli/templates/workflows/ai-agent.js +326 -0
  192. package/dist/cli/templates/workflows/ai-chat.d.ts +7 -0
  193. package/dist/cli/templates/workflows/ai-chat.js +169 -0
  194. package/dist/cli/templates/workflows/ai-pipeline-durable.d.ts +8 -0
  195. package/dist/cli/templates/workflows/ai-pipeline-durable.js +330 -0
  196. package/dist/cli/templates/workflows/ai-rag.d.ts +7 -0
  197. package/dist/cli/templates/workflows/ai-rag.js +186 -0
  198. package/dist/cli/templates/workflows/ai-react.d.ts +7 -0
  199. package/dist/cli/templates/workflows/ai-react.js +294 -0
  200. package/dist/cli/templates/workflows/conditional.d.ts +12 -0
  201. package/dist/cli/templates/workflows/conditional.js +142 -0
  202. package/dist/cli/templates/workflows/error-handler.d.ts +7 -0
  203. package/dist/cli/templates/workflows/error-handler.js +147 -0
  204. package/dist/cli/templates/workflows/foreach.d.ts +7 -0
  205. package/dist/cli/templates/workflows/foreach.js +143 -0
  206. package/dist/cli/templates/workflows/sequential.d.ts +7 -0
  207. package/dist/cli/templates/workflows/sequential.js +198 -0
  208. package/dist/cli/templates/workflows/webhook.d.ts +7 -0
  209. package/dist/cli/templates/workflows/webhook.js +161 -0
  210. package/dist/cli/utils/logger.d.ts +15 -0
  211. package/dist/cli/utils/logger.js +46 -0
  212. package/dist/constants.d.ts +100 -0
  213. package/dist/constants.js +125 -0
  214. package/dist/defaults.d.ts +3 -0
  215. package/dist/defaults.js +3 -0
  216. package/dist/deployment/config/defaults.d.ts +29 -0
  217. package/dist/deployment/config/defaults.js +98 -0
  218. package/dist/deployment/config/loader.d.ts +24 -0
  219. package/dist/deployment/config/loader.js +236 -0
  220. package/dist/deployment/config/types.d.ts +117 -0
  221. package/dist/deployment/config/types.js +5 -0
  222. package/dist/deployment/core/adapters.d.ts +90 -0
  223. package/dist/deployment/core/adapters.js +251 -0
  224. package/dist/deployment/core/executor.d.ts +62 -0
  225. package/dist/deployment/core/executor.js +197 -0
  226. package/dist/deployment/core/formatters.d.ts +57 -0
  227. package/dist/deployment/core/formatters.js +170 -0
  228. package/dist/deployment/index.d.ts +31 -0
  229. package/dist/deployment/index.js +48 -0
  230. package/dist/deployment/openapi/generator.d.ts +146 -0
  231. package/dist/deployment/openapi/generator.js +347 -0
  232. package/dist/deployment/openapi/schema-converter.d.ts +49 -0
  233. package/dist/deployment/openapi/schema-converter.js +192 -0
  234. package/dist/deployment/targets/base.d.ts +316 -0
  235. package/dist/deployment/targets/base.js +823 -0
  236. package/dist/deployment/targets/cloudflare.d.ts +23 -0
  237. package/dist/deployment/targets/cloudflare.js +1125 -0
  238. package/dist/deployment/targets/inngest.d.ts +38 -0
  239. package/dist/deployment/targets/inngest.js +926 -0
  240. package/dist/deployment/targets/lambda.d.ts +23 -0
  241. package/dist/deployment/targets/lambda.js +1289 -0
  242. package/dist/deployment/targets/vercel.d.ts +23 -0
  243. package/dist/deployment/targets/vercel.js +886 -0
  244. package/dist/deployment/types.d.ts +183 -0
  245. package/dist/deployment/types.js +8 -0
  246. package/dist/diagram/geometry.d.ts +26 -0
  247. package/dist/diagram/geometry.js +850 -0
  248. package/dist/diagram/index.d.ts +16 -0
  249. package/dist/diagram/index.js +42 -0
  250. package/dist/diagram/layout.d.ts +11 -0
  251. package/dist/diagram/layout.js +143 -0
  252. package/dist/diagram/orthogonal-router.d.ts +79 -0
  253. package/dist/diagram/orthogonal-router.js +568 -0
  254. package/dist/diagram/renderer.d.ts +3 -0
  255. package/dist/diagram/renderer.js +207 -0
  256. package/dist/diagram/theme.d.ts +20 -0
  257. package/dist/diagram/theme.js +189 -0
  258. package/dist/diagram/types.d.ts +70 -0
  259. package/dist/diagram/types.js +2 -0
  260. package/dist/diff/WorkflowDiffer.d.ts +13 -0
  261. package/dist/diff/WorkflowDiffer.js +429 -0
  262. package/dist/diff/formatDiff.d.ts +10 -0
  263. package/dist/diff/formatDiff.js +220 -0
  264. package/dist/diff/impact.d.ts +29 -0
  265. package/dist/diff/impact.js +119 -0
  266. package/dist/diff/index.d.ts +10 -0
  267. package/dist/diff/index.js +9 -0
  268. package/dist/diff/types.d.ts +138 -0
  269. package/dist/diff/types.js +35 -0
  270. package/dist/doc-metadata/extractors/annotations.d.ts +56 -0
  271. package/dist/doc-metadata/extractors/annotations.js +337 -0
  272. package/dist/doc-metadata/extractors/cli-commands.d.ts +17 -0
  273. package/dist/doc-metadata/extractors/cli-commands.js +355 -0
  274. package/dist/doc-metadata/extractors/mcp-tools.d.ts +16 -0
  275. package/dist/doc-metadata/extractors/mcp-tools.js +689 -0
  276. package/dist/doc-metadata/extractors/plugin-api.d.ts +19 -0
  277. package/dist/doc-metadata/extractors/plugin-api.js +279 -0
  278. package/dist/doc-metadata/index.d.ts +5 -0
  279. package/dist/doc-metadata/index.js +4 -0
  280. package/dist/doc-metadata/types.d.ts +120 -0
  281. package/dist/doc-metadata/types.js +5 -0
  282. package/dist/editor-completions/annotationValues.d.ts +12 -0
  283. package/dist/editor-completions/annotationValues.js +138 -0
  284. package/dist/editor-completions/contextParser.d.ts +40 -0
  285. package/dist/editor-completions/contextParser.js +410 -0
  286. package/dist/editor-completions/dataTypes.d.ts +16 -0
  287. package/dist/editor-completions/dataTypes.js +95 -0
  288. package/dist/editor-completions/goToDefinition.d.ts +27 -0
  289. package/dist/editor-completions/goToDefinition.js +112 -0
  290. package/dist/editor-completions/index.d.ts +39 -0
  291. package/dist/editor-completions/index.js +181 -0
  292. package/dist/editor-completions/jsDocAnnotations.d.ts +29 -0
  293. package/dist/editor-completions/jsDocAnnotations.js +357 -0
  294. package/dist/editor-completions/modifierCompletions.d.ts +17 -0
  295. package/dist/editor-completions/modifierCompletions.js +197 -0
  296. package/dist/editor-completions/types.d.ts +119 -0
  297. package/dist/editor-completions/types.js +8 -0
  298. package/dist/export/index.d.ts +68 -0
  299. package/dist/export/index.js +1074 -0
  300. package/dist/export/templates.d.ts +24 -0
  301. package/dist/export/templates.js +186 -0
  302. package/dist/friendly-errors.d.ts +35 -0
  303. package/dist/friendly-errors.js +375 -0
  304. package/dist/function-like.d.ts +38 -0
  305. package/dist/function-like.js +83 -0
  306. package/dist/generated-branding.d.ts +16 -0
  307. package/dist/generated-branding.js +22 -0
  308. package/dist/generator/async-detection.d.ts +27 -0
  309. package/dist/generator/async-detection.js +56 -0
  310. package/dist/generator/code-utils.d.ts +76 -0
  311. package/dist/generator/code-utils.js +410 -0
  312. package/dist/generator/control-flow.d.ts +54 -0
  313. package/dist/generator/control-flow.js +284 -0
  314. package/dist/generator/inngest.d.ts +53 -0
  315. package/dist/generator/inngest.js +1126 -0
  316. package/dist/generator/scope-function-generator.d.ts +78 -0
  317. package/dist/generator/scope-function-generator.js +360 -0
  318. package/dist/generator/unified.d.ts +42 -0
  319. package/dist/generator/unified.js +1504 -0
  320. package/dist/generator.d.ts +54 -0
  321. package/dist/generator.js +100 -0
  322. package/dist/index.d.ts +85 -0
  323. package/dist/index.js +89 -0
  324. package/dist/jsdoc-parser.d.ts +308 -0
  325. package/dist/jsdoc-parser.js +923 -0
  326. package/dist/jsdoc-port-sync/constants.d.ts +41 -0
  327. package/dist/jsdoc-port-sync/constants.js +103 -0
  328. package/dist/jsdoc-port-sync/diff.d.ts +76 -0
  329. package/dist/jsdoc-port-sync/diff.js +319 -0
  330. package/dist/jsdoc-port-sync/index.d.ts +42 -0
  331. package/dist/jsdoc-port-sync/index.js +45 -0
  332. package/dist/jsdoc-port-sync/port-parser.d.ts +68 -0
  333. package/dist/jsdoc-port-sync/port-parser.js +579 -0
  334. package/dist/jsdoc-port-sync/rename.d.ts +21 -0
  335. package/dist/jsdoc-port-sync/rename.js +256 -0
  336. package/dist/jsdoc-port-sync/signature-parser.d.ts +104 -0
  337. package/dist/jsdoc-port-sync/signature-parser.js +559 -0
  338. package/dist/jsdoc-port-sync/sync.d.ts +36 -0
  339. package/dist/jsdoc-port-sync/sync.js +644 -0
  340. package/dist/jsdoc-port-sync.d.ts +10 -0
  341. package/dist/jsdoc-port-sync.js +10 -0
  342. package/dist/marketplace/index.d.ts +11 -0
  343. package/dist/marketplace/index.js +10 -0
  344. package/dist/marketplace/manifest.d.ts +32 -0
  345. package/dist/marketplace/manifest.js +176 -0
  346. package/dist/marketplace/registry.d.ts +30 -0
  347. package/dist/marketplace/registry.js +100 -0
  348. package/dist/marketplace/types.d.ts +154 -0
  349. package/dist/marketplace/types.js +9 -0
  350. package/dist/marketplace/validator.d.ts +13 -0
  351. package/dist/marketplace/validator.js +131 -0
  352. package/dist/mcp/auto-registration.d.ts +3 -0
  353. package/dist/mcp/auto-registration.js +62 -0
  354. package/dist/mcp/editor-connection.d.ts +50 -0
  355. package/dist/mcp/editor-connection.js +125 -0
  356. package/dist/mcp/event-buffer.d.ts +62 -0
  357. package/dist/mcp/event-buffer.js +150 -0
  358. package/dist/mcp/index.d.ts +12 -0
  359. package/dist/mcp/index.js +11 -0
  360. package/dist/mcp/resources.d.ts +14 -0
  361. package/dist/mcp/resources.js +55 -0
  362. package/dist/mcp/response-utils.d.ts +63 -0
  363. package/dist/mcp/response-utils.js +89 -0
  364. package/dist/mcp/server.d.ts +4 -0
  365. package/dist/mcp/server.js +99 -0
  366. package/dist/mcp/tools-diagram.d.ts +8 -0
  367. package/dist/mcp/tools-diagram.js +53 -0
  368. package/dist/mcp/tools-editor.d.ts +5 -0
  369. package/dist/mcp/tools-editor.js +190 -0
  370. package/dist/mcp/tools-export.d.ts +9 -0
  371. package/dist/mcp/tools-export.js +180 -0
  372. package/dist/mcp/tools-marketplace.d.ts +9 -0
  373. package/dist/mcp/tools-marketplace.js +132 -0
  374. package/dist/mcp/tools-pattern.d.ts +3 -0
  375. package/dist/mcp/tools-pattern.js +783 -0
  376. package/dist/mcp/tools-query.d.ts +3 -0
  377. package/dist/mcp/tools-query.js +364 -0
  378. package/dist/mcp/tools-template.d.ts +10 -0
  379. package/dist/mcp/tools-template.js +119 -0
  380. package/dist/mcp/types.d.ts +70 -0
  381. package/dist/mcp/types.js +8 -0
  382. package/dist/mcp/workflow-executor.d.ts +47 -0
  383. package/dist/mcp/workflow-executor.js +133 -0
  384. package/dist/migration/registry.d.ts +30 -0
  385. package/dist/migration/registry.js +29 -0
  386. package/dist/node-types-generator.d.ts +49 -0
  387. package/dist/node-types-generator.js +139 -0
  388. package/dist/npm-packages.d.ts +56 -0
  389. package/dist/npm-packages.js +255 -0
  390. package/dist/parser.d.ts +204 -0
  391. package/dist/parser.js +2100 -0
  392. package/dist/plugin/PluginPanel.d.ts +12 -0
  393. package/dist/plugin/PluginPanel.js +5 -0
  394. package/dist/plugin/index.d.ts +13 -0
  395. package/dist/plugin/index.js +14 -0
  396. package/dist/plugin/types.d.ts +75 -0
  397. package/dist/plugin/types.js +8 -0
  398. package/dist/resolve-package-types.d.ts +17 -0
  399. package/dist/resolve-package-types.js +123 -0
  400. package/dist/runtime/CancellationError.d.ts +11 -0
  401. package/dist/runtime/CancellationError.js +20 -0
  402. package/dist/runtime/ExecutionContext.d.ts +146 -0
  403. package/dist/runtime/ExecutionContext.js +235 -0
  404. package/dist/runtime/builtin-functions.d.ts +8 -0
  405. package/dist/runtime/builtin-functions.js +549 -0
  406. package/dist/runtime/events.d.ts +50 -0
  407. package/dist/runtime/events.js +2 -0
  408. package/dist/runtime/function-registry.d.ts +59 -0
  409. package/dist/runtime/function-registry.js +66 -0
  410. package/dist/runtime/index.d.ts +7 -0
  411. package/dist/runtime/index.js +7 -0
  412. package/dist/runtime/parameter-resolver.d.ts +62 -0
  413. package/dist/runtime/parameter-resolver.js +113 -0
  414. package/dist/server/index.d.ts +7 -0
  415. package/dist/server/index.js +6 -0
  416. package/dist/server/types.d.ts +93 -0
  417. package/dist/server/types.js +5 -0
  418. package/dist/server/webhook-server.d.ts +50 -0
  419. package/dist/server/webhook-server.js +269 -0
  420. package/dist/server/workflow-registry.d.ts +61 -0
  421. package/dist/server/workflow-registry.js +202 -0
  422. package/dist/shared-project.d.ts +9 -0
  423. package/dist/shared-project.js +28 -0
  424. package/dist/sugar-optimizer.d.ts +40 -0
  425. package/dist/sugar-optimizer.js +387 -0
  426. package/dist/testing/assertions.d.ts +51 -0
  427. package/dist/testing/assertions.js +127 -0
  428. package/dist/testing/index.d.ts +30 -0
  429. package/dist/testing/index.js +24 -0
  430. package/dist/testing/mock-approval.d.ts +81 -0
  431. package/dist/testing/mock-approval.js +98 -0
  432. package/dist/testing/mock-llm.d.ts +124 -0
  433. package/dist/testing/mock-llm.js +119 -0
  434. package/dist/testing/recorder.d.ts +72 -0
  435. package/dist/testing/recorder.js +70 -0
  436. package/dist/testing/replayer.d.ts +56 -0
  437. package/dist/testing/replayer.js +143 -0
  438. package/dist/testing/token-tracker.d.ts +71 -0
  439. package/dist/testing/token-tracker.js +94 -0
  440. package/dist/type-checker.d.ts +42 -0
  441. package/dist/type-checker.js +190 -0
  442. package/dist/type-mappings.d.ts +29 -0
  443. package/dist/type-mappings.js +125 -0
  444. package/dist/types/branded-ports.d.ts +151 -0
  445. package/dist/types/branded-ports.js +121 -0
  446. package/dist/types/index.d.ts +5 -0
  447. package/dist/types/index.js +5 -0
  448. package/dist/types.d.ts +139 -0
  449. package/dist/types.js +15 -0
  450. package/dist/utils/error-utils.d.ts +15 -0
  451. package/dist/utils/error-utils.js +27 -0
  452. package/dist/utils/lru-cache.d.ts +15 -0
  453. package/dist/utils/lru-cache.js +40 -0
  454. package/dist/utils/port-ordering.d.ts +26 -0
  455. package/dist/utils/port-ordering.js +88 -0
  456. package/dist/utils/port-tag-utils.d.ts +23 -0
  457. package/dist/utils/port-tag-utils.js +41 -0
  458. package/dist/utils/string-distance.d.ts +14 -0
  459. package/dist/utils/string-distance.js +56 -0
  460. package/dist/validation/agent-detection.d.ts +33 -0
  461. package/dist/validation/agent-detection.js +115 -0
  462. package/dist/validation/agent-rules.d.ts +48 -0
  463. package/dist/validation/agent-rules.js +262 -0
  464. package/dist/validator.d.ts +92 -0
  465. package/dist/validator.js +970 -0
  466. package/package.json +109 -0
@@ -0,0 +1,850 @@
1
+ import { isExecutePort, isSuccessPort, isFailurePort, SCOPED_PORT_NAMES, isScopedStartPort, isScopedSuccessPort, isScopedFailurePort } from '../constants.js';
2
+ import { assignImplicitPortOrders } from '../utils/port-ordering.js';
3
+ import { getPortColor, NODE_VARIANT_COLORS, TYPE_ABBREVIATIONS } from './theme.js';
4
+ import { layoutWorkflow } from './layout.js';
5
+ import { calculateOrthogonalPathSafe, TrackAllocator } from './orthogonal-router.js';
6
+ // ---- Constants (matching React component-node) ----
7
+ export const PORT_RADIUS = 7;
8
+ export const PORT_SIZE = PORT_RADIUS * 2; // 14px — matches portRootStyle
9
+ export const PORT_GAP = 8; // matches port column gap
10
+ export const PORT_PADDING_Y = 18; // matches inputsStyle paddingTop/Bottom
11
+ export const NODE_MIN_WIDTH = 90; // matches NODE_MIN_WIDTH in styles.ts
12
+ export const NODE_MIN_HEIGHT = 90; // matches NODE_MIN_HEIGHT in styles.ts
13
+ export const BORDER_RADIUS = 6; // matches wrapperStyle borderRadius
14
+ export const LAYER_GAP_X = 220;
15
+ export const NODE_GAP_Y = 60;
16
+ export const LABEL_HEIGHT = 20; // 13px font + padding
17
+ export const LABEL_GAP = 12; // matches labelRootStyle bottom: calc(100% + 12px)
18
+ // Scope rendering constants
19
+ export const SCOPE_PADDING = 40; // padding around scope area inside parent
20
+ export const SCOPE_PORT_COLUMN = 50; // width for scoped port column on inner edges
21
+ export const SCOPE_INNER_GAP_X = 160; // horizontal gap between children inside scope
22
+ // Routing mode threshold — connections longer than this use orthogonal routing
23
+ // (midpoint of original 250–350 hysteresis thresholds)
24
+ export const ORTHOGONAL_DISTANCE_THRESHOLD = 300;
25
+ // ---- Font metrics (Montserrat 600-weight, 10px — measured via SVG getBBox) ----
26
+ const CHAR_WIDTHS = {
27
+ ' ': 2.78, '!': 3.34, '"': 4.74, '#': 5.56, '$': 5.56, '%': 8.9, '&': 7.23,
28
+ "'": 2.38, '(': 3.34, ')': 3.34, '*': 3.9, '+': 5.84, ',': 2.78, '-': 3.34,
29
+ '.': 2.78, '/': 3.95, '0': 5.56, '1': 5.56, '2': 5.56, '3': 5.56, '4': 5.56,
30
+ '5': 5.56, '6': 5.56, '7': 5.56, '8': 5.56, '9': 5.56, ':': 3.34, ';': 3.34,
31
+ '<': 5.86, '=': 5.84, '>': 5.86, '?': 6.11, '@': 9.76,
32
+ A: 7.23, B: 7.23, C: 7.23, D: 7.23, E: 6.67, F: 6.11, G: 7.78, H: 7.23,
33
+ I: 2.78, J: 5.56, K: 7.23, L: 6.11, M: 8.34, N: 7.23, O: 7.78, P: 6.67,
34
+ Q: 7.78, R: 7.23, S: 6.67, T: 6.11, U: 7.23, V: 6.67, W: 9.45, X: 6.67,
35
+ Y: 6.67, Z: 6.11, '[': 3.34, '\\': 3.95, ']': 3.34, '^': 5.84, '_': 5.56, '`': 3.58,
36
+ a: 5.56, b: 6.11, c: 5.56, d: 6.11, e: 5.56, f: 3.34, g: 6.11, h: 6.11,
37
+ i: 2.78, j: 2.78, k: 5.56, l: 2.78, m: 8.9, n: 6.11, o: 6.11, p: 6.11,
38
+ q: 6.11, r: 3.9, s: 5.56, t: 3.34, u: 6.11, v: 5.56, w: 7.78, x: 5.56,
39
+ y: 5.56, z: 5, '{': 3.9, '|': 2.8, '}': 3.9, '~': 5.96,
40
+ };
41
+ const DEFAULT_CHAR_WIDTH = 5.56;
42
+ /** Measure text width using pre-computed Montserrat 600/10px SVG character widths */
43
+ export function measureText(text) {
44
+ let width = 0;
45
+ for (let i = 0; i < text.length; i++) {
46
+ width += CHAR_WIDTHS[text[i]] ?? DEFAULT_CHAR_WIDTH;
47
+ }
48
+ return width;
49
+ }
50
+ // ---- Dimension computation ----
51
+ export function computeNodeDimensions(node) {
52
+ const maxPorts = Math.max(node.inputs.length, node.outputs.length);
53
+ // React: paddingTop + n * (PORT_SIZE + PORT_GAP) - PORT_GAP + paddingBottom
54
+ const portsHeight = maxPorts > 0
55
+ ? PORT_PADDING_Y + maxPorts * PORT_SIZE + (maxPorts - 1) * PORT_GAP + PORT_PADDING_Y
56
+ : 0;
57
+ node.width = NODE_MIN_WIDTH;
58
+ node.height = Math.max(NODE_MIN_HEIGHT, portsHeight);
59
+ }
60
+ // ---- Port positions ----
61
+ export function computePortPositions(node) {
62
+ positionPortList(node.inputs, node.x, node.y, node.height);
63
+ positionPortList(node.outputs, node.x + node.width, node.y, node.height);
64
+ }
65
+ function positionPortList(ports, cx, nodeY, _nodeHeight) {
66
+ if (ports.length === 0)
67
+ return;
68
+ // Matches React portPositionCalculator: y = nodeY + paddingTop + i * (size + gap) + size/2
69
+ for (let i = 0; i < ports.length; i++) {
70
+ ports[i].cx = cx;
71
+ ports[i].cy = nodeY + PORT_PADDING_Y + i * (PORT_SIZE + PORT_GAP) + PORT_SIZE / 2;
72
+ }
73
+ }
74
+ // ---- Connection path (ported from connectionCalculator.ts) ----
75
+ /**
76
+ * Compute a quad-curve connection from B towards D with consistent tangent.
77
+ * U is a unit vector from B to C with the same slope as B→D.
78
+ */
79
+ function quadCurveControl(ax, ay, bx, by, ux, uy) {
80
+ const dn = Math.abs(ay - by);
81
+ const cx = bx + (ux * dn) / Math.abs(uy);
82
+ const cy = ay;
83
+ return [cx, cy];
84
+ }
85
+ export function computeConnectionPath(sx, sy, tx, ty) {
86
+ const e = 0.0001; // insignificant shift to avoid degenerate tangents
87
+ const ax = sx + e;
88
+ const ay = sy + e;
89
+ const hx = tx - e;
90
+ const hy = ty - e;
91
+ const ramp = Math.min(20, (hx - ax) / 10);
92
+ const bx = ax + ramp;
93
+ const by = ay + e;
94
+ const gx = hx - ramp;
95
+ const gy = hy - e;
96
+ const curveSizeX = Math.min(60, Math.abs(ax - hx) / 4);
97
+ const curveSizeY = Math.min(60, Math.abs(ay - hy) / 4);
98
+ const curveMag = Math.sqrt(curveSizeX * curveSizeX + curveSizeY * curveSizeY);
99
+ const bgX = gx - bx;
100
+ const bgY = gy - by;
101
+ const bgLen = Math.sqrt(bgX * bgX + bgY * bgY);
102
+ const bgUx = bgX / bgLen;
103
+ const bgUy = bgY / bgLen;
104
+ const dx = bx + bgUx * curveMag;
105
+ const dy = by + (bgUy * curveMag) / 2;
106
+ const ex = gx - bgUx * curveMag;
107
+ const ey = gy - (bgUy * curveMag) / 2;
108
+ const deX = ex - dx;
109
+ const deY = ey - dy;
110
+ const deLen = Math.sqrt(deX * deX + deY * deY);
111
+ const deUx = deX / deLen;
112
+ const deUy = deY / deLen;
113
+ const [cx, cy] = quadCurveControl(bx, by, dx, dy, -deUx, -deUy);
114
+ const [fx, fy] = quadCurveControl(gx, gy, ex, ey, deUx, deUy);
115
+ let path = `M ${cx},${cy} M ${ax},${ay}`;
116
+ path += ` L ${bx},${by}`;
117
+ path += ` Q ${cx},${cy} ${dx},${dy}`;
118
+ path += ` L ${ex},${ey}`;
119
+ path += ` Q ${fx},${fy} ${gx},${gy}`;
120
+ path += ` L ${hx},${hy}`;
121
+ return path;
122
+ }
123
+ /** @deprecated Use computeConnectionPath instead */
124
+ export function computeBezierPath(sx, sy, tx, ty) {
125
+ return computeConnectionPath(sx, sy, tx, ty);
126
+ }
127
+ // ---- Port ordering helpers ----
128
+ /**
129
+ * Get ordered ports from a port definition record using metadata.order.
130
+ * Uses assignImplicitPortOrders to ensure all ports have proper ordering
131
+ * (mandatory ports like execute/onSuccess/onFailure get precedence).
132
+ */
133
+ function orderedPorts(ports, direction) {
134
+ // Clone port definitions so assignImplicitPortOrders can mutate safely
135
+ const cloned = {};
136
+ for (const [name, def] of Object.entries(ports)) {
137
+ cloned[name] = { ...def, metadata: def.metadata ? { ...def.metadata } : undefined };
138
+ }
139
+ // Ensure all ports have order values (mandatory ports get precedence)
140
+ assignImplicitPortOrders(cloned);
141
+ return Object.entries(cloned)
142
+ .sort(([, a], [, b]) => {
143
+ const orderA = a.metadata?.order ?? Infinity;
144
+ const orderB = b.metadata?.order ?? Infinity;
145
+ return orderA - orderB;
146
+ })
147
+ .map(([name, def]) => ({
148
+ name,
149
+ label: def.label ?? name,
150
+ dataType: def.dataType,
151
+ direction,
152
+ isControlFlow: def.dataType === 'STEP',
153
+ isFailure: !!def.failure,
154
+ cx: 0,
155
+ cy: 0,
156
+ }));
157
+ }
158
+ // ---- Instance node builder (shared by main graph and scope sub-graphs) ----
159
+ function buildInstanceNode(instId, instNodeType, instConfig, nodeTypeMap, theme = 'dark') {
160
+ const nt = nodeTypeMap.get(instNodeType);
161
+ const allInputs = nt
162
+ ? { ...filterNonScopedPorts(nt.inputs) }
163
+ : {};
164
+ const allOutputs = nt
165
+ ? { ...filterNonScopedPorts(nt.outputs) }
166
+ : {};
167
+ if (nt && !nt.expression) {
168
+ if (!allInputs.execute)
169
+ allInputs.execute = { dataType: 'STEP' };
170
+ }
171
+ if (nt && nt.hasSuccessPort && !allOutputs.onSuccess) {
172
+ allOutputs.onSuccess = { dataType: 'STEP', isControlFlow: true };
173
+ }
174
+ if (nt && nt.hasFailurePort && !allOutputs.onFailure) {
175
+ allOutputs.onFailure = { dataType: 'STEP', isControlFlow: true, failure: true };
176
+ }
177
+ // Resolve icon: instance config → node type visuals → auto-detection
178
+ const resolvedIcon = instConfig?.icon
179
+ ?? nt?.visuals?.icon
180
+ ?? resolveDefaultIcon(nt);
181
+ return {
182
+ id: instId,
183
+ label: instConfig?.label ?? nt?.label ?? instId,
184
+ color: resolveNodeColor(instConfig?.color ?? nt?.visuals?.color, theme),
185
+ icon: resolvedIcon,
186
+ isVirtual: false,
187
+ inputs: orderedPorts(allInputs, 'INPUT'),
188
+ outputs: orderedPorts(allOutputs, 'OUTPUT'),
189
+ x: 0, y: 0,
190
+ width: NODE_MIN_WIDTH,
191
+ height: NODE_MIN_HEIGHT,
192
+ };
193
+ }
194
+ // ---- Scope sub-graph builder ----
195
+ function buildScopeSubGraph(parentNode, parentNt, scopeName, childIds, ast, nodeTypeMap, theme = 'dark') {
196
+ const childIdSet = new Set(childIds);
197
+ // Extract scoped port definitions from parent's node type (ports with explicit scope marker)
198
+ const scopedOutputDefs = {};
199
+ const scopedInputDefs = {};
200
+ for (const [name, def] of Object.entries(parentNt.outputs)) {
201
+ if (def.scope === scopeName)
202
+ scopedOutputDefs[name] = def;
203
+ }
204
+ for (const [name, def] of Object.entries(parentNt.inputs)) {
205
+ if (def.scope === scopeName)
206
+ scopedInputDefs[name] = def;
207
+ }
208
+ // Derive additional scope ports from connections involving scope children.
209
+ // Parent→child connections need a scope OUTPUT port (left inner edge).
210
+ // Child→parent connections need a scope INPUT port (right inner edge).
211
+ for (const conn of ast.connections) {
212
+ // Parent → child: parent's output becomes scope output
213
+ if (conn.from.node === parentNode.id && childIdSet.has(conn.to.node)) {
214
+ const portName = conn.from.port;
215
+ if (!scopedOutputDefs[portName]) {
216
+ const parentDef = parentNt.outputs[portName];
217
+ if (parentDef) {
218
+ // Move existing output from external to scoped
219
+ scopedOutputDefs[portName] = { ...parentDef, scope: scopeName };
220
+ }
221
+ else {
222
+ // Implicit scoped port (e.g. forEach.item:iteration) — infer type and label from child
223
+ const childInst = ast.instances.find(i => i.id === conn.to.node);
224
+ const childNt = childInst ? nodeTypeMap.get(childInst.nodeType) : undefined;
225
+ const childInputDef = childNt?.inputs[conn.to.port];
226
+ scopedOutputDefs[portName] = {
227
+ dataType: childInputDef?.dataType ?? 'ANY',
228
+ scope: scopeName,
229
+ label: childInputDef?.label ?? portName,
230
+ };
231
+ }
232
+ }
233
+ }
234
+ // Child → parent: parent's input becomes scope input
235
+ if (conn.to.node === parentNode.id && childIdSet.has(conn.from.node)) {
236
+ const portName = conn.to.port;
237
+ if (!scopedInputDefs[portName]) {
238
+ const parentDef = parentNt.inputs[portName];
239
+ if (parentDef) {
240
+ scopedInputDefs[portName] = { ...parentDef, scope: scopeName };
241
+ }
242
+ else {
243
+ // Implicit scoped port — infer type and label from child
244
+ const childInst = ast.instances.find(i => i.id === conn.from.node);
245
+ const childNt = childInst ? nodeTypeMap.get(childInst.nodeType) : undefined;
246
+ const childOutputDef = childNt?.outputs[conn.from.port];
247
+ scopedInputDefs[portName] = {
248
+ dataType: childOutputDef?.dataType ?? 'ANY',
249
+ scope: scopeName,
250
+ label: childOutputDef?.label ?? portName,
251
+ };
252
+ }
253
+ }
254
+ }
255
+ }
256
+ // Add mandatory STEP scope ports for non-expression scoped nodes.
257
+ // Use scoped port names (start/success/failure) so assignImplicitPortOrders gives them priority.
258
+ if (!parentNt.expression) {
259
+ if (!scopedOutputDefs[SCOPED_PORT_NAMES.START]) {
260
+ scopedOutputDefs[SCOPED_PORT_NAMES.START] = { dataType: 'STEP', scope: scopeName, label: 'Execute' };
261
+ }
262
+ if (!scopedInputDefs[SCOPED_PORT_NAMES.SUCCESS]) {
263
+ scopedInputDefs[SCOPED_PORT_NAMES.SUCCESS] = { dataType: 'STEP', isControlFlow: true, scope: scopeName, label: 'On Success' };
264
+ }
265
+ if (!scopedInputDefs[SCOPED_PORT_NAMES.FAILURE]) {
266
+ scopedInputDefs[SCOPED_PORT_NAMES.FAILURE] = { dataType: 'STEP', isControlFlow: true, scope: scopeName, failure: true, label: 'On Failure' };
267
+ }
268
+ }
269
+ // Remove scope-derived ports from parent's external port lists
270
+ // (they should only appear on inner edges, not outer edges)
271
+ parentNode.outputs = parentNode.outputs.filter(p => !scopedOutputDefs[p.name]);
272
+ parentNode.inputs = parentNode.inputs.filter(p => !scopedInputDefs[p.name]);
273
+ const scopeOutputPorts = orderedPorts(scopedOutputDefs, 'OUTPUT');
274
+ const scopeInputPorts = orderedPorts(scopedInputDefs, 'INPUT');
275
+ // Build child nodes
276
+ const children = [];
277
+ const childNodeMap = new Map();
278
+ for (const childId of childIds) {
279
+ const childInst = ast.instances.find(i => i.id === childId);
280
+ if (!childInst)
281
+ continue;
282
+ const childNode = buildInstanceNode(childId, childInst.nodeType, childInst.config, nodeTypeMap, theme);
283
+ computeNodeDimensions(childNode);
284
+ children.push(childNode);
285
+ childNodeMap.set(childId, childNode);
286
+ }
287
+ if (children.length === 0)
288
+ return;
289
+ // Layout children left-to-right in local coordinates
290
+ let childX = 0;
291
+ const maxChildHeight = Math.max(...children.map(c => c.height + LABEL_HEIGHT + LABEL_GAP));
292
+ for (const child of children) {
293
+ child.x = childX;
294
+ child.y = LABEL_HEIGHT + LABEL_GAP + (maxChildHeight - LABEL_HEIGHT - LABEL_GAP - child.height) / 2;
295
+ childX += child.width + SCOPE_INNER_GAP_X;
296
+ }
297
+ const childrenWidth = childX > 0 ? childX - SCOPE_INNER_GAP_X : 0;
298
+ const childrenHeight = maxChildHeight;
299
+ // Compute scope port column heights
300
+ const scopeOutPortsHeight = portsColumnHeight(scopeOutputPorts.length);
301
+ const scopeInPortsHeight = portsColumnHeight(scopeInputPorts.length);
302
+ // Use persisted UI dimensions if available, otherwise compute from children
303
+ const parentUI = ast.ui?.instances?.find(u => u.name === parentNode.id);
304
+ const uiWidth = parentUI?.expandedWidth ?? parentUI?.width;
305
+ const uiHeight = parentUI?.expandedHeight ?? parentUI?.height;
306
+ const computedWidth = SCOPE_PORT_COLUMN + SCOPE_PADDING + childrenWidth + SCOPE_PADDING + SCOPE_PORT_COLUMN;
307
+ const computedHeight = SCOPE_PADDING * 2 + Math.max(childrenHeight, scopeOutPortsHeight, scopeInPortsHeight);
308
+ parentNode.width = Math.max(parentNode.width, uiWidth ?? computedWidth);
309
+ parentNode.height = Math.max(parentNode.height, uiHeight ?? computedHeight);
310
+ // Store scope data (children positions are in local coordinates, will be offset later)
311
+ parentNode.scopeChildren = children;
312
+ parentNode.scopePorts = { inputs: scopeInputPorts, outputs: scopeOutputPorts };
313
+ parentNode.scopeConnections = []; // populated after positioning
314
+ }
315
+ /** Position scope children and ports relative to the parent's final position */
316
+ function finalizeScopePositions(parentNode, ast, theme = 'dark') {
317
+ const children = parentNode.scopeChildren;
318
+ const scopePorts = parentNode.scopePorts;
319
+ if (!children || children.length === 0 || !scopePorts)
320
+ return;
321
+ // Scope inner area (between the two port columns)
322
+ const innerLeft = parentNode.x + SCOPE_PORT_COLUMN + SCOPE_PADDING;
323
+ const innerRight = parentNode.x + parentNode.width - SCOPE_PORT_COLUMN - SCOPE_PADDING;
324
+ const innerWidth = innerRight - innerLeft;
325
+ // Compute children block width from local coordinates
326
+ const lastChild = children[children.length - 1];
327
+ const childrenBlockWidth = lastChild.x + lastChild.width;
328
+ // Center children horizontally within the inner area
329
+ const centerOffsetX = innerLeft + (innerWidth - childrenBlockWidth) / 2;
330
+ const scopeOriginY = parentNode.y + SCOPE_PADDING;
331
+ // Offset children to absolute positions
332
+ for (const child of children) {
333
+ child.x += centerOffsetX;
334
+ child.y += scopeOriginY;
335
+ computePortPositions(child);
336
+ }
337
+ // Position scoped output ports on left inner edge
338
+ const leftEdgeX = parentNode.x + SCOPE_PORT_COLUMN;
339
+ positionPortList(scopePorts.outputs, leftEdgeX, parentNode.y, parentNode.height);
340
+ // Position scoped input ports on right inner edge
341
+ const rightEdgeX = parentNode.x + parentNode.width - SCOPE_PORT_COLUMN;
342
+ positionPortList(scopePorts.inputs, rightEdgeX, parentNode.y, parentNode.height);
343
+ // Build scope connections — match by child membership, not scope qualifiers
344
+ const childNodeMap = new Map();
345
+ for (const child of children)
346
+ childNodeMap.set(child.id, child);
347
+ const childIdSet = new Set(children.map(c => c.id));
348
+ parentNode.scopeConnections = [];
349
+ for (const conn of ast.connections) {
350
+ const fromIsChild = childIdSet.has(conn.from.node);
351
+ const toIsChild = childIdSet.has(conn.to.node);
352
+ const fromIsParent = conn.from.node === parentNode.id;
353
+ const toIsParent = conn.to.node === parentNode.id;
354
+ // Only process connections that involve at least one scope child
355
+ if (!fromIsChild && !toIsChild)
356
+ continue;
357
+ // Parent port → child input (scope output feeds child)
358
+ if (fromIsParent && toIsChild) {
359
+ const sourcePort = scopePorts.outputs.find(p => p.name === conn.from.port);
360
+ const targetChild = childNodeMap.get(conn.to.node);
361
+ const targetPort = targetChild?.inputs.find(p => p.name === conn.to.port);
362
+ if (sourcePort && targetPort) {
363
+ parentNode.scopeConnections.push(buildConnection(parentNode.id, conn.from.port, conn.to.node, conn.to.port, sourcePort, targetPort, theme));
364
+ }
365
+ continue;
366
+ }
367
+ // Child output → parent port (child feeds scope input)
368
+ if (fromIsChild && toIsParent) {
369
+ const sourceChild = childNodeMap.get(conn.from.node);
370
+ const sourcePort = sourceChild?.outputs.find(p => p.name === conn.from.port);
371
+ const targetPort = scopePorts.inputs.find(p => p.name === conn.to.port);
372
+ if (sourcePort && targetPort) {
373
+ parentNode.scopeConnections.push(buildConnection(conn.from.node, conn.from.port, parentNode.id, conn.to.port, sourcePort, targetPort, theme));
374
+ }
375
+ continue;
376
+ }
377
+ // Child → child within scope
378
+ if (fromIsChild && toIsChild) {
379
+ const sourceChild = childNodeMap.get(conn.from.node);
380
+ const targetChild = childNodeMap.get(conn.to.node);
381
+ if (sourceChild && targetChild) {
382
+ const sourcePort = sourceChild.outputs.find(p => p.name === conn.from.port);
383
+ const targetPort = targetChild.inputs.find(p => p.name === conn.to.port);
384
+ if (sourcePort && targetPort) {
385
+ parentNode.scopeConnections.push(buildConnection(conn.from.node, conn.from.port, conn.to.node, conn.to.port, sourcePort, targetPort, theme));
386
+ }
387
+ }
388
+ continue;
389
+ }
390
+ // Cross-scope: child → external or external → child
391
+ // These are handled in the main connection loop (which looks up scope children)
392
+ }
393
+ // Auto-connect mandatory STEP scope ports that have no explicit connections.
394
+ // scope.execute → first child's execute, last child's onSuccess/onFailure → scope inputs.
395
+ if (children.length > 0) {
396
+ const connectedScopePorts = new Set(parentNode.scopeConnections.map(c => c.fromNode === parentNode.id ? `out:${c.fromPort}` : `in:${c.toPort}`).filter(k => k.startsWith('out:') || k.startsWith('in:')));
397
+ const firstChild = children[0];
398
+ const lastChild = children[children.length - 1];
399
+ // scope.start → first child.execute (scoped port uses "start", child uses "execute")
400
+ const execScopePort = scopePorts.outputs.find(p => isScopedStartPort(p.name));
401
+ const execChildPort = firstChild.inputs.find(p => isExecutePort(p.name));
402
+ if (execScopePort && execChildPort && !connectedScopePorts.has(`out:${execScopePort.name}`)) {
403
+ parentNode.scopeConnections.push(buildConnection(parentNode.id, execScopePort.name, firstChild.id, execChildPort.name, execScopePort, execChildPort, theme));
404
+ }
405
+ // last child.onSuccess → scope.success (child uses "onSuccess", scoped port uses "success")
406
+ const successScopePort = scopePorts.inputs.find(p => isScopedSuccessPort(p.name));
407
+ const successChildPort = lastChild.outputs.find(p => isSuccessPort(p.name));
408
+ if (successScopePort && successChildPort && !connectedScopePorts.has(`in:${successScopePort.name}`)) {
409
+ parentNode.scopeConnections.push(buildConnection(lastChild.id, successChildPort.name, parentNode.id, successScopePort.name, successChildPort, successScopePort, theme));
410
+ }
411
+ // last child.onFailure → scope.failure (child uses "onFailure", scoped port uses "failure")
412
+ const failureScopePort = scopePorts.inputs.find(p => isScopedFailurePort(p.name));
413
+ const failureChildPort = lastChild.outputs.find(p => isFailurePort(p.name));
414
+ if (failureScopePort && failureChildPort && !connectedScopePorts.has(`in:${failureScopePort.name}`)) {
415
+ parentNode.scopeConnections.push(buildConnection(lastChild.id, failureChildPort.name, parentNode.id, failureScopePort.name, failureChildPort, failureScopePort, theme));
416
+ }
417
+ }
418
+ }
419
+ function buildConnection(fromNode, fromPort, toNode, toPort, sourcePort, targetPort, theme = 'dark') {
420
+ const sourceColor = getPortColor(sourcePort.dataType, sourcePort.isFailure, theme);
421
+ const targetColor = getPortColor(targetPort.dataType, targetPort.isFailure, theme);
422
+ const path = computeConnectionPath(sourcePort.cx, sourcePort.cy, targetPort.cx, targetPort.cy);
423
+ return {
424
+ fromNode, fromPort, toNode, toPort,
425
+ sourceColor, targetColor,
426
+ isStepConnection: sourcePort.dataType === 'STEP',
427
+ path,
428
+ };
429
+ }
430
+ function portsColumnHeight(count) {
431
+ if (count === 0)
432
+ return 0;
433
+ return PORT_PADDING_Y + count * PORT_SIZE + (count - 1) * PORT_GAP + PORT_PADDING_Y;
434
+ }
435
+ // ---- Main orchestrator ----
436
+ export function buildDiagramGraph(ast, options = {}) {
437
+ const themeName = options.theme ?? 'dark';
438
+ const nodeTypeMap = new Map();
439
+ for (const nt of ast.nodeTypes) {
440
+ nodeTypeMap.set(nt.name, nt);
441
+ if (nt.functionName && nt.functionName !== nt.name) {
442
+ nodeTypeMap.set(nt.functionName, nt);
443
+ }
444
+ }
445
+ // Track scoped children — from explicit ast.scopes and from scope-qualified connections
446
+ const scopedChildren = new Set();
447
+ const allScopes = { ...(ast.scopes ?? {}) };
448
+ if (ast.scopes) {
449
+ for (const children of Object.values(ast.scopes)) {
450
+ for (const child of children)
451
+ scopedChildren.add(child);
452
+ }
453
+ }
454
+ // Infer scopes from per-port scope annotations (connections with :scopeName qualifiers)
455
+ const inferredScopes = new Map();
456
+ for (const conn of ast.connections) {
457
+ if (conn.from.scope) {
458
+ const key = `${conn.from.node}.${conn.from.scope}`;
459
+ if (!inferredScopes.has(key))
460
+ inferredScopes.set(key, new Set());
461
+ inferredScopes.get(key).add(conn.to.node);
462
+ }
463
+ if (conn.to.scope) {
464
+ const key = `${conn.to.node}.${conn.to.scope}`;
465
+ if (!inferredScopes.has(key))
466
+ inferredScopes.set(key, new Set());
467
+ inferredScopes.get(key).add(conn.from.node);
468
+ }
469
+ }
470
+ for (const [key, childSet] of inferredScopes) {
471
+ if (!allScopes[key]) {
472
+ allScopes[key] = [...childSet];
473
+ for (const child of childSet)
474
+ scopedChildren.add(child);
475
+ }
476
+ }
477
+ // Build diagram nodes
478
+ const diagramNodes = new Map();
479
+ // Start node — ensure mandatory execute STEP port exists
480
+ const allStartPorts = { ...ast.startPorts };
481
+ if (!allStartPorts.execute) {
482
+ allStartPorts.execute = { dataType: 'STEP' };
483
+ }
484
+ const startOutputs = orderedPorts(allStartPorts, 'OUTPUT');
485
+ diagramNodes.set('Start', {
486
+ id: 'Start',
487
+ label: 'Start',
488
+ color: '#334155',
489
+ icon: 'startNode',
490
+ isVirtual: true,
491
+ inputs: [],
492
+ outputs: startOutputs,
493
+ x: 0, y: 0,
494
+ width: NODE_MIN_WIDTH,
495
+ height: NODE_MIN_HEIGHT,
496
+ });
497
+ // Exit node — ensure mandatory onSuccess/onFailure STEP ports exist
498
+ const allExitPorts = { ...ast.exitPorts };
499
+ if (!allExitPorts.onSuccess) {
500
+ allExitPorts.onSuccess = { dataType: 'STEP', isControlFlow: true };
501
+ }
502
+ if (!allExitPorts.onFailure) {
503
+ allExitPorts.onFailure = { dataType: 'STEP', isControlFlow: true, failure: true };
504
+ }
505
+ else {
506
+ allExitPorts.onFailure = { ...allExitPorts.onFailure, failure: true };
507
+ }
508
+ const exitInputs = orderedPorts(allExitPorts, 'INPUT');
509
+ diagramNodes.set('Exit', {
510
+ id: 'Exit',
511
+ label: 'Exit',
512
+ color: '#334155',
513
+ icon: 'exitNode',
514
+ isVirtual: true,
515
+ inputs: exitInputs,
516
+ outputs: [],
517
+ x: 0, y: 0,
518
+ width: NODE_MIN_WIDTH,
519
+ height: NODE_MIN_HEIGHT,
520
+ });
521
+ // Instance nodes (skip scoped children — they are built inside their parent)
522
+ for (const inst of ast.instances) {
523
+ if (scopedChildren.has(inst.id))
524
+ continue;
525
+ const node = buildInstanceNode(inst.id, inst.nodeType, inst.config, nodeTypeMap, themeName);
526
+ diagramNodes.set(inst.id, node);
527
+ }
528
+ // Compute base dimensions
529
+ for (const node of diagramNodes.values()) {
530
+ computeNodeDimensions(node);
531
+ }
532
+ // Build scope sub-graphs (expands parent dimensions)
533
+ for (const [scopeKey, childIds] of Object.entries(allScopes)) {
534
+ const dotIndex = scopeKey.indexOf('.');
535
+ const parentId = scopeKey.substring(0, dotIndex);
536
+ const scopeName = scopeKey.substring(dotIndex + 1);
537
+ const parentNode = diagramNodes.get(parentId);
538
+ if (!parentNode)
539
+ continue;
540
+ const parentInst = ast.instances.find(i => i.id === parentId);
541
+ if (!parentInst)
542
+ continue;
543
+ const parentNt = nodeTypeMap.get(parentInst.nodeType);
544
+ if (!parentNt)
545
+ continue;
546
+ buildScopeSubGraph(parentNode, parentNt, scopeName, childIds, ast, nodeTypeMap, themeName);
547
+ }
548
+ // Layout
549
+ const { layers } = layoutWorkflow(ast);
550
+ // Assign coordinates
551
+ let currentX = 0;
552
+ for (const layer of layers) {
553
+ const layerNodes = layer.filter(id => diagramNodes.has(id));
554
+ if (layerNodes.length === 0) {
555
+ currentX += LAYER_GAP_X;
556
+ continue;
557
+ }
558
+ const maxWidth = Math.max(...layerNodes.map(id => diagramNodes.get(id).width));
559
+ const totalHeight = layerNodes.reduce((sum, id) => {
560
+ const n = diagramNodes.get(id);
561
+ return sum + n.height + LABEL_HEIGHT + LABEL_GAP;
562
+ }, 0) + (layerNodes.length - 1) * NODE_GAP_Y;
563
+ let currentY = -totalHeight / 2;
564
+ for (const id of layerNodes) {
565
+ const node = diagramNodes.get(id);
566
+ currentY += LABEL_HEIGHT + LABEL_GAP;
567
+ node.x = currentX + (maxWidth - node.width) / 2;
568
+ node.y = currentY;
569
+ currentY += node.height + NODE_GAP_Y;
570
+ }
571
+ currentX += maxWidth + LAYER_GAP_X;
572
+ }
573
+ // Compute external port positions
574
+ for (const node of diagramNodes.values()) {
575
+ computePortPositions(node);
576
+ }
577
+ // Finalize scope sub-graph positions (offset children + build scope connections)
578
+ for (const node of diagramNodes.values()) {
579
+ if (node.scopeChildren) {
580
+ finalizeScopePositions(node, ast, themeName);
581
+ }
582
+ }
583
+ const pendingConnections = [];
584
+ for (const conn of ast.connections) {
585
+ // Skip scope-qualified connections (handled by scope logic)
586
+ if (conn.from.scope || conn.to.scope)
587
+ continue;
588
+ // Look up nodes — check main diagram nodes first, then scope children
589
+ let fromNode = diagramNodes.get(conn.from.node);
590
+ let toNode = diagramNodes.get(conn.to.node);
591
+ // Cross-scope: look up scope children for nodes not in main diagram
592
+ if (!fromNode) {
593
+ for (const node of diagramNodes.values()) {
594
+ const child = node.scopeChildren?.find(c => c.id === conn.from.node);
595
+ if (child) {
596
+ fromNode = child;
597
+ break;
598
+ }
599
+ }
600
+ }
601
+ if (!toNode) {
602
+ for (const node of diagramNodes.values()) {
603
+ const child = node.scopeChildren?.find(c => c.id === conn.to.node);
604
+ if (child) {
605
+ toNode = child;
606
+ break;
607
+ }
608
+ }
609
+ }
610
+ if (!fromNode || !toNode)
611
+ continue;
612
+ // Skip connections where both endpoints are scope children or parent↔child
613
+ // (these are handled as scope connections in finalizeScopePositions)
614
+ const fromIsScoped = scopedChildren.has(conn.from.node);
615
+ const toIsScoped = scopedChildren.has(conn.to.node);
616
+ if (fromIsScoped && toIsScoped)
617
+ continue; // child→child
618
+ if (fromIsScoped && diagramNodes.has(conn.to.node) && findScopeParent(conn.from.node, diagramNodes) === conn.to.node)
619
+ continue; // child→parent
620
+ if (toIsScoped && diagramNodes.has(conn.from.node) && findScopeParent(conn.to.node, diagramNodes) === conn.from.node)
621
+ continue; // parent→child
622
+ const sourcePort = fromNode.outputs.find(p => p.name === conn.from.port);
623
+ const targetPort = toNode.inputs.find(p => p.name === conn.to.port);
624
+ if (!sourcePort || !targetPort)
625
+ continue;
626
+ const fromPortIndex = fromNode.outputs.indexOf(sourcePort);
627
+ const toPortIndex = toNode.inputs.indexOf(targetPort);
628
+ pendingConnections.push({
629
+ fromNodeId: conn.from.node, fromPortName: conn.from.port,
630
+ toNodeId: conn.to.node, toPortName: conn.to.port,
631
+ sourcePort, targetPort,
632
+ fromPortIndex, toPortIndex,
633
+ });
634
+ }
635
+ // Compute bounds (include scope children and port labels in calculation)
636
+ const nodes = Array.from(diagramNodes.values());
637
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
638
+ for (const node of nodes) {
639
+ const labelTop = node.y - LABEL_HEIGHT - LABEL_GAP;
640
+ // Port label badges extend beyond node boundaries
641
+ const inputLabelExtent = maxPortLabelExtent(node.inputs);
642
+ const outputLabelExtent = maxPortLabelExtent(node.outputs);
643
+ minX = Math.min(minX, node.x - inputLabelExtent);
644
+ minY = Math.min(minY, labelTop);
645
+ maxX = Math.max(maxX, node.x + node.width + outputLabelExtent);
646
+ maxY = Math.max(maxY, node.y + node.height);
647
+ }
648
+ const padding = options.padding ?? 40;
649
+ const offsetX = -minX + padding;
650
+ const offsetY = -minY + padding;
651
+ // Normalize all coordinates
652
+ for (const node of nodes) {
653
+ node.x += offsetX;
654
+ node.y += offsetY;
655
+ for (const p of node.inputs) {
656
+ p.cx += offsetX;
657
+ p.cy += offsetY;
658
+ }
659
+ for (const p of node.outputs) {
660
+ p.cx += offsetX;
661
+ p.cy += offsetY;
662
+ }
663
+ // Offset scope children and scope ports
664
+ if (node.scopeChildren) {
665
+ for (const child of node.scopeChildren) {
666
+ child.x += offsetX;
667
+ child.y += offsetY;
668
+ for (const p of child.inputs) {
669
+ p.cx += offsetX;
670
+ p.cy += offsetY;
671
+ }
672
+ for (const p of child.outputs) {
673
+ p.cx += offsetX;
674
+ p.cy += offsetY;
675
+ }
676
+ }
677
+ }
678
+ if (node.scopePorts) {
679
+ for (const p of node.scopePorts.inputs) {
680
+ p.cx += offsetX;
681
+ p.cy += offsetY;
682
+ }
683
+ for (const p of node.scopePorts.outputs) {
684
+ p.cx += offsetX;
685
+ p.cy += offsetY;
686
+ }
687
+ }
688
+ }
689
+ // Build NodeBox array for orthogonal routing (after coordinate normalization)
690
+ const nodeBoxes = nodes.map(node => ({
691
+ id: node.id,
692
+ x: node.x,
693
+ y: node.y,
694
+ width: node.width,
695
+ height: node.height,
696
+ }));
697
+ // Sort connections: short spans first, then by source X, then by source Y
698
+ // (matching original editor for deterministic track allocation)
699
+ pendingConnections.sort((a, b) => {
700
+ const aSpan = Math.abs(a.targetPort.cx - a.sourcePort.cx);
701
+ const bSpan = Math.abs(b.targetPort.cx - b.sourcePort.cx);
702
+ if (Math.abs(aSpan - bSpan) > 1)
703
+ return aSpan - bSpan;
704
+ if (Math.abs(a.sourcePort.cx - b.sourcePort.cx) > 1)
705
+ return a.sourcePort.cx - b.sourcePort.cx;
706
+ return a.sourcePort.cy - b.sourcePort.cy;
707
+ });
708
+ // Create a single TrackAllocator for deterministic batch routing
709
+ const allocator = new TrackAllocator();
710
+ // Compute all connection paths with routing mode selection
711
+ const connections = [];
712
+ for (const pc of pendingConnections) {
713
+ const sx = pc.sourcePort.cx;
714
+ const sy = pc.sourcePort.cy;
715
+ const tx = pc.targetPort.cx;
716
+ const ty = pc.targetPort.cy;
717
+ const dx = tx - sx;
718
+ const dy = ty - sy;
719
+ const distance = Math.sqrt(dx * dx + dy * dy);
720
+ let path;
721
+ if (distance > ORTHOGONAL_DISTANCE_THRESHOLD) {
722
+ // Try orthogonal routing for long-distance connections
723
+ const orthoPath = calculateOrthogonalPathSafe([sx, sy], [tx, ty], nodeBoxes, pc.fromNodeId, pc.toNodeId, { fromPortIndex: pc.fromPortIndex, toPortIndex: pc.toPortIndex }, allocator);
724
+ path = orthoPath ?? computeConnectionPath(sx, sy, tx, ty);
725
+ }
726
+ else {
727
+ path = computeConnectionPath(sx, sy, tx, ty);
728
+ }
729
+ const sourceColor = getPortColor(pc.sourcePort.dataType, pc.sourcePort.isFailure, themeName);
730
+ const targetColor = getPortColor(pc.targetPort.dataType, pc.targetPort.isFailure, themeName);
731
+ connections.push({
732
+ fromNode: pc.fromNodeId, fromPort: pc.fromPortName,
733
+ toNode: pc.toNodeId, toPort: pc.toPortName,
734
+ sourceColor, targetColor,
735
+ isStepConnection: pc.sourcePort.dataType === 'STEP',
736
+ path,
737
+ });
738
+ }
739
+ // Recompute scope connection paths after normalization
740
+ for (const node of nodes) {
741
+ if (node.scopeConnections && node.scopePorts && node.scopeChildren) {
742
+ const childMap = new Map();
743
+ for (const c of node.scopeChildren)
744
+ childMap.set(c.id, c);
745
+ for (const conn of node.scopeConnections) {
746
+ const sPort = findScopePort(conn.fromNode, conn.fromPort, node, childMap, 'output');
747
+ const tPort = findScopePort(conn.toNode, conn.toPort, node, childMap, 'input');
748
+ if (sPort && tPort) {
749
+ conn.path = computeConnectionPath(sPort.cx, sPort.cy, tPort.cx, tPort.cy);
750
+ }
751
+ }
752
+ }
753
+ }
754
+ // Extend bounds to include connection paths (orthogonal routes can go outside node area)
755
+ let normalizedMaxY = (maxY - minY) + padding * 2;
756
+ let normalizedMaxX = (maxX - minX) + padding * 2;
757
+ const allConns = [...connections];
758
+ for (const node of nodes) {
759
+ if (node.scopeConnections)
760
+ allConns.push(...node.scopeConnections);
761
+ }
762
+ for (const conn of allConns) {
763
+ const extent = pathExtent(conn.path);
764
+ if (extent.maxY + padding > normalizedMaxY)
765
+ normalizedMaxY = extent.maxY + padding;
766
+ if (extent.maxX + padding > normalizedMaxX)
767
+ normalizedMaxX = extent.maxX + padding;
768
+ }
769
+ return {
770
+ nodes,
771
+ connections,
772
+ bounds: { width: normalizedMaxX, height: normalizedMaxY },
773
+ workflowName: ast.name,
774
+ };
775
+ }
776
+ /** Find a port for scope connection path recomputation */
777
+ function findScopePort(nodeId, portName, parentNode, childMap, side) {
778
+ // Check if it's a scope port on the parent
779
+ if (nodeId === parentNode.id) {
780
+ const ports = side === 'output' ? parentNode.scopePorts?.outputs : parentNode.scopePorts?.inputs;
781
+ return ports?.find(p => p.name === portName);
782
+ }
783
+ // Check child nodes
784
+ const child = childMap.get(nodeId);
785
+ if (!child)
786
+ return undefined;
787
+ return side === 'output'
788
+ ? child.outputs.find(p => p.name === portName)
789
+ : child.inputs.find(p => p.name === portName);
790
+ }
791
+ // ---- Helpers ----
792
+ /** Find the parent diagram node that contains a scope child */
793
+ function findScopeParent(childId, diagramNodes) {
794
+ for (const node of diagramNodes.values()) {
795
+ if (node.scopeChildren?.some(c => c.id === childId))
796
+ return node.id;
797
+ }
798
+ return undefined;
799
+ }
800
+ function filterNonScopedPorts(ports) {
801
+ const result = {};
802
+ for (const [name, def] of Object.entries(ports)) {
803
+ if (!def.scope)
804
+ result[name] = def;
805
+ }
806
+ return result;
807
+ }
808
+ function resolveNodeColor(color, theme = 'dark') {
809
+ if (!color)
810
+ return '#334155';
811
+ const variant = NODE_VARIANT_COLORS[color];
812
+ if (variant)
813
+ return theme === 'dark' ? variant.darkBorder : variant.border;
814
+ return color;
815
+ }
816
+ /** Auto-detect icon based on node type variant (matching original getNodeIcon logic) */
817
+ function resolveDefaultIcon(nt) {
818
+ if (!nt)
819
+ return 'code';
820
+ if (nt.variant === 'WORKFLOW' || nt.variant === 'IMPORTED_WORKFLOW')
821
+ return 'flow';
822
+ return 'code';
823
+ }
824
+ /** Extract max X/Y extent from an SVG path string (for bounds calculation) */
825
+ function pathExtent(path) {
826
+ let maxX = -Infinity;
827
+ let maxY = -Infinity;
828
+ const pattern = /(-?[\d.]+),(-?[\d.]+)/g;
829
+ let m;
830
+ while ((m = pattern.exec(path)) !== null) {
831
+ maxX = Math.max(maxX, parseFloat(m[1]));
832
+ maxY = Math.max(maxY, parseFloat(m[2]));
833
+ }
834
+ return { maxX, maxY };
835
+ }
836
+ /** Estimate the maximum port label badge extent beyond the node edge */
837
+ function maxPortLabelExtent(ports) {
838
+ if (ports.length === 0)
839
+ return 0;
840
+ let max = 0;
841
+ for (const port of ports) {
842
+ const abbrev = TYPE_ABBREVIATIONS[port.dataType] ?? port.dataType;
843
+ const badgeTextWidth = measureText(abbrev) + measureText(port.label);
844
+ const badgeWidth = badgeTextWidth + 23; // 7px pad + 4px + 1px divider + 4px + 7px pad
845
+ // PORT_RADIUS + gap(5) + badgeWidth
846
+ max = Math.max(max, PORT_RADIUS + 5 + badgeWidth);
847
+ }
848
+ return max;
849
+ }
850
+ //# sourceMappingURL=geometry.js.map