@synergenius/flow-weaver 0.33.2 → 0.44.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 (922) hide show
  1. package/LICENSE +201 -226
  2. package/NOTICE +13 -0
  3. package/README.md +152 -245
  4. package/dist/agent/agent-loop.d.ts +4 -2
  5. package/dist/agent/cli-session.d.ts +3 -3
  6. package/dist/agent/cli-session.js +511 -438
  7. package/dist/agent/cli-spawn-config.d.ts +4 -4
  8. package/dist/agent/gate.d.ts +164 -0
  9. package/dist/agent/index.d.ts +4 -4
  10. package/dist/agent/index.js +174 -28
  11. package/dist/agent/mcp-bridge.d.ts +1 -1
  12. package/dist/agent/mcp-bridge.js +114 -128
  13. package/dist/agent/mcp-tool-server.d.ts +2 -2
  14. package/dist/agent/mcp-tool-server.js +147 -189
  15. package/dist/agent/profiles.d.ts +69 -0
  16. package/dist/agent/providers/anthropic.d.ts +2 -4
  17. package/dist/agent/providers/claude-cli.d.ts +4 -5
  18. package/dist/agent/providers/openai-compat.d.ts +8 -1
  19. package/dist/agent/streaming.d.ts +2 -2
  20. package/dist/agent/types.d.ts +16 -10
  21. package/dist/api/builder.d.ts +3 -3
  22. package/dist/api/compile.d.ts +9 -4
  23. package/dist/api/durable-validation.d.ts +15 -0
  24. package/dist/api/generate-in-place.d.ts +21 -19
  25. package/dist/api/generate.d.ts +21 -16
  26. package/dist/api/generated-module/local-node-functions.d.ts +24 -0
  27. package/dist/api/generated-module/module-format.d.ts +23 -0
  28. package/dist/api/generated-module/module-writer.d.ts +34 -0
  29. package/dist/api/generated-module/node-type-imports.d.ts +39 -0
  30. package/dist/api/generated-module/preamble.d.ts +16 -0
  31. package/dist/api/generated-module/workflow-functions.d.ts +29 -0
  32. package/dist/api/graph-identity.d.ts +39 -0
  33. package/dist/api/helpers.d.ts +4 -60
  34. package/dist/api/in-place/built-in-nodes.d.ts +18 -0
  35. package/dist/api/in-place/function-body.d.ts +21 -0
  36. package/dist/api/in-place/fw-imports.d.ts +30 -0
  37. package/dist/api/in-place/macro-coverage.d.ts +14 -0
  38. package/dist/api/in-place/node-type-functions.d.ts +18 -0
  39. package/dist/api/in-place/node-type-jsdoc.d.ts +20 -0
  40. package/dist/api/in-place/orphaned-node-types.d.ts +16 -0
  41. package/dist/api/in-place/runtime-section.d.ts +16 -0
  42. package/dist/api/in-place/signature.d.ts +47 -0
  43. package/dist/api/in-place/source-file.d.ts +19 -0
  44. package/dist/api/in-place/workflow-jsdoc.d.ts +19 -0
  45. package/dist/api/index.d.ts +18 -21
  46. package/dist/api/index.js +259 -53
  47. package/dist/api/inline-engine.generated.d.ts +3 -0
  48. package/dist/api/inline-runtime.d.ts +10 -2
  49. package/dist/api/manipulation/connections.d.ts +1 -1
  50. package/dist/api/manipulation/index.d.ts +8 -8
  51. package/dist/api/manipulation/node-types.d.ts +1 -1
  52. package/dist/api/manipulation/nodes.d.ts +3 -13
  53. package/dist/api/manipulation/ports.d.ts +1 -1
  54. package/dist/api/manipulation/scopes.d.ts +1 -1
  55. package/dist/api/manipulation/workflow.d.ts +1 -1
  56. package/dist/api/modify-operation.d.ts +0 -2
  57. package/dist/api/parse.d.ts +22 -1
  58. package/dist/api/port-references.d.ts +66 -0
  59. package/dist/api/query.d.ts +18 -2
  60. package/dist/api/templates.d.ts +1 -1
  61. package/dist/api/transform.d.ts +1 -1
  62. package/dist/api/validate.d.ts +1 -1
  63. package/dist/api/validation-registry.d.ts +2 -2
  64. package/dist/artifacts/brief.d.ts +43 -0
  65. package/dist/artifacts/index.d.ts +31 -0
  66. package/dist/artifacts/pdf.d.ts +19 -0
  67. package/dist/ast/builder.d.ts +3 -3
  68. package/dist/ast/index.d.ts +4 -4
  69. package/dist/ast/index.js +60 -5
  70. package/dist/ast/serialization-node.d.ts +1 -1
  71. package/dist/ast/serialization.d.ts +1 -1
  72. package/dist/ast/types.d.ts +82 -291
  73. package/dist/ast/workflow-utils.d.ts +4 -4
  74. package/dist/built-in-nodes/coercion-types.d.ts +1 -1
  75. package/dist/built-in-nodes/delay.d.ts +3 -1
  76. package/dist/built-in-nodes/generated-registry.d.ts +1 -1
  77. package/dist/built-in-nodes/index.d.ts +6 -5
  78. package/dist/built-in-nodes/index.js +79 -5
  79. package/dist/built-in-nodes/invoke-workflow.d.ts +2 -1
  80. package/dist/built-in-nodes/mock-types.d.ts +45 -14
  81. package/dist/built-in-nodes/sleep.d.ts +12 -0
  82. package/dist/built-in-nodes/wait-for-agent.d.ts +2 -1
  83. package/dist/built-in-nodes/wait-for-event.d.ts +2 -1
  84. package/dist/chevrotain-parser/coerce-parser.d.ts +1 -1
  85. package/dist/chevrotain-parser/connect-parser.d.ts +1 -1
  86. package/dist/chevrotain-parser/grammar-diagrams.d.ts +1 -1
  87. package/dist/chevrotain-parser/index.d.ts +20 -23
  88. package/dist/chevrotain-parser/node-parser.d.ts +7 -8
  89. package/dist/chevrotain-parser/parse-line.d.ts +54 -0
  90. package/dist/chevrotain-parser/tokens.d.ts +0 -17
  91. package/dist/chevrotain-parser/trigger-cancel-parser.d.ts +6 -1
  92. package/dist/chunks/chunk-4EUSHAY6.js +298 -0
  93. package/dist/chunks/chunk-4KDUEOFD.js +197 -0
  94. package/dist/chunks/chunk-5Y3AIUWY.js +911 -0
  95. package/dist/chunks/chunk-6KMVP6AU.js +20 -0
  96. package/dist/chunks/chunk-6PNJORFL.js +128 -0
  97. package/dist/chunks/chunk-7AAQNGRH.js +2001 -0
  98. package/dist/chunks/chunk-7YYKTPJ5.js +22705 -0
  99. package/dist/chunks/chunk-A5MBOFVY.js +33 -0
  100. package/dist/chunks/chunk-AXNQRVJB.js +18 -0
  101. package/dist/chunks/chunk-B6HQ6YS5.js +572 -0
  102. package/dist/chunks/chunk-CY3RNVML.js +296 -0
  103. package/dist/chunks/chunk-CYHYDLV4.js +653 -0
  104. package/dist/chunks/chunk-CZBCCK4Y.js +82 -0
  105. package/dist/chunks/chunk-DCMGQP5V.js +505 -0
  106. package/dist/chunks/chunk-DIAA66GL.js +72 -0
  107. package/dist/chunks/chunk-DUO6H5PR.js +20 -0
  108. package/dist/chunks/chunk-E5WN7IGO.js +125 -0
  109. package/dist/chunks/chunk-EFGFXXQF.js +184 -0
  110. package/dist/chunks/chunk-F3RTZV2A.js +2811 -0
  111. package/dist/chunks/chunk-FMTLP5ZX.js +1397 -0
  112. package/dist/chunks/chunk-HKZLQJDV.js +79 -0
  113. package/dist/chunks/chunk-INDEVYEC.js +146 -0
  114. package/dist/chunks/chunk-JQTF4R5L.js +390 -0
  115. package/dist/chunks/chunk-KMCAYNUM.js +331 -0
  116. package/dist/chunks/chunk-KMWCCOUJ.js +1444 -0
  117. package/dist/chunks/chunk-KU3CLJI2.js +338 -0
  118. package/dist/chunks/chunk-NDSTGMKR.js +3300 -0
  119. package/dist/chunks/chunk-NQNLUAPO.js +505 -0
  120. package/dist/chunks/chunk-O2U2LO57.js +466 -0
  121. package/dist/chunks/chunk-OOQG7UPP.js +457 -0
  122. package/dist/chunks/chunk-OZQAW5ZG.js +112 -0
  123. package/dist/chunks/chunk-P2CVDGHR.js +487 -0
  124. package/dist/chunks/chunk-P44RIZ7C.js +592 -0
  125. package/dist/chunks/chunk-PEZCT37T.js +1475 -0
  126. package/dist/chunks/chunk-PKWSAW6O.js +152 -0
  127. package/dist/chunks/chunk-Q6MDDZMT.js +4373 -0
  128. package/dist/chunks/chunk-QDE4Z7KW.js +6 -0
  129. package/dist/chunks/chunk-QJDAVSNY.js +8 -0
  130. package/dist/chunks/chunk-QYPORSLO.js +7552 -0
  131. package/dist/chunks/chunk-R4QGNK34.js +183 -0
  132. package/dist/chunks/chunk-REEYC73I.js +3002 -0
  133. package/dist/chunks/chunk-SEWDMQ6Q.js +46 -0
  134. package/dist/chunks/chunk-TAIUWKZB.js +3057 -0
  135. package/dist/chunks/chunk-TN4YZ3O7.js +196 -0
  136. package/dist/chunks/chunk-TRMFB43C.js +143 -0
  137. package/dist/chunks/chunk-VO4QXG2X.js +1016 -0
  138. package/dist/chunks/chunk-VP2P3BPA.js +1002 -0
  139. package/dist/chunks/chunk-VQ7H33J4.js +2176 -0
  140. package/dist/chunks/chunk-VWA7MCV2.js +105 -0
  141. package/dist/chunks/chunk-XAV22WD7.js +253 -0
  142. package/dist/chunks/chunk-YSPBPZDV.js +148 -0
  143. package/dist/chunks/chunk-ZKEGXO73.js +282 -0
  144. package/dist/chunks/chunk-ZMGN6F3S.js +4256 -0
  145. package/dist/chunks/grammar-diagrams-AI7VDXOM.js +14 -0
  146. package/dist/chunks/index.min-ECJD6GZC.js +37 -0
  147. package/dist/chunks/manifest-EPTR5MYH.js +21 -0
  148. package/dist/chunks/openapi-document-6TCGVDUW.js +69 -0
  149. package/dist/chunks/registry-K2U5KUTY.js +23 -0
  150. package/dist/chunks/serialization-node-UGY6CFH6.js +38 -0
  151. package/dist/chunks/validate-GEKSZPIN.js +24 -0
  152. package/dist/chunks/validation-registry-IQZX3UE3.js +7 -0
  153. package/dist/chunks/validator-VXFHLPDW.js +26 -0
  154. package/dist/chunks/workflow-executor-KBGFKHNR.js +36 -0
  155. package/dist/cli/commands/agents.d.ts +16 -0
  156. package/dist/cli/commands/artifact.d.ts +10 -0
  157. package/dist/cli/commands/compile.d.ts +0 -30
  158. package/dist/cli/commands/console.d.ts +32 -0
  159. package/dist/cli/commands/context.d.ts +0 -3
  160. package/dist/cli/commands/describe.js +386 -352
  161. package/dist/cli/commands/dev.d.ts +9 -4
  162. package/dist/cli/commands/diagram.d.ts +3 -5
  163. package/dist/cli/commands/doctor.d.ts +27 -4
  164. package/dist/cli/commands/doctor.js +3307 -633
  165. package/dist/cli/commands/export.d.ts +6 -4
  166. package/dist/cli/commands/grammar.d.ts +0 -3
  167. package/dist/cli/commands/implement.d.ts +1 -1
  168. package/dist/cli/commands/init/agent-handoff.d.ts +28 -0
  169. package/dist/cli/commands/init/config.d.ts +3 -0
  170. package/dist/cli/commands/init/files.d.ts +12 -0
  171. package/dist/cli/commands/init/naming.d.ts +13 -0
  172. package/dist/cli/commands/init/output.d.ts +12 -0
  173. package/dist/cli/commands/init/setup.d.ts +21 -0
  174. package/dist/cli/commands/init/types.d.ts +53 -0
  175. package/dist/cli/commands/init-personas.d.ts +9 -1
  176. package/dist/cli/commands/init.d.ts +24 -88
  177. package/dist/cli/commands/market.d.ts +1 -1
  178. package/dist/cli/commands/mcp-setup.d.ts +1 -4
  179. package/dist/cli/commands/modify.d.ts +0 -5
  180. package/dist/cli/commands/openapi.d.ts +9 -11
  181. package/dist/cli/commands/run.d.ts +0 -4
  182. package/dist/cli/commands/serve.d.ts +24 -26
  183. package/dist/cli/commands/status.d.ts +1 -1
  184. package/dist/cli/exports.d.ts +3 -4
  185. package/dist/cli/exports.js +124 -23
  186. package/dist/cli/flow-weaver-agents-H653446S.mjs +81 -0
  187. package/dist/cli/flow-weaver-artifact-WBFYTW76.mjs +58 -0
  188. package/dist/cli/flow-weaver-chunk-265CEK74.mjs +2 -0
  189. package/dist/cli/flow-weaver-chunk-2C7PZCV5.mjs +186 -0
  190. package/dist/cli/flow-weaver-chunk-3BSYCWPL.mjs +3109 -0
  191. package/dist/cli/flow-weaver-chunk-3MKUQP3D.mjs +547 -0
  192. package/dist/cli/flow-weaver-chunk-3ZLMPQTH.mjs +27 -0
  193. package/dist/cli/flow-weaver-chunk-4DVY73ML.mjs +280 -0
  194. package/dist/cli/flow-weaver-chunk-54M4KNEL.mjs +200 -0
  195. package/dist/cli/flow-weaver-chunk-55QMUZIA.mjs +256 -0
  196. package/dist/cli/flow-weaver-chunk-6ZUJ7LMX.mjs +2003 -0
  197. package/dist/cli/flow-weaver-chunk-7ET6N32V.mjs +419 -0
  198. package/dist/cli/flow-weaver-chunk-7G63RR4K.mjs +8880 -0
  199. package/dist/cli/flow-weaver-chunk-A6M5K3W7.mjs +4418 -0
  200. package/dist/cli/flow-weaver-chunk-AA3NATMX.mjs +154 -0
  201. package/dist/cli/flow-weaver-chunk-APX6MQ5A.mjs +5652 -0
  202. package/dist/cli/flow-weaver-chunk-BHCC5FE5.mjs +17 -0
  203. package/dist/cli/flow-weaver-chunk-DM4BBRRU.mjs +35 -0
  204. package/dist/cli/flow-weaver-chunk-DRN7KPWY.mjs +168 -0
  205. package/dist/cli/flow-weaver-chunk-EKWF27G6.mjs +23 -0
  206. package/dist/cli/flow-weaver-chunk-EM5HWQ4R.mjs +338 -0
  207. package/dist/cli/flow-weaver-chunk-FPPPU2DG.mjs +226 -0
  208. package/dist/cli/flow-weaver-chunk-GAQXZHNO.mjs +3005 -0
  209. package/dist/cli/flow-weaver-chunk-GBUNNP33.mjs +1329 -0
  210. package/dist/cli/flow-weaver-chunk-HMAKDE55.mjs +636 -0
  211. package/dist/cli/flow-weaver-chunk-HQ3ZAN44.mjs +367 -0
  212. package/dist/cli/flow-weaver-chunk-I4APCXYN.mjs +21442 -0
  213. package/dist/cli/flow-weaver-chunk-IJJ4JXTL.mjs +2297 -0
  214. package/dist/cli/flow-weaver-chunk-J7EPZW2I.mjs +33 -0
  215. package/dist/cli/flow-weaver-chunk-KOEMJHLG.mjs +83 -0
  216. package/dist/cli/flow-weaver-chunk-M6CBWQKJ.mjs +271 -0
  217. package/dist/cli/flow-weaver-chunk-MHJ4N652.mjs +1580 -0
  218. package/dist/cli/flow-weaver-chunk-MKAFQWLP.mjs +202 -0
  219. package/dist/cli/flow-weaver-chunk-MMV2XGD3.mjs +3291 -0
  220. package/dist/cli/flow-weaver-chunk-MSI2UJES.mjs +125 -0
  221. package/dist/cli/flow-weaver-chunk-N767YRAI.mjs +48 -0
  222. package/dist/cli/flow-weaver-chunk-NQKKWDGF.mjs +56 -0
  223. package/dist/cli/flow-weaver-chunk-NYZDQYFU.mjs +45 -0
  224. package/dist/cli/flow-weaver-chunk-OMVWSNHJ.mjs +14 -0
  225. package/dist/cli/flow-weaver-chunk-PUWZ47H5.mjs +2188 -0
  226. package/dist/cli/flow-weaver-chunk-QOPRVDES.mjs +46 -0
  227. package/dist/cli/flow-weaver-chunk-RIWE7YTR.mjs +216 -0
  228. package/dist/cli/flow-weaver-chunk-S63Q3JIU.mjs +789 -0
  229. package/dist/cli/flow-weaver-chunk-T7X5A23H.mjs +558 -0
  230. package/dist/cli/flow-weaver-chunk-TLV3VZUN.mjs +2 -0
  231. package/dist/cli/flow-weaver-chunk-TS5P3PIN.mjs +194 -0
  232. package/dist/cli/flow-weaver-chunk-U3EO3X4B.mjs +649 -0
  233. package/dist/cli/flow-weaver-chunk-UNFS3NQP.mjs +34 -0
  234. package/dist/cli/flow-weaver-chunk-V6DHWFQG.mjs +2811 -0
  235. package/dist/cli/flow-weaver-chunk-VXWNLYQU.mjs +9 -0
  236. package/dist/cli/flow-weaver-chunk-W3YNK26P.mjs +149 -0
  237. package/dist/cli/flow-weaver-chunk-XG2WKXYZ.mjs +324 -0
  238. package/dist/cli/flow-weaver-chunk-YLSRZWFK.mjs +2219 -0
  239. package/dist/cli/flow-weaver-chunk-YVPURWS6.mjs +40 -0
  240. package/dist/cli/flow-weaver-chunk-Z44JK332.mjs +582 -0
  241. package/dist/cli/flow-weaver-chunk-Z5ZJPNSY.mjs +517 -0
  242. package/dist/cli/flow-weaver-chunk-ZQALO25T.mjs +594 -0
  243. package/dist/cli/flow-weaver-compile-A2CABDSB.mjs +37 -0
  244. package/dist/cli/flow-weaver-console-6EBHDBTN.mjs +71 -0
  245. package/dist/cli/flow-weaver-context-ECLYANFF.mjs +17 -0
  246. package/dist/cli/flow-weaver-context-ZRUMW2KE.mjs +69 -0
  247. package/dist/cli/flow-weaver-create-WIP4EFNP.mjs +124 -0
  248. package/dist/cli/flow-weaver-deployment-WJJRK7NO.mjs +14 -0
  249. package/dist/cli/flow-weaver-describe-XDIFF5LI.mjs +41 -0
  250. package/dist/cli/flow-weaver-dev-LG2NSQAU.mjs +196 -0
  251. package/dist/cli/flow-weaver-diagram-3EVQARQE.mjs +52 -0
  252. package/dist/cli/flow-weaver-diagram-7LR7O4M2.mjs +44 -0
  253. package/dist/cli/flow-weaver-diff-USF7DJLU.mjs +85 -0
  254. package/dist/cli/flow-weaver-docs-QU2ZOXKH.mjs +96 -0
  255. package/dist/cli/flow-weaver-doctor-K447YWHR.mjs +43 -0
  256. package/dist/cli/flow-weaver-export-LAS6N56Y.mjs +140 -0
  257. package/dist/cli/flow-weaver-grammar-RIRUS3Q6.mjs +49 -0
  258. package/dist/cli/flow-weaver-grammar-diagrams-WXRTW5SK.mjs +15 -0
  259. package/dist/cli/flow-weaver-implement-5JG6BCFZ.mjs +114 -0
  260. package/dist/cli/flow-weaver-index.min-OR5SIHXD.mjs +39 -0
  261. package/dist/cli/flow-weaver-init-34YZNPQX.mjs +972 -0
  262. package/dist/cli/flow-weaver-init-personas-NOGZTQQ2.mjs +48 -0
  263. package/dist/cli/flow-weaver-manifest-4JNUSEB3.mjs +18 -0
  264. package/dist/cli/flow-weaver-market-WA4CKHKV.mjs +444 -0
  265. package/dist/cli/flow-weaver-mcp-setup-O26MGXSD.mjs +22 -0
  266. package/dist/cli/flow-weaver-migrate-VFVEUTPH.mjs +119 -0
  267. package/dist/cli/flow-weaver-modify-VM3JP5K6.mjs +97 -0
  268. package/dist/cli/flow-weaver-openapi-IRBWI3HM.mjs +71 -0
  269. package/dist/cli/flow-weaver-openapi-document-7N6YMPG3.mjs +30 -0
  270. package/dist/cli/flow-weaver-pack-commands-OS2QRXAK.mjs +146 -0
  271. package/dist/cli/flow-weaver-registry-5MLFRPPT.mjs +25 -0
  272. package/dist/cli/flow-weaver-run-DSTLSTHR.mjs +555 -0
  273. package/dist/cli/flow-weaver-serialization-node-LE6PCG4M.mjs +50 -0
  274. package/dist/cli/flow-weaver-serve-NVLCLSOW.mjs +192 -0
  275. package/dist/cli/flow-weaver-server-7IERLVXE.mjs +2925 -0
  276. package/dist/cli/flow-weaver-server-KWF4PXYC.mjs +19112 -0
  277. package/dist/cli/flow-weaver-status-75W2S3YB.mjs +138 -0
  278. package/dist/cli/flow-weaver-strip-AZPXUYVA.mjs +79 -0
  279. package/dist/cli/flow-weaver-templates-DSNMB6K7.mjs +72 -0
  280. package/dist/cli/flow-weaver-validate-A4UWDQN6.mjs +19 -0
  281. package/dist/cli/flow-weaver-validate-GRBZ5W4C.mjs +296 -0
  282. package/dist/cli/flow-weaver-validation-registry-BINGUNXX.mjs +9 -0
  283. package/dist/cli/flow-weaver-validator-TY56CI42.mjs +21 -0
  284. package/dist/cli/flow-weaver-watch-OPPERXL6.mjs +114 -0
  285. package/dist/cli/flow-weaver-workflow-executor-6AHYPXAN.mjs +26 -0
  286. package/dist/cli/flow-weaver.mjs +3557 -89384
  287. package/dist/cli/index.d.ts +5 -2
  288. package/dist/cli/pack-commands-needed.d.ts +12 -0
  289. package/dist/cli/program.d.ts +14 -0
  290. package/dist/cli/templates/ai/mock-provider.d.ts +1 -1
  291. package/dist/cli/templates/index.d.ts +1 -8
  292. package/dist/cli/templates/nodes/agent-router.d.ts +1 -1
  293. package/dist/cli/templates/nodes/aggregator.d.ts +1 -1
  294. package/dist/cli/templates/nodes/conversation-memory.d.ts +1 -1
  295. package/dist/cli/templates/nodes/http.d.ts +1 -1
  296. package/dist/cli/templates/nodes/human-approval.d.ts +1 -1
  297. package/dist/cli/templates/nodes/json-extractor.d.ts +1 -1
  298. package/dist/cli/templates/nodes/llm-call.d.ts +1 -1
  299. package/dist/cli/templates/nodes/prompt-template.d.ts +1 -1
  300. package/dist/cli/templates/nodes/rag-retriever.d.ts +1 -1
  301. package/dist/cli/templates/nodes/tool-executor.d.ts +1 -1
  302. package/dist/cli/templates/nodes/transformer.d.ts +1 -1
  303. package/dist/cli/templates/nodes/validator.d.ts +1 -1
  304. package/dist/cli/templates/shared/approval-types.d.ts +1 -1
  305. package/dist/cli/templates/shared/case.d.ts +14 -0
  306. package/dist/cli/templates/shared/llm-types.d.ts +4 -4
  307. package/dist/cli/templates/workflows/aggregator.d.ts +1 -1
  308. package/dist/cli/templates/workflows/ai-agent.d.ts +1 -1
  309. package/dist/cli/templates/workflows/ai-chat.d.ts +1 -1
  310. package/dist/cli/templates/workflows/ai-rag.d.ts +1 -1
  311. package/dist/cli/templates/workflows/ai-react.d.ts +1 -1
  312. package/dist/cli/templates/workflows/approval.d.ts +10 -0
  313. package/dist/cli/templates/workflows/conditional.d.ts +2 -2
  314. package/dist/cli/templates/workflows/error-handler.d.ts +2 -2
  315. package/dist/cli/templates/workflows/foreach.d.ts +1 -1
  316. package/dist/cli/templates/workflows/sequential.d.ts +1 -1
  317. package/dist/cli/templates/workflows/webhook.d.ts +1 -1
  318. package/dist/cli/utils/interactive.d.ts +6 -0
  319. package/dist/cli/utils/json-option.d.ts +8 -0
  320. package/dist/cli/utils/logger.d.ts +2 -0
  321. package/dist/compiler/durable-source-proof.d.ts +23 -0
  322. package/dist/compiler/executable-artifact.d.ts +29 -0
  323. package/dist/compiler/index.d.ts +4 -0
  324. package/dist/compiler/index.js +36 -0
  325. package/dist/console/app.js +106 -0
  326. package/dist/console/assets/synergenius.svg +18 -0
  327. package/dist/console/author.d.ts +32 -0
  328. package/dist/console/cli-catalog.d.ts +21 -0
  329. package/dist/console/cli-run.d.ts +35 -0
  330. package/dist/console/cli-run.js +46 -0
  331. package/dist/console/debug.d.ts +67 -0
  332. package/dist/console/diff-view.d.ts +96 -0
  333. package/dist/console/export.d.ts +36 -0
  334. package/dist/console/git.d.ts +27 -0
  335. package/dist/console/index.d.ts +4 -0
  336. package/dist/console/index.html +16 -0
  337. package/dist/console/index.js +203 -0
  338. package/dist/console/packs.d.ts +100 -0
  339. package/dist/console/request-guard.d.ts +10 -0
  340. package/dist/console/respond.d.ts +16 -0
  341. package/dist/console/router.d.ts +64 -0
  342. package/dist/console/routes-agents.d.ts +14 -0
  343. package/dist/console/routes-project.d.ts +3 -0
  344. package/dist/console/routes-runs.d.ts +3 -0
  345. package/dist/console/routes-services.d.ts +7 -0
  346. package/dist/console/routes-tools.d.ts +3 -0
  347. package/dist/console/runs.d.ts +69 -0
  348. package/dist/console/scan.d.ts +49 -0
  349. package/dist/console/schema.d.ts +74 -0
  350. package/dist/console/server.d.ts +34 -0
  351. package/dist/console/server.js +43264 -0
  352. package/dist/console/services.d.ts +119 -0
  353. package/dist/console/source.d.ts +23 -0
  354. package/dist/console/status.d.ts +68 -0
  355. package/dist/console/styles.css +1023 -0
  356. package/dist/console/terminals.d.ts +22 -0
  357. package/dist/console/workflow-view.d.ts +153 -0
  358. package/dist/constants.d.ts +5 -1
  359. package/dist/constants.js +56 -167
  360. package/dist/context/index.d.ts +10 -0
  361. package/dist/context/index.js +14 -191
  362. package/dist/coordinator/agent-gate.d.ts +107 -0
  363. package/dist/coordinator/bundle-digest.d.ts +20 -0
  364. package/dist/coordinator/clock-tick.d.ts +4 -0
  365. package/dist/coordinator/effect-receipts.d.ts +10 -0
  366. package/dist/coordinator/errors.d.ts +31 -0
  367. package/dist/coordinator/file-store.d.ts +3 -0
  368. package/dist/coordinator/gate-labeling.d.ts +33 -0
  369. package/dist/coordinator/gate-resolution.d.ts +28 -0
  370. package/dist/coordinator/index.d.ts +12 -0
  371. package/dist/coordinator/index.js +107 -0
  372. package/dist/coordinator/memory-store.d.ts +3 -0
  373. package/dist/coordinator/params.d.ts +18 -0
  374. package/dist/coordinator/run-annotations.d.ts +6 -0
  375. package/dist/coordinator/run-context.d.ts +11 -0
  376. package/dist/coordinator/run-ending.d.ts +5 -0
  377. package/dist/coordinator/run-outcome.d.ts +31 -0
  378. package/dist/coordinator/run-resume.d.ts +6 -0
  379. package/dist/coordinator/run-start.d.ts +4 -0
  380. package/dist/coordinator/run-store.d.ts +275 -0
  381. package/dist/coordinator/run-trace.d.ts +41 -0
  382. package/dist/coordinator/run-views.d.ts +12 -0
  383. package/dist/coordinator/runs-dir.d.ts +26 -0
  384. package/dist/coordinator/store.d.ts +67 -0
  385. package/dist/coordinator/time.d.ts +39 -0
  386. package/dist/coordinator/workflow-selection.d.ts +6 -0
  387. package/dist/deployment/index.d.ts +11 -16
  388. package/dist/deployment/index.js +541 -50
  389. package/dist/deployment/targets/base.d.ts +11 -13
  390. package/dist/deployment/targets/openapi-parts.d.ts +92 -0
  391. package/dist/diagram/arms.d.ts +70 -0
  392. package/dist/diagram/ascii-renderer.d.ts +1 -1
  393. package/dist/diagram/geometry.d.ts +20 -32
  394. package/dist/diagram/graph/bounds.d.ts +30 -0
  395. package/dist/diagram/graph/metrics.d.ts +21 -0
  396. package/dist/diagram/graph/nodes.d.ts +33 -0
  397. package/dist/diagram/graph/placement.d.ts +22 -0
  398. package/dist/diagram/graph/ports.d.ts +23 -0
  399. package/dist/diagram/graph/routing.d.ts +40 -0
  400. package/dist/diagram/graph/scopes.d.ts +30 -0
  401. package/dist/diagram/index.d.ts +15 -23
  402. package/dist/diagram/index.js +632 -111
  403. package/dist/diagram/labels.d.ts +12 -0
  404. package/dist/diagram/lanes.d.ts +93 -0
  405. package/dist/diagram/layout.d.ts +1 -1
  406. package/dist/diagram/material-symbols.d.ts +7 -0
  407. package/dist/diagram/orthogonal-router.d.ts +2 -3
  408. package/dist/diagram/process-view.d.ts +79 -0
  409. package/dist/diagram/spine.d.ts +25 -0
  410. package/dist/diagram/theme.d.ts +1 -5
  411. package/dist/diagram/types.d.ts +6 -20
  412. package/dist/diff/index.js +53 -9
  413. package/dist/diff/types.d.ts +1 -5
  414. package/dist/doc-metadata/extractors/annotations.d.ts +0 -4
  415. package/dist/doc-metadata/extractors/cli-commands.d.ts +2 -1
  416. package/dist/doc-metadata/extractors/core-metadata.d.ts +19 -4
  417. package/dist/doc-metadata/extractors/error-codes.d.ts +1 -1
  418. package/dist/doc-metadata/extractors/mcp-tools.d.ts +7 -3
  419. package/dist/doc-metadata/index.d.ts +1 -2
  420. package/dist/doc-metadata/index.js +2368 -9
  421. package/dist/doc-metadata/types.d.ts +7 -24
  422. package/dist/docs/guide.d.ts +33 -0
  423. package/dist/docs/index.d.ts +7 -4
  424. package/dist/docs/index.js +298 -298
  425. package/dist/docs/pack-topics.d.ts +18 -0
  426. package/dist/editor-completions/annotationValues.d.ts +1 -1
  427. package/dist/editor-completions/contextParser.d.ts +3 -2
  428. package/dist/editor-completions/dataTypes.d.ts +1 -1
  429. package/dist/editor-completions/goToDefinition.d.ts +1 -1
  430. package/dist/editor-completions/index.d.ts +8 -8
  431. package/dist/editor-completions/index.js +1244 -175
  432. package/dist/editor-completions/jsDocAnnotations.d.ts +1 -1
  433. package/dist/editor-completions/modifierCompletions.d.ts +1 -1
  434. package/dist/export/index.d.ts +7 -1
  435. package/dist/generated-branding.js +8 -21
  436. package/dist/generated-version.d.ts +1 -1
  437. package/dist/generated-version.js +7 -3
  438. package/dist/generator/annotation-generator.d.ts +84 -0
  439. package/dist/generator/async-detection.d.ts +1 -1
  440. package/dist/{body-generator.d.ts → generator/body-generator.d.ts} +7 -3
  441. package/dist/generator/code-utils.d.ts +15 -60
  442. package/dist/generator/connection-reads.d.ts +94 -0
  443. package/dist/generator/control-flow-plan.d.ts +74 -0
  444. package/dist/generator/control-flow.d.ts +1 -1
  445. package/dist/generator/exit-assembly.d.ts +11 -0
  446. package/dist/generator/index.d.ts +4 -5
  447. package/dist/generator/index.js +34 -11
  448. package/dist/generator/input-port-values.d.ts +22 -0
  449. package/dist/generator/{scope-function-generator.d.ts → node-arguments.d.ts} +76 -1
  450. package/dist/generator/node-invocation.d.ts +74 -0
  451. package/dist/{node-types-generator.d.ts → generator/node-types-generator.d.ts} +3 -2
  452. package/dist/generator/scope-closure.d.ts +23 -0
  453. package/dist/generator/scoped-child.d.ts +49 -0
  454. package/dist/{sugar-optimizer.d.ts → generator/sugar-optimizer.d.ts} +1 -1
  455. package/dist/generator/unified.d.ts +14 -2
  456. package/dist/generator/workflow-generator.d.ts +37 -0
  457. package/dist/index.d.ts +29 -26
  458. package/dist/index.js +1322 -92
  459. package/dist/jsdoc-port-sync/apply-diff.d.ts +15 -0
  460. package/dist/jsdoc-port-sync/callback-signature.d.ts +17 -0
  461. package/dist/jsdoc-port-sync/diff.d.ts +5 -7
  462. package/dist/jsdoc-port-sync/incomplete-lines.d.ts +41 -0
  463. package/dist/jsdoc-port-sync/index.d.ts +11 -11
  464. package/dist/jsdoc-port-sync/index.js +88 -45
  465. package/dist/jsdoc-port-sync/jsdoc-to-signature.d.ts +66 -0
  466. package/dist/jsdoc-port-sync/port-parser.d.ts +6 -24
  467. package/dist/jsdoc-port-sync/port-tag-placement.d.ts +55 -0
  468. package/dist/jsdoc-port-sync/scoped-ports.d.ts +21 -0
  469. package/dist/jsdoc-port-sync/signature-parser.d.ts +8 -1
  470. package/dist/jsdoc-port-sync/signature-to-jsdoc.d.ts +77 -0
  471. package/dist/jsdoc-port-sync/sync.d.ts +4 -1
  472. package/dist/marketplace/index.d.ts +5 -3
  473. package/dist/marketplace/index.js +62 -10
  474. package/dist/marketplace/install.d.ts +24 -0
  475. package/dist/marketplace/manifest.d.ts +1 -1
  476. package/dist/marketplace/npmrc.d.ts +24 -0
  477. package/dist/marketplace/registry.d.ts +46 -11
  478. package/dist/marketplace/types.d.ts +41 -24
  479. package/dist/marketplace/validator.d.ts +1 -1
  480. package/dist/mcp/debug-session.d.ts +2 -4
  481. package/dist/mcp/dist-imports.d.ts +12 -0
  482. package/dist/mcp/response-utils.d.ts +11 -9
  483. package/dist/mcp/server.d.ts +0 -1
  484. package/dist/mcp/tools-context.d.ts +11 -0
  485. package/dist/mcp/tools-diagram.d.ts +1 -2
  486. package/dist/mcp/tools-export.d.ts +2 -2
  487. package/dist/mcp/tools-marketplace.d.ts +1 -1
  488. package/dist/mcp/tools-run.d.ts +17 -0
  489. package/dist/mcp/tools-workflow.d.ts +3 -0
  490. package/dist/mcp/types.d.ts +4 -14
  491. package/dist/mcp/workflow-executor.d.ts +57 -19
  492. package/dist/npm-packages.d.ts +1 -1
  493. package/dist/npm-packages.js +10 -473
  494. package/dist/parser/annotation-parser.d.ts +88 -0
  495. package/dist/parser/annotation-suggestion.d.ts +23 -0
  496. package/dist/parser/durable-effect-contract.d.ts +10 -0
  497. package/dist/parser/expression-references.d.ts +101 -0
  498. package/dist/parser/external-node-types.d.ts +69 -0
  499. package/dist/{function-like.d.ts → parser/function-like.d.ts} +10 -3
  500. package/dist/parser/generated-sections.d.ts +25 -0
  501. package/dist/parser/import-resolution.d.ts +67 -0
  502. package/dist/parser/import-stub.d.ts +29 -0
  503. package/dist/parser/jsdoc/config-types.d.ts +209 -0
  504. package/dist/parser/jsdoc/graph-tags.d.ts +54 -0
  505. package/dist/parser/jsdoc/node-type-block.d.ts +23 -0
  506. package/dist/parser/jsdoc/parse-line-once.d.ts +11 -0
  507. package/dist/parser/jsdoc/port-tags.d.ts +42 -0
  508. package/dist/parser/jsdoc/runtime-tags.d.ts +65 -0
  509. package/dist/parser/jsdoc/signature-types.d.ts +52 -0
  510. package/dist/parser/jsdoc/workflow-block.d.ts +22 -0
  511. package/dist/parser/jsdoc-parser.d.ts +23 -0
  512. package/dist/parser/macro-expansion.d.ts +80 -0
  513. package/dist/parser/module-resolution.d.ts +38 -0
  514. package/dist/parser/node-inference.d.ts +39 -0
  515. package/dist/parser/npm-node-types.d.ts +24 -0
  516. package/dist/parser/pack-handlers.d.ts +12 -0
  517. package/dist/parser/path-data-resolution.d.ts +75 -0
  518. package/dist/parser/port-inference.d.ts +15 -0
  519. package/dist/{resolve-package-types.d.ts → parser/resolve-package-types.d.ts} +4 -0
  520. package/dist/parser/serialize-deploy-annotations.d.ts +19 -0
  521. package/dist/parser/tag-registry.d.ts +22 -0
  522. package/dist/parser/workflow-extraction.d.ts +39 -0
  523. package/dist/runtime/ExecutionContext.d.ts +87 -99
  524. package/dist/runtime/continuation-core.d.ts +147 -0
  525. package/dist/runtime/continuation.d.ts +48 -0
  526. package/dist/runtime/debug-controller.d.ts +7 -22
  527. package/dist/runtime/durable-execution.d.ts +176 -0
  528. package/dist/runtime/events.d.ts +16 -1
  529. package/dist/runtime/executable-module-contract.d.ts +16 -0
  530. package/dist/runtime/index.d.ts +13 -10
  531. package/dist/runtime/index.js +947 -9
  532. package/dist/runtime/strict-json.d.ts +15 -0
  533. package/dist/server/access.d.ts +12 -0
  534. package/dist/server/api.d.ts +126 -0
  535. package/dist/server/callback-delivery.d.ts +62 -0
  536. package/dist/server/callback-url.d.ts +44 -0
  537. package/dist/server/context.d.ts +35 -0
  538. package/dist/server/http-error.d.ts +10 -0
  539. package/dist/server/index.d.ts +7 -1
  540. package/dist/server/index.js +125 -6
  541. package/dist/server/openapi-document.d.ts +33 -0
  542. package/dist/server/openapi.d.ts +32 -0
  543. package/dist/server/respond.d.ts +35 -0
  544. package/dist/server/route-params.d.ts +17 -0
  545. package/dist/server/route-plan.d.ts +41 -0
  546. package/dist/server/routes-catalog.d.ts +5 -0
  547. package/dist/server/routes-declared.d.ts +12 -0
  548. package/dist/server/routes-runs.d.ts +8 -0
  549. package/dist/server/run-driver.d.ts +58 -0
  550. package/dist/server/run-view.d.ts +26 -0
  551. package/dist/server/transport.d.ts +35 -0
  552. package/dist/server/types.d.ts +143 -52
  553. package/dist/server/webhook-server.d.ts +12 -38
  554. package/dist/server/workflow-registry.d.ts +7 -4
  555. package/dist/service-registry.d.ts +49 -0
  556. package/dist/service-registry.js +123 -0
  557. package/dist/testing/assertions.d.ts +2 -2
  558. package/dist/testing/index.d.ts +14 -13
  559. package/dist/testing/index.js +582 -24
  560. package/dist/testing/mock-approval.d.ts +3 -5
  561. package/dist/testing/mock-llm.d.ts +2 -3
  562. package/dist/testing/recorder.d.ts +5 -6
  563. package/dist/testing/replayer.d.ts +6 -7
  564. package/dist/testing/run-store-check.d.ts +3 -0
  565. package/dist/testing/token-tracker.d.ts +2 -2
  566. package/dist/{type-mappings.d.ts → types/type-mappings.d.ts} +13 -1
  567. package/dist/utils/error-utils.d.ts +4 -2
  568. package/dist/utils/port-ordering.d.ts +2 -2
  569. package/dist/utils/port-tag-utils.d.ts +1 -1
  570. package/dist/validation/agent-detection.d.ts +17 -5
  571. package/dist/validation/agent-rules.d.ts +6 -7
  572. package/dist/validation/core-rules.d.ts +49 -0
  573. package/dist/validation/design-rules.d.ts +9 -3
  574. package/dist/validation/rule-registry.d.ts +3 -3
  575. package/dist/validation/rules/connections.d.ts +27 -0
  576. package/dist/validation/rules/context.d.ts +11 -0
  577. package/dist/validation/rules/cycles.d.ts +17 -0
  578. package/dist/validation/rules/data-flow.d.ts +19 -0
  579. package/dist/validation/rules/scope-topology.d.ts +35 -0
  580. package/dist/validation/rules/type-compatibility.d.ts +30 -0
  581. package/dist/validation/type-checker.d.ts +39 -0
  582. package/dist/validation/validator-helpers.d.ts +31 -0
  583. package/dist/validation/validator.d.ts +30 -0
  584. package/docs/reference/advanced-annotations.md +277 -60
  585. package/docs/reference/built-in-nodes.md +164 -94
  586. package/docs/reference/cancellation.md +44 -0
  587. package/docs/reference/cli-reference.md +252 -234
  588. package/docs/reference/compilation.md +36 -109
  589. package/docs/reference/concepts.md +80 -63
  590. package/docs/reference/console.md +169 -0
  591. package/docs/reference/debugging.md +26 -57
  592. package/docs/reference/deployment.md +217 -143
  593. package/docs/reference/durable-gates.md +445 -0
  594. package/docs/reference/error-codes.md +90 -43
  595. package/docs/reference/export-interface.md +91 -26
  596. package/docs/reference/iterative-development.md +50 -28
  597. package/docs/reference/jsdoc-grammar.md +66 -311
  598. package/docs/reference/library.md +250 -0
  599. package/docs/reference/marketplace.md +301 -152
  600. package/docs/reference/mcp-tools.md +102 -0
  601. package/docs/reference/node-conversion.md +84 -59
  602. package/docs/reference/orientation.md +68 -0
  603. package/docs/reference/scaffold.md +5 -4
  604. package/docs/reference/tutorial.md +106 -166
  605. package/docs/reference/visual-reference.md +1 -1
  606. package/package.json +85 -50
  607. package/dist/agent/agent-loop.js +0 -156
  608. package/dist/agent/cli-spawn-config.js +0 -65
  609. package/dist/agent/device-connection.d.ts +0 -79
  610. package/dist/agent/device-connection.js +0 -184
  611. package/dist/agent/env-allowlist.js +0 -60
  612. package/dist/agent/providers/anthropic.js +0 -198
  613. package/dist/agent/providers/claude-cli.js +0 -161
  614. package/dist/agent/providers/openai-compat.js +0 -205
  615. package/dist/agent/providers/platform.d.ts +0 -23
  616. package/dist/agent/providers/platform.js +0 -132
  617. package/dist/agent/streaming.js +0 -186
  618. package/dist/agent/types.js +0 -20
  619. package/dist/annotation-generator.d.ts +0 -50
  620. package/dist/annotation-generator.js +0 -743
  621. package/dist/api/builder.js +0 -345
  622. package/dist/api/command-runner.js +0 -787
  623. package/dist/api/compile.js +0 -148
  624. package/dist/api/extract-types.js +0 -57
  625. package/dist/api/generate-in-place.js +0 -1477
  626. package/dist/api/generate.js +0 -514
  627. package/dist/api/helpers.js +0 -285
  628. package/dist/api/inline-runtime.js +0 -526
  629. package/dist/api/manipulation/connections.js +0 -151
  630. package/dist/api/manipulation/index.js +0 -41
  631. package/dist/api/manipulation/node-types.js +0 -200
  632. package/dist/api/manipulation/nodes.js +0 -355
  633. package/dist/api/manipulation/ports.js +0 -228
  634. package/dist/api/manipulation/scopes.js +0 -156
  635. package/dist/api/manipulation/workflow.js +0 -116
  636. package/dist/api/modify-operation.js +0 -177
  637. package/dist/api/parse.js +0 -115
  638. package/dist/api/patterns.d.ts +0 -112
  639. package/dist/api/patterns.js +0 -303
  640. package/dist/api/query.js +0 -840
  641. package/dist/api/templates.js +0 -117
  642. package/dist/api/transform.js +0 -40
  643. package/dist/api/validate.js +0 -64
  644. package/dist/api/validation-registry.js +0 -10
  645. package/dist/api/workflow-file-operations.js +0 -180
  646. package/dist/ast/builder.js +0 -395
  647. package/dist/ast/serialization-node.js +0 -30
  648. package/dist/ast/serialization.js +0 -134
  649. package/dist/ast/types.js +0 -2
  650. package/dist/ast/workflow-utils.js +0 -114
  651. package/dist/body-generator.js +0 -35
  652. package/dist/built-in-nodes/coercion-types.js +0 -61
  653. package/dist/built-in-nodes/delay.js +0 -29
  654. package/dist/built-in-nodes/generated-registry.js +0 -299
  655. package/dist/built-in-nodes/invoke-workflow.js +0 -36
  656. package/dist/built-in-nodes/mock-types.js +0 -42
  657. package/dist/built-in-nodes/wait-for-agent.js +0 -31
  658. package/dist/built-in-nodes/wait-for-event.js +0 -25
  659. package/dist/chevrotain-parser/coerce-parser.js +0 -103
  660. package/dist/chevrotain-parser/connect-parser.js +0 -136
  661. package/dist/chevrotain-parser/fan-parser.js +0 -149
  662. package/dist/chevrotain-parser/grammar-diagrams.js +0 -273
  663. package/dist/chevrotain-parser/index.js +0 -31
  664. package/dist/chevrotain-parser/map-parser.js +0 -130
  665. package/dist/chevrotain-parser/node-parser.js +0 -558
  666. package/dist/chevrotain-parser/path-parser.js +0 -140
  667. package/dist/chevrotain-parser/port-parser.js +0 -519
  668. package/dist/chevrotain-parser/position-parser.d.ts +0 -20
  669. package/dist/chevrotain-parser/position-parser.js +0 -83
  670. package/dist/chevrotain-parser/scope-parser.js +0 -104
  671. package/dist/chevrotain-parser/tokens.js +0 -429
  672. package/dist/chevrotain-parser/trigger-cancel-parser.js +0 -291
  673. package/dist/cli/commands/account.d.ts +0 -4
  674. package/dist/cli/commands/account.js +0 -50
  675. package/dist/cli/commands/ai-credentials.d.ts +0 -12
  676. package/dist/cli/commands/ai-credentials.js +0 -95
  677. package/dist/cli/commands/apikey.d.ts +0 -4
  678. package/dist/cli/commands/apikey.js +0 -64
  679. package/dist/cli/commands/auth.d.ts +0 -9
  680. package/dist/cli/commands/auth.js +0 -255
  681. package/dist/cli/commands/compile.js +0 -331
  682. package/dist/cli/commands/connect.d.ts +0 -4
  683. package/dist/cli/commands/connect.js +0 -163
  684. package/dist/cli/commands/context.js +0 -51
  685. package/dist/cli/commands/create.js +0 -139
  686. package/dist/cli/commands/deploy.d.ts +0 -6
  687. package/dist/cli/commands/deploy.js +0 -74
  688. package/dist/cli/commands/dev.js +0 -227
  689. package/dist/cli/commands/diagram.js +0 -39
  690. package/dist/cli/commands/diff.js +0 -57
  691. package/dist/cli/commands/docs.js +0 -74
  692. package/dist/cli/commands/export.js +0 -153
  693. package/dist/cli/commands/grammar.js +0 -40
  694. package/dist/cli/commands/implement.js +0 -91
  695. package/dist/cli/commands/init-personas.js +0 -541
  696. package/dist/cli/commands/init.js +0 -797
  697. package/dist/cli/commands/market.js +0 -440
  698. package/dist/cli/commands/mcp-setup.js +0 -433
  699. package/dist/cli/commands/migrate.js +0 -91
  700. package/dist/cli/commands/modify.js +0 -58
  701. package/dist/cli/commands/openapi.js +0 -71
  702. package/dist/cli/commands/org.d.ts +0 -8
  703. package/dist/cli/commands/org.js +0 -136
  704. package/dist/cli/commands/pattern.d.ts +0 -34
  705. package/dist/cli/commands/pattern.js +0 -186
  706. package/dist/cli/commands/plugin.d.ts +0 -16
  707. package/dist/cli/commands/plugin.js +0 -176
  708. package/dist/cli/commands/run.js +0 -742
  709. package/dist/cli/commands/serve.js +0 -93
  710. package/dist/cli/commands/status.js +0 -123
  711. package/dist/cli/commands/strip.js +0 -61
  712. package/dist/cli/commands/templates.js +0 -58
  713. package/dist/cli/commands/validate.js +0 -267
  714. package/dist/cli/commands/watch.js +0 -71
  715. package/dist/cli/config/credentials.d.ts +0 -15
  716. package/dist/cli/config/credentials.js +0 -43
  717. package/dist/cli/config/platform-client.d.ts +0 -123
  718. package/dist/cli/config/platform-client.js +0 -248
  719. package/dist/cli/env-setup.js +0 -12
  720. package/dist/cli/index.js +0 -850
  721. package/dist/cli/pack-commands.js +0 -122
  722. package/dist/cli/postinstall.d.ts +0 -16
  723. package/dist/cli/postinstall.js +0 -119
  724. package/dist/cli/templates/ai/mock-provider.js +0 -64
  725. package/dist/cli/templates/ai/types.js +0 -5
  726. package/dist/cli/templates/approvals/index.d.ts +0 -15
  727. package/dist/cli/templates/approvals/index.js +0 -241
  728. package/dist/cli/templates/index.js +0 -123
  729. package/dist/cli/templates/nodes/agent-router.js +0 -114
  730. package/dist/cli/templates/nodes/aggregator.js +0 -63
  731. package/dist/cli/templates/nodes/conversation-memory.js +0 -85
  732. package/dist/cli/templates/nodes/http.js +0 -80
  733. package/dist/cli/templates/nodes/human-approval.js +0 -109
  734. package/dist/cli/templates/nodes/json-extractor.js +0 -119
  735. package/dist/cli/templates/nodes/llm-call.js +0 -106
  736. package/dist/cli/templates/nodes/prompt-template.js +0 -52
  737. package/dist/cli/templates/nodes/rag-retriever.js +0 -128
  738. package/dist/cli/templates/nodes/tool-executor.js +0 -108
  739. package/dist/cli/templates/nodes/transformer.js +0 -68
  740. package/dist/cli/templates/nodes/validator.js +0 -62
  741. package/dist/cli/templates/pack-loader.js +0 -58
  742. package/dist/cli/templates/providers/index.js +0 -239
  743. package/dist/cli/templates/shared/approval-types.js +0 -31
  744. package/dist/cli/templates/shared/llm-types.js +0 -109
  745. package/dist/cli/templates/workflows/aggregator.js +0 -101
  746. package/dist/cli/templates/workflows/ai-agent.js +0 -326
  747. package/dist/cli/templates/workflows/ai-chat.js +0 -167
  748. package/dist/cli/templates/workflows/ai-rag.js +0 -184
  749. package/dist/cli/templates/workflows/ai-react.js +0 -293
  750. package/dist/cli/templates/workflows/conditional.js +0 -139
  751. package/dist/cli/templates/workflows/error-handler.js +0 -145
  752. package/dist/cli/templates/workflows/foreach.js +0 -140
  753. package/dist/cli/templates/workflows/sequential.js +0 -200
  754. package/dist/cli/templates/workflows/webhook.js +0 -158
  755. package/dist/cli/utils/cli-helpers.d.ts +0 -44
  756. package/dist/cli/utils/cli-helpers.js +0 -99
  757. package/dist/cli/utils/logger.js +0 -126
  758. package/dist/cli/utils/parse-int-strict.js +0 -17
  759. package/dist/cli/utils/safe-write.js +0 -54
  760. package/dist/deployment/config/defaults.d.ts +0 -29
  761. package/dist/deployment/config/defaults.js +0 -98
  762. package/dist/deployment/config/loader.d.ts +0 -24
  763. package/dist/deployment/config/loader.js +0 -237
  764. package/dist/deployment/config/types.d.ts +0 -117
  765. package/dist/deployment/config/types.js +0 -5
  766. package/dist/deployment/core/adapters.d.ts +0 -66
  767. package/dist/deployment/core/adapters.js +0 -156
  768. package/dist/deployment/core/executor.d.ts +0 -62
  769. package/dist/deployment/core/executor.js +0 -197
  770. package/dist/deployment/core/formatters.d.ts +0 -42
  771. package/dist/deployment/core/formatters.js +0 -146
  772. package/dist/deployment/openapi/generator.d.ts +0 -146
  773. package/dist/deployment/openapi/generator.js +0 -347
  774. package/dist/deployment/openapi/schema-converter.d.ts +0 -49
  775. package/dist/deployment/openapi/schema-converter.js +0 -192
  776. package/dist/deployment/targets/base.js +0 -855
  777. package/dist/deployment/types.d.ts +0 -140
  778. package/dist/deployment/types.js +0 -8
  779. package/dist/diagram/ascii-renderer.js +0 -528
  780. package/dist/diagram/geometry.js +0 -1226
  781. package/dist/diagram/html-viewer.d.ts +0 -21
  782. package/dist/diagram/html-viewer.js +0 -1745
  783. package/dist/diagram/layout.js +0 -143
  784. package/dist/diagram/orthogonal-router.js +0 -458
  785. package/dist/diagram/renderer.d.ts +0 -3
  786. package/dist/diagram/renderer.js +0 -280
  787. package/dist/diagram/theme.js +0 -282
  788. package/dist/diagram/types.js +0 -2
  789. package/dist/diff/WorkflowDiffer.js +0 -429
  790. package/dist/diff/formatDiff.js +0 -239
  791. package/dist/diff/impact.js +0 -119
  792. package/dist/diff/types.js +0 -35
  793. package/dist/doc-metadata/extractors/annotations.js +0 -638
  794. package/dist/doc-metadata/extractors/cli-commands.js +0 -326
  795. package/dist/doc-metadata/extractors/core-metadata.js +0 -61
  796. package/dist/doc-metadata/extractors/error-codes.js +0 -372
  797. package/dist/doc-metadata/extractors/grammar-rules.js +0 -51
  798. package/dist/doc-metadata/extractors/mcp-tools.js +0 -705
  799. package/dist/doc-metadata/extractors/plugin-api.d.ts +0 -19
  800. package/dist/doc-metadata/extractors/plugin-api.js +0 -279
  801. package/dist/doc-metadata/types.js +0 -5
  802. package/dist/editor-completions/annotationValues.js +0 -146
  803. package/dist/editor-completions/contextParser.js +0 -410
  804. package/dist/editor-completions/dataTypes.js +0 -95
  805. package/dist/editor-completions/goToDefinition.js +0 -112
  806. package/dist/editor-completions/jsDocAnnotations.js +0 -359
  807. package/dist/editor-completions/modifierCompletions.js +0 -197
  808. package/dist/editor-completions/types.js +0 -8
  809. package/dist/export/index.js +0 -212
  810. package/dist/extensions/index.d.ts +0 -16
  811. package/dist/extensions/index.js +0 -17
  812. package/dist/friendly-errors.js +0 -761
  813. package/dist/function-like.js +0 -84
  814. package/dist/generator/async-detection.js +0 -56
  815. package/dist/generator/code-utils.js +0 -551
  816. package/dist/generator/compile-target-registry.d.ts +0 -20
  817. package/dist/generator/compile-target-registry.js +0 -20
  818. package/dist/generator/control-flow.js +0 -358
  819. package/dist/generator/dev-mode-registry.d.ts +0 -27
  820. package/dist/generator/dev-mode-registry.js +0 -20
  821. package/dist/generator/scope-function-generator.js +0 -397
  822. package/dist/generator/unified.js +0 -1831
  823. package/dist/generator.d.ts +0 -54
  824. package/dist/generator.js +0 -101
  825. package/dist/jsdoc-parser.d.ts +0 -377
  826. package/dist/jsdoc-parser.js +0 -1189
  827. package/dist/jsdoc-port-sync/constants.js +0 -103
  828. package/dist/jsdoc-port-sync/diff.js +0 -319
  829. package/dist/jsdoc-port-sync/port-parser.js +0 -579
  830. package/dist/jsdoc-port-sync/rename.js +0 -256
  831. package/dist/jsdoc-port-sync/signature-parser.js +0 -559
  832. package/dist/jsdoc-port-sync/sync.js +0 -653
  833. package/dist/marketplace/manifest.js +0 -194
  834. package/dist/marketplace/registry.js +0 -198
  835. package/dist/marketplace/types.js +0 -9
  836. package/dist/marketplace/validator.js +0 -150
  837. package/dist/mcp/agent-channel.d.ts +0 -35
  838. package/dist/mcp/agent-channel.js +0 -61
  839. package/dist/mcp/auto-registration.d.ts +0 -3
  840. package/dist/mcp/auto-registration.js +0 -62
  841. package/dist/mcp/debug-session.js +0 -25
  842. package/dist/mcp/index.d.ts +0 -11
  843. package/dist/mcp/index.js +0 -10
  844. package/dist/mcp/pack-tools.js +0 -59
  845. package/dist/mcp/prompts.js +0 -68
  846. package/dist/mcp/response-utils.js +0 -97
  847. package/dist/mcp/run-registry.d.ts +0 -29
  848. package/dist/mcp/run-registry.js +0 -24
  849. package/dist/mcp/server.js +0 -63
  850. package/dist/mcp/tools-context.js +0 -51
  851. package/dist/mcp/tools-debug.js +0 -451
  852. package/dist/mcp/tools-diagram.js +0 -97
  853. package/dist/mcp/tools-docs.js +0 -62
  854. package/dist/mcp/tools-export.js +0 -222
  855. package/dist/mcp/tools-marketplace.js +0 -132
  856. package/dist/mcp/tools-model.d.ts +0 -3
  857. package/dist/mcp/tools-model.js +0 -279
  858. package/dist/mcp/tools-pattern.d.ts +0 -3
  859. package/dist/mcp/tools-pattern.js +0 -604
  860. package/dist/mcp/tools-query.js +0 -377
  861. package/dist/mcp/tools-resources.js +0 -41
  862. package/dist/mcp/tools-template.js +0 -119
  863. package/dist/mcp/tools-workflow-run.d.ts +0 -40
  864. package/dist/mcp/tools-workflow-run.js +0 -150
  865. package/dist/mcp/types.js +0 -2
  866. package/dist/mcp/workflow-executor.js +0 -242
  867. package/dist/migration/registry.js +0 -29
  868. package/dist/node-types-generator.js +0 -139
  869. package/dist/parser/tag-registry.js +0 -57
  870. package/dist/parser.d.ts +0 -232
  871. package/dist/parser.js +0 -2500
  872. package/dist/plugin/PluginPanel.d.ts +0 -12
  873. package/dist/plugin/PluginPanel.js +0 -5
  874. package/dist/plugin/index.d.ts +0 -13
  875. package/dist/plugin/index.js +0 -14
  876. package/dist/plugin/types.d.ts +0 -75
  877. package/dist/plugin/types.js +0 -8
  878. package/dist/resolve-package-types.js +0 -123
  879. package/dist/runtime/CancellationError.js +0 -20
  880. package/dist/runtime/ExecutionContext.js +0 -280
  881. package/dist/runtime/builtin-functions.js +0 -549
  882. package/dist/runtime/checkpoint.d.ts +0 -84
  883. package/dist/runtime/checkpoint.js +0 -225
  884. package/dist/runtime/debug-controller.js +0 -247
  885. package/dist/runtime/events.js +0 -2
  886. package/dist/runtime/function-registry.js +0 -66
  887. package/dist/runtime/parameter-resolver.js +0 -113
  888. package/dist/server/types.js +0 -5
  889. package/dist/server/webhook-server.js +0 -269
  890. package/dist/server/workflow-registry.js +0 -202
  891. package/dist/shared-project.js +0 -28
  892. package/dist/sugar-optimizer.js +0 -498
  893. package/dist/testing/assertions.js +0 -127
  894. package/dist/testing/mock-approval.js +0 -98
  895. package/dist/testing/mock-llm.js +0 -119
  896. package/dist/testing/recorder.js +0 -70
  897. package/dist/testing/replayer.js +0 -143
  898. package/dist/testing/token-tracker.js +0 -94
  899. package/dist/type-checker.d.ts +0 -42
  900. package/dist/type-checker.js +0 -190
  901. package/dist/type-mappings.js +0 -131
  902. package/dist/types/branded-ports.d.ts +0 -151
  903. package/dist/types/branded-ports.js +0 -121
  904. package/dist/types/index.d.ts +0 -5
  905. package/dist/types/index.js +0 -5
  906. package/dist/types.d.ts +0 -139
  907. package/dist/types.js +0 -15
  908. package/dist/utils/error-utils.js +0 -27
  909. package/dist/utils/lru-cache.js +0 -40
  910. package/dist/utils/port-ordering.js +0 -81
  911. package/dist/utils/port-tag-utils.js +0 -41
  912. package/dist/utils/string-distance.js +0 -56
  913. package/dist/validation/agent-detection.js +0 -115
  914. package/dist/validation/agent-rules.js +0 -262
  915. package/dist/validation/design-rules.js +0 -377
  916. package/dist/validation/rule-registry.js +0 -37
  917. package/dist/validator.d.ts +0 -113
  918. package/dist/validator.js +0 -1631
  919. package/docs/reference/patterns.md +0 -159
  920. package/scripts/postinstall.cjs +0 -86
  921. /package/dist/{shared-project.d.ts → parser/shared-project.d.ts} +0 -0
  922. /package/dist/{friendly-errors.d.ts → validation/friendly-errors.d.ts} +0 -0
package/dist/validator.js DELETED
@@ -1,1631 +0,0 @@
1
- import { RESERVED_NODE_NAMES, isStartNode, isExitNode, isPseudoNode, isExecutePort, isReservedNodeName, VALID_NODE_COLORS, EXECUTION_STRATEGIES, } from './constants.js';
2
- import { findClosestMatches } from './utils/string-distance.js';
3
- import { parseFunctionSignature } from './jsdoc-port-sync/signature-parser.js';
4
- import { checkTypeCompatibilityFromStrings } from './type-checker.js';
5
- import { isValidPortType } from './type-mappings.js';
6
- import { VALID_NODE_ICONS } from './diagram/theme.js';
7
- const DOCS_BASE = 'https://docs.flowweaver.dev/reference';
8
- /** Map error codes to the documentation page that explains how to fix them. */
9
- const ERROR_DOC_URLS = {
10
- UNKNOWN_NODE_TYPE: `${DOCS_BASE}/concepts#node-registration`,
11
- UNKNOWN_SOURCE_PORT: `${DOCS_BASE}/concepts#port-architecture`,
12
- UNKNOWN_TARGET_PORT: `${DOCS_BASE}/concepts#port-architecture`,
13
- TYPE_MISMATCH: `${DOCS_BASE}/compilation#type-compatibility`,
14
- UNREACHABLE_NODE: `${DOCS_BASE}/concepts#graph-structure`,
15
- MISSING_START_CONNECTION: `${DOCS_BASE}/concepts#start-and-exit`,
16
- MISSING_EXIT_CONNECTION: `${DOCS_BASE}/concepts#start-and-exit`,
17
- INFERRED_NODE_TYPE: `${DOCS_BASE}/node-conversion`,
18
- DUPLICATE_CONNECTION: `${DOCS_BASE}/concepts#connections`,
19
- STUB_NODE: `${DOCS_BASE}/model-driven#stub-nodes`,
20
- COERCE_TYPE_MISMATCH: `${DOCS_BASE}/compilation#type-coercion`,
21
- REDUNDANT_COERCE: `${DOCS_BASE}/compilation#type-coercion`,
22
- COERCE_ON_FUNCTION_PORT: `${DOCS_BASE}/compilation#type-coercion`,
23
- };
24
- /** Map coerce type to the dataType it produces */
25
- const COERCE_OUTPUT_TYPE = {
26
- string: 'STRING', number: 'NUMBER', boolean: 'BOOLEAN',
27
- json: 'STRING', object: 'OBJECT',
28
- };
29
- /** Suggest the correct `as <type>` for a given target dataType */
30
- function suggestCoerceType(targetType) {
31
- switch (targetType) {
32
- case 'STRING': return 'string';
33
- case 'NUMBER': return 'number';
34
- case 'BOOLEAN': return 'boolean';
35
- case 'OBJECT': return 'object';
36
- default: return '<type>';
37
- }
38
- }
39
- export class WorkflowValidator {
40
- errors = [];
41
- warnings = [];
42
- strictMode = false;
43
- draftMode = false;
44
- /** Look up instance sourceLocation by instance ID */
45
- getInstanceLocation(workflow, instanceId) {
46
- const instance = workflow.instances.find((inst) => inst.id === instanceId);
47
- return instance?.sourceLocation;
48
- }
49
- /** Look up connection sourceLocation */
50
- getConnectionLocation(conn) {
51
- return conn.sourceLocation;
52
- }
53
- /**
54
- * Validate a single node type for scoped port requirements
55
- *
56
- * Scoped Port Architecture Rules:
57
- * - Scope names must be valid JavaScript identifiers
58
- *
59
- * Per-Port Scope Architecture:
60
- * - Scoped OUTPUT ports become callback PARAMETERS (data flows to children)
61
- * - Scoped INPUT ports become callback RETURN VALUES (data flows from children)
62
- * - Scoped ports can be ANY data type - they're not functions themselves
63
- * - The callback function is passed as a function parameter (e.g., forEach's itemProcessor)
64
- *
65
- * NOTE: execute/onSuccess/onFailure ports are mandatory base interface ports
66
- * that are auto-added to ALL nodes - no validation needed for those.
67
- */
68
- validateNodeType(nodeType) {
69
- const errors = [];
70
- // Get all scoped ports (both INPUT and OUTPUT)
71
- const scopedPorts = [
72
- ...Object.entries(nodeType.inputs).filter(([_, portDef]) => portDef.scope !== undefined),
73
- ...Object.entries(nodeType.outputs).filter(([_, portDef]) => portDef.scope !== undefined),
74
- ];
75
- // Rule: Validate scope names are valid JavaScript identifiers
76
- const scopeNameRegex = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
77
- scopedPorts.forEach(([portName, portDef]) => {
78
- if (portDef.scope && !scopeNameRegex.test(portDef.scope)) {
79
- errors.push(`Port "${portName}" has invalid scope name "${portDef.scope}". Scope names must be valid JavaScript identifiers (letters, numbers, underscore, dollar sign; cannot start with number).`);
80
- }
81
- });
82
- // Note: Scoped ports can be ANY data type in the per-port scope architecture
83
- // They become callback parameters/returns, not functions themselves
84
- return errors;
85
- }
86
- validate(workflow, options) {
87
- this.errors = [];
88
- this.warnings = [];
89
- this.strictMode = options?.strictMode ?? false;
90
- this.draftMode = options?.mode === 'draft';
91
- const nodeTypeMap = new Map();
92
- // Map by both functionName and name to support npm nodes (name='npm/pkg/func', functionName='func')
93
- workflow.nodeTypes.forEach((nodeType) => {
94
- nodeTypeMap.set(nodeType.functionName, nodeType);
95
- if (nodeType.name !== nodeType.functionName) {
96
- nodeTypeMap.set(nodeType.name, nodeType);
97
- }
98
- });
99
- // Build instance map: instance ID -> node type
100
- const instanceMap = new Map();
101
- workflow.instances.forEach((instance) => {
102
- // Check both name (for npm nodes like 'npm/pkg/func') and functionName (for local nodes)
103
- const nodeType = workflow.nodeTypes.find((nt) => nt.name === instance.nodeType || nt.functionName === instance.nodeType);
104
- if (nodeType) {
105
- instanceMap.set(instance.id, nodeType);
106
- }
107
- else {
108
- // Check if the function exists but is unannotated
109
- const isUnannotatedFunction = workflow.availableFunctionNames?.includes(instance.nodeType) ?? false;
110
- let hint;
111
- if (isUnannotatedFunction) {
112
- hint = ` Function "${instance.nodeType}" exists but has no @flowWeaver nodeType annotation. Add /** @flowWeaver nodeType */ above it.`;
113
- }
114
- else {
115
- const availableTypes = workflow.nodeTypes.map((nt) => nt.functionName);
116
- const suggestions = findClosestMatches(instance.nodeType, availableTypes);
117
- hint = suggestions.length > 0 ? ` Did you mean "${suggestions[0]}"?` : '';
118
- }
119
- this.errors.push({
120
- type: 'error',
121
- code: 'UNKNOWN_NODE_TYPE',
122
- message: `Node "${instance.id}" references unknown node type "${instance.nodeType}".${hint}`,
123
- node: instance.id,
124
- location: instance.sourceLocation,
125
- });
126
- }
127
- });
128
- // Info diagnostic for auto-inferred node types
129
- workflow.instances.forEach((instance) => {
130
- // Check both name (for npm nodes like 'npm/pkg/func') and functionName (for local nodes)
131
- const nodeType = workflow.nodeTypes.find((nt) => nt.name === instance.nodeType || nt.functionName === instance.nodeType);
132
- if (nodeType?.inferred && nodeType.variant !== 'STUB') {
133
- this.warnings.push({
134
- type: 'warning',
135
- code: 'INFERRED_NODE_TYPE',
136
- message: `Node type "${instance.nodeType}" was auto-inferred from function signature (expression mode). Add @flowWeaver nodeType for explicit port control.`,
137
- node: instance.id,
138
- location: instance.sourceLocation,
139
- });
140
- }
141
- });
142
- // Stub node diagnostics: always emit as errors, draft mode reclassifies at the end
143
- workflow.instances.forEach((instance) => {
144
- const nodeType = workflow.nodeTypes.find((nt) => nt.name === instance.nodeType || nt.functionName === instance.nodeType);
145
- if (nodeType?.variant === 'STUB') {
146
- this.errors.push({
147
- type: 'error',
148
- code: 'STUB_NODE',
149
- message: `Node "${instance.id}" uses stub type "${instance.nodeType}" which has no implementation. Use draft mode to validate structure, or implement the node.`,
150
- node: instance.id,
151
- location: instance.sourceLocation,
152
- });
153
- }
154
- });
155
- // Structural validation
156
- this.validateStructure(workflow);
157
- this.validateDuplicateNodeNames(workflow);
158
- this.validateDuplicateInstanceIds(workflow);
159
- this.validateMutableBindings(workflow);
160
- // Connection and node validation
161
- this.validateReservedNames(workflow, nodeTypeMap);
162
- this.validateConnections(workflow, instanceMap);
163
- this.validateDuplicateConnections(workflow);
164
- this.validateNodeReferences(workflow, instanceMap);
165
- this.validateTypeCompatibility(workflow, instanceMap);
166
- this.validateRequiredInputs(workflow, instanceMap);
167
- this.detectUnusedNodes(workflow, instanceMap);
168
- this.validateStartAndExit(workflow);
169
- this.validateDataFlow(workflow, instanceMap);
170
- this.validateCycles(workflow);
171
- this.validateMultipleInputConnections(workflow, instanceMap);
172
- this.validateAnnotationSignatureConsistency(workflow);
173
- this.validateVisualAnnotations(workflow, instanceMap);
174
- this.validatePortTypes(workflow);
175
- this.validatePortConfigReferences(workflow, instanceMap);
176
- this.validateExecuteWhen(workflow);
177
- this.validateScopeTopology(workflow, instanceMap);
178
- // Deduplicate cascading errors: if a node has UNKNOWN_NODE_TYPE,
179
- // suppress UNKNOWN_SOURCE_NODE, UNKNOWN_TARGET_NODE, and UNDEFINED_NODE
180
- // that reference the same node IDs (they're just noise).
181
- const unknownTypeInstanceIds = new Set(workflow.instances.filter((inst) => !nodeTypeMap.has(inst.nodeType)).map((inst) => inst.id));
182
- if (unknownTypeInstanceIds.size > 0) {
183
- this.errors = this.errors.filter((error) => {
184
- if (error.code === 'UNKNOWN_NODE_TYPE')
185
- return true; // Always keep root cause
186
- // Suppress cascading errors that reference unknown-type instances
187
- const cascadingCodes = new Set([
188
- 'UNKNOWN_SOURCE_NODE',
189
- 'UNKNOWN_TARGET_NODE',
190
- 'UNDEFINED_NODE',
191
- 'MISSING_REQUIRED_INPUT',
192
- ]);
193
- if (!cascadingCodes.has(error.code))
194
- return true;
195
- // Check if this error references an unknown-type instance
196
- if (error.node && unknownTypeInstanceIds.has(error.node))
197
- return false;
198
- if (error.connection) {
199
- if (unknownTypeInstanceIds.has(error.connection.from.node))
200
- return false;
201
- if (unknownTypeInstanceIds.has(error.connection.to.node))
202
- return false;
203
- }
204
- return true;
205
- });
206
- }
207
- // Draft mode post-processing: reclassify stub-related errors as warnings
208
- if (this.draftMode) {
209
- const stubTypeNames = new Set(workflow.nodeTypes.filter((nt) => nt.variant === 'STUB').map((nt) => nt.functionName));
210
- // Also index by name for npm-style nodes
211
- workflow.nodeTypes.filter((nt) => nt.variant === 'STUB').forEach((nt) => {
212
- stubTypeNames.add(nt.name);
213
- });
214
- const stubInstanceIds = new Set(workflow.instances
215
- .filter((inst) => stubTypeNames.has(inst.nodeType))
216
- .map((inst) => inst.id));
217
- const promoted = [];
218
- this.errors = this.errors.filter((err) => {
219
- if (err.code === 'STUB_NODE') {
220
- promoted.push({ ...err, type: 'warning' });
221
- return false;
222
- }
223
- if (err.code === 'MISSING_REQUIRED_INPUT' && err.node && stubInstanceIds.has(err.node)) {
224
- promoted.push({ ...err, type: 'warning' });
225
- return false;
226
- }
227
- return true;
228
- });
229
- this.warnings.push(...promoted);
230
- }
231
- // Filter out warnings suppressed by per-instance [suppress: "CODE"] annotations
232
- const suppressMap = new Map();
233
- for (const inst of workflow.instances) {
234
- if (inst.config?.suppressWarnings?.length) {
235
- suppressMap.set(inst.id, new Set(inst.config.suppressWarnings));
236
- }
237
- }
238
- if (suppressMap.size > 0) {
239
- this.warnings = this.warnings.filter((w) => {
240
- if (!w.node)
241
- return true;
242
- const codes = suppressMap.get(w.node);
243
- return !codes || !codes.has(w.code);
244
- });
245
- }
246
- // Attach doc URLs to diagnostics that have mapped error codes
247
- for (const diag of [...this.errors, ...this.warnings]) {
248
- if (!diag.docUrl && ERROR_DOC_URLS[diag.code]) {
249
- diag.docUrl = ERROR_DOC_URLS[diag.code];
250
- }
251
- }
252
- return {
253
- valid: this.errors.length === 0,
254
- errors: this.errors,
255
- warnings: this.warnings,
256
- };
257
- }
258
- validateStructure(workflow) {
259
- if (!workflow.name) {
260
- this.errors.push({
261
- type: 'error',
262
- code: 'MISSING_WORKFLOW_NAME',
263
- message: 'Workflow must have a name',
264
- });
265
- }
266
- if (!workflow.functionName) {
267
- this.errors.push({
268
- type: 'error',
269
- code: 'MISSING_FUNCTION_NAME',
270
- message: 'Workflow must have a functionName',
271
- });
272
- }
273
- }
274
- validateDuplicateNodeNames(workflow) {
275
- const nodeNames = new Set();
276
- workflow.nodeTypes.forEach((nodeType) => {
277
- if (nodeNames.has(nodeType.functionName)) {
278
- this.errors.push({
279
- type: 'error',
280
- code: 'DUPLICATE_NODE_NAME',
281
- message: `Duplicate node type name: "${nodeType.functionName}"`,
282
- node: nodeType.functionName,
283
- location: nodeType.sourceLocation,
284
- });
285
- }
286
- nodeNames.add(nodeType.functionName);
287
- });
288
- }
289
- validateMutableBindings(workflow) {
290
- workflow.nodeTypes.forEach((nodeType) => {
291
- if (nodeType.declarationKind && nodeType.declarationKind !== 'const') {
292
- this.warnings.push({
293
- type: 'warning',
294
- code: 'MUTABLE_NODE_TYPE_BINDING',
295
- message: `Node type "${nodeType.functionName}" is declared with "${nodeType.declarationKind}" instead of "const". Use "const" to prevent accidental reassignment.`,
296
- node: nodeType.functionName,
297
- location: nodeType.sourceLocation,
298
- });
299
- }
300
- });
301
- }
302
- validateReservedNames(workflow, nodeTypeMap) {
303
- // Check for node types with reserved names (Start, Exit)
304
- // Note: Port name validation is done during parsing
305
- nodeTypeMap.forEach((nodeType, nodeName) => {
306
- if (isReservedNodeName(nodeName)) {
307
- this.errors.push({
308
- type: 'error',
309
- code: 'RESERVED_NODE_NAME',
310
- message: `Node type name "${nodeName}" is reserved. Reserved node names: ${Object.values(RESERVED_NODE_NAMES).join(', ')}`,
311
- node: nodeName,
312
- location: nodeType.sourceLocation,
313
- });
314
- }
315
- });
316
- // Check for instances with reserved IDs
317
- workflow.instances.forEach((instance) => {
318
- if (isReservedNodeName(instance.id)) {
319
- this.errors.push({
320
- type: 'error',
321
- code: 'RESERVED_INSTANCE_ID',
322
- message: `Instance ID "${instance.id}" is reserved. Reserved names: ${Object.values(RESERVED_NODE_NAMES).join(', ')}`,
323
- node: instance.id,
324
- location: instance.sourceLocation,
325
- });
326
- }
327
- });
328
- }
329
- validateConnections(workflow, instanceMap) {
330
- workflow.connections.forEach((conn, _index) => {
331
- const fromNode = conn.from.node;
332
- const fromPort = conn.from.port;
333
- const connLocation = this.getConnectionLocation(conn);
334
- if (!isStartNode(fromNode) && !isPseudoNode(fromNode) && !instanceMap.has(fromNode)) {
335
- const instanceIds = [...instanceMap.keys()];
336
- const suggestions = findClosestMatches(fromNode, instanceIds);
337
- const suggestion = suggestions.length > 0 ? ` Did you mean "${suggestions[0]}"?` : '';
338
- this.errors.push({
339
- type: 'error',
340
- code: 'UNKNOWN_SOURCE_NODE',
341
- message: `Connection references unknown source node: "${fromNode}"${suggestion}`,
342
- connection: conn,
343
- location: connLocation,
344
- });
345
- }
346
- const toNode = conn.to.node;
347
- const toPort = conn.to.port;
348
- if (!isExitNode(toNode) && !instanceMap.has(toNode)) {
349
- const instanceIds = [...instanceMap.keys()];
350
- const suggestions = findClosestMatches(toNode, instanceIds);
351
- const suggestion = suggestions.length > 0 ? ` Did you mean "${suggestions[0]}"?` : '';
352
- this.errors.push({
353
- type: 'error',
354
- code: 'UNKNOWN_TARGET_NODE',
355
- message: `Connection references unknown target node: "${toNode}"${suggestion}`,
356
- connection: conn,
357
- location: connLocation,
358
- });
359
- }
360
- if (!isStartNode(fromNode)) {
361
- const sourceNode = instanceMap.get(fromNode);
362
- if (sourceNode && !sourceNode.outputs.hasOwnProperty(fromPort)) {
363
- const portNames = Object.keys(sourceNode.outputs);
364
- const suggestions = findClosestMatches(fromPort, portNames);
365
- const suggestion = suggestions.length > 0 ? ` Did you mean "${suggestions[0]}"?` : '';
366
- this.errors.push({
367
- type: 'error',
368
- code: 'UNKNOWN_SOURCE_PORT',
369
- message: `Node "${fromNode}" does not have output port "${fromPort}"${suggestion}`,
370
- node: fromNode,
371
- connection: conn,
372
- location: connLocation,
373
- });
374
- }
375
- }
376
- else {
377
- // Validate Start output port against declared @param ports
378
- // 'execute' is always implicit on Start
379
- const validStartPorts = new Set(['execute', ...Object.keys(workflow.startPorts)]);
380
- if (!validStartPorts.has(fromPort)) {
381
- const portNames = Array.from(validStartPorts);
382
- const suggestions = findClosestMatches(fromPort, portNames);
383
- let hint;
384
- if (suggestions.length > 0) {
385
- hint = ` Did you mean "${suggestions[0]}"?`;
386
- }
387
- else {
388
- hint = `\nAdd '@param ${fromPort}' to the workflow JSDoc and include it in the params object:\n(execute: boolean, params: { ${fromPort}: type, ... })`;
389
- }
390
- this.errors.push({
391
- type: 'error',
392
- code: 'UNKNOWN_SOURCE_PORT',
393
- message: `Start node does not have output port "${fromPort}".${hint}`,
394
- node: fromNode,
395
- connection: conn,
396
- location: connLocation,
397
- });
398
- }
399
- }
400
- if (!isExitNode(toNode)) {
401
- const targetNode = instanceMap.get(toNode);
402
- if (targetNode && !targetNode.inputs.hasOwnProperty(toPort)) {
403
- const portNames = Object.keys(targetNode.inputs);
404
- const suggestions = findClosestMatches(toPort, portNames);
405
- const suggestion = suggestions.length > 0 ? ` Did you mean "${suggestions[0]}"?` : '';
406
- this.errors.push({
407
- type: 'error',
408
- code: 'UNKNOWN_TARGET_PORT',
409
- message: `Node "${toNode}" does not have input port "${toPort}"${suggestion}`,
410
- node: toNode,
411
- connection: conn,
412
- location: connLocation,
413
- });
414
- }
415
- }
416
- else {
417
- // Validate Exit input port against declared @returns ports
418
- // 'onSuccess' and 'onFailure' are always implicit on Exit
419
- const validExitPorts = new Set([
420
- 'onSuccess',
421
- 'onFailure',
422
- ...Object.keys(workflow.exitPorts),
423
- ]);
424
- if (!validExitPorts.has(toPort)) {
425
- const portNames = Array.from(validExitPorts);
426
- const suggestions = findClosestMatches(toPort, portNames);
427
- const suggestion = suggestions.length > 0 ? ` Did you mean "${suggestions[0]}"?` : '';
428
- this.errors.push({
429
- type: 'error',
430
- code: 'UNKNOWN_TARGET_PORT',
431
- message: `Exit node does not have input port "${toPort}"${suggestion}`,
432
- node: toNode,
433
- connection: conn,
434
- location: connLocation,
435
- });
436
- }
437
- }
438
- });
439
- }
440
- /**
441
- * Validate type compatibility for connections with coercion support
442
- *
443
- * Type coercion rules:
444
- * - ANY type connections always allowed (no warning)
445
- * - Safe coercions: NUMBER → STRING, BOOLEAN → STRING (no warning)
446
- * - Lossy coercions: STRING → NUMBER, STRING → BOOLEAN, OBJECT → STRING (warning or error in strict mode)
447
- * - Unusual coercions: NUMBER → BOOLEAN, BOOLEAN → NUMBER (warning or error in strict mode)
448
- * - Same type connections always allowed (no warning)
449
- *
450
- * Strict types mode (@strictTypes):
451
- * - When enabled, type incompatibilities are errors instead of warnings
452
- */
453
- validateTypeCompatibility(workflow, instanceMap) {
454
- const strictTypes = this.strictMode || workflow.options?.strictTypes === true;
455
- // Helper to push to errors or warnings based on strictTypes mode
456
- const pushTypeIssue = (issue, isIncompatible = false) => {
457
- if (strictTypes && isIncompatible) {
458
- this.errors.push({ ...issue, type: 'error', code: 'TYPE_INCOMPATIBLE' });
459
- }
460
- else {
461
- this.warnings.push(issue);
462
- }
463
- };
464
- workflow.connections.forEach((conn) => {
465
- const fromNode = conn.from.node;
466
- const fromPort = conn.from.port;
467
- const toNode = conn.to.node;
468
- const toPort = conn.to.port;
469
- const connLocation = this.getConnectionLocation(conn);
470
- // Skip Start and Exit nodes (they handle types dynamically)
471
- if (isStartNode(fromNode) || isExitNode(toNode)) {
472
- return;
473
- }
474
- // Get source and target port types
475
- const sourceNode = instanceMap.get(fromNode);
476
- const targetNode = instanceMap.get(toNode);
477
- if (!sourceNode || !targetNode) {
478
- return; // Already caught by validateConnections
479
- }
480
- const sourcePortDef = sourceNode.outputs[fromPort];
481
- const targetPortDef = targetNode.inputs[toPort];
482
- if (!sourcePortDef || !targetPortDef) {
483
- return; // Already caught by validateConnections
484
- }
485
- const sourceType = sourcePortDef.dataType;
486
- const targetType = targetPortDef.dataType;
487
- const sourceTsType = sourcePortDef.tsType;
488
- const targetTsType = targetPortDef.tsType;
489
- // Validate STEP port connections - STEP must connect to STEP only
490
- if (sourceType === 'STEP' && targetType !== 'STEP') {
491
- this.errors.push({
492
- type: 'error',
493
- code: 'STEP_PORT_TYPE_MISMATCH',
494
- message: `STEP port "${fromPort}" on node "${fromNode}" cannot connect to non-STEP port "${toPort}" (${this.formatType(targetType, targetTsType)}) on node "${toNode}"`,
495
- connection: conn,
496
- location: connLocation,
497
- });
498
- return;
499
- }
500
- if (targetType === 'STEP' && sourceType !== 'STEP') {
501
- this.errors.push({
502
- type: 'error',
503
- code: 'STEP_PORT_TYPE_MISMATCH',
504
- message: `Non-STEP port "${fromPort}" (${this.formatType(sourceType, sourceTsType)}) on node "${fromNode}" cannot connect to STEP port "${toPort}" on node "${toNode}"`,
505
- connection: conn,
506
- location: connLocation,
507
- });
508
- return;
509
- }
510
- // Skip further type checking for STEP-to-STEP (valid control flow)
511
- if (sourceType === 'STEP' && targetType === 'STEP') {
512
- return;
513
- }
514
- // Block coercion on FUNCTION ports — coercing a function value is nonsensical
515
- if (conn.coerce && (sourceType === 'FUNCTION' || targetType === 'FUNCTION')) {
516
- this.errors.push({
517
- type: 'error',
518
- code: 'COERCE_ON_FUNCTION_PORT',
519
- message: `Coercion \`as ${conn.coerce}\` cannot be used on FUNCTION ports in connection "${fromNode}.${fromPort}" → "${toNode}.${toPort}". FUNCTION values cannot be meaningfully coerced.`,
520
- connection: conn,
521
- location: connLocation,
522
- });
523
- return;
524
- }
525
- // Same type - check for structural compatibility if both are OBJECT
526
- if (sourceType === targetType) {
527
- // Redundant coerce: same types don't need coercion
528
- if (conn.coerce) {
529
- this.warnings.push({
530
- type: 'warning',
531
- code: 'REDUNDANT_COERCE',
532
- message: `Coercion \`as ${conn.coerce}\` on connection "${fromNode}.${fromPort}" → "${toNode}.${toPort}" is redundant — source and target are both ${sourceType}.`,
533
- connection: conn,
534
- location: connLocation,
535
- });
536
- return;
537
- }
538
- // For OBJECT types, check if tsType differs (structural mismatch)
539
- if (sourceType === 'OBJECT' && sourcePortDef.tsType && targetPortDef.tsType) {
540
- const normalizedSource = this.normalizeTypeString(sourcePortDef.tsType);
541
- const normalizedTarget = this.normalizeTypeString(targetPortDef.tsType);
542
- if (normalizedSource !== normalizedTarget) {
543
- // Use string-based compatibility check to suppress false positives (e.g. when one side is 'any')
544
- const compat = checkTypeCompatibilityFromStrings(sourcePortDef.tsType, targetPortDef.tsType);
545
- if (!compat.isCompatible) {
546
- this.warnings.push({
547
- type: 'warning',
548
- code: 'OBJECT_TYPE_MISMATCH',
549
- message: `Structural type mismatch: ${fromNode}.${fromPort} outputs "${sourcePortDef.tsType}" but ${toNode}.${toPort} expects "${targetPortDef.tsType}". Verify the object shapes are compatible.`,
550
- connection: conn,
551
- location: connLocation,
552
- });
553
- }
554
- }
555
- }
556
- return;
557
- }
558
- // ANY type - always compatible (no warning)
559
- if (sourceType === 'ANY' || targetType === 'ANY') {
560
- return;
561
- }
562
- // Validate explicit coerce: check that produced type matches target
563
- if (conn.coerce) {
564
- const producedType = COERCE_OUTPUT_TYPE[conn.coerce];
565
- if (producedType === targetType) {
566
- return; // Coerce correctly resolves the mismatch
567
- }
568
- // Wrong coerce type — produced type doesn't match target
569
- pushTypeIssue({
570
- type: 'warning',
571
- code: 'COERCE_TYPE_MISMATCH',
572
- message: `Coercion \`as ${conn.coerce}\` produces ${producedType} but target port "${toPort}" on "${toNode}" expects ${targetType}. Use \`as ${suggestCoerceType(targetType)}\` instead.`,
573
- connection: conn,
574
- location: connLocation,
575
- }, true);
576
- return;
577
- }
578
- // Safe coercions (no warning)
579
- const safeCoercions = [
580
- ['NUMBER', 'STRING'],
581
- ['BOOLEAN', 'STRING'],
582
- ];
583
- for (const [from, to] of safeCoercions) {
584
- if (sourceType === from && targetType === to) {
585
- return; // Safe coercion, no warning
586
- }
587
- }
588
- // Lossy coercions (warning)
589
- const lossyCoercions = [
590
- ['STRING', 'NUMBER', 'May result in NaN if string is not a valid number'],
591
- ['STRING', 'BOOLEAN', 'Will use JavaScript truthy/falsy conversion'],
592
- ['OBJECT', 'STRING', 'Will use JSON.stringify()'],
593
- ['ARRAY', 'STRING', 'Will use JSON.stringify()'],
594
- ];
595
- for (const [from, to, reason] of lossyCoercions) {
596
- if (sourceType === from && targetType === to) {
597
- pushTypeIssue({
598
- type: 'warning',
599
- code: 'LOSSY_TYPE_COERCION',
600
- message: `Lossy type coercion from ${this.formatType(sourceType, sourceTsType)} to ${this.formatType(targetType, targetTsType)} in connection ${fromNode}.${fromPort} → ${toNode}.${toPort}. ${reason}. Add @strictTypes to your workflow annotation to enforce type safety.`,
601
- connection: conn,
602
- location: connLocation,
603
- }, true);
604
- return;
605
- }
606
- }
607
- // Unusual coercions (warning)
608
- const unusualCoercions = [
609
- [
610
- 'NUMBER',
611
- 'BOOLEAN',
612
- 'Will use JavaScript truthy/falsy conversion (0 = false, non-zero = true)',
613
- ],
614
- ['BOOLEAN', 'NUMBER', 'Will convert false to 0, true to 1'],
615
- ['STRING', 'OBJECT', 'May fail if string is not valid JSON'],
616
- ['STRING', 'ARRAY', 'May fail if string is not valid JSON array'],
617
- ];
618
- for (const [from, to, reason] of unusualCoercions) {
619
- if (sourceType === from && targetType === to) {
620
- pushTypeIssue({
621
- type: 'warning',
622
- code: 'UNUSUAL_TYPE_COERCION',
623
- message: `Unusual type coercion from ${this.formatType(sourceType, sourceTsType)} to ${this.formatType(targetType, targetTsType)} in connection ${fromNode}.${fromPort} → ${toNode}.${toPort}. ${reason}.`,
624
- connection: conn,
625
- location: connLocation,
626
- }, true);
627
- return;
628
- }
629
- }
630
- // All other type mismatches
631
- pushTypeIssue({
632
- type: 'warning',
633
- code: 'TYPE_MISMATCH',
634
- message: `Type mismatch in connection ${fromNode}.${fromPort} (${this.formatType(sourceType, sourceTsType)}) → ${toNode}.${toPort} (${this.formatType(targetType, targetTsType)}). Runtime coercion will be attempted.`,
635
- connection: conn,
636
- location: connLocation,
637
- }, true);
638
- });
639
- }
640
- validateNodeReferences(workflow, instanceMap) {
641
- const referencedNodes = new Set();
642
- workflow.connections.forEach((conn) => {
643
- const fromNode = conn.from.node;
644
- const toNode = conn.to.node;
645
- if (!isStartNode(fromNode) && !isExitNode(fromNode) && !isPseudoNode(fromNode)) {
646
- referencedNodes.add(fromNode);
647
- }
648
- if (!isStartNode(toNode) && !isExitNode(toNode)) {
649
- referencedNodes.add(toNode);
650
- }
651
- });
652
- referencedNodes.forEach((nodeName) => {
653
- if (!instanceMap.has(nodeName)) {
654
- this.errors.push({
655
- type: 'error',
656
- code: 'UNDEFINED_NODE',
657
- message: `Workflow references undefined node: "${nodeName}"`,
658
- node: nodeName,
659
- });
660
- }
661
- });
662
- }
663
- validateRequiredInputs(workflow, instanceMap) {
664
- instanceMap.forEach((nodeType, instanceId) => {
665
- // Find the instance to check for port-level constant expressions
666
- const instance = workflow.instances.find((inst) => inst.id === instanceId);
667
- Object.entries(nodeType.inputs).forEach(([portName, portConfig]) => {
668
- if (isExecutePort(portName))
669
- return;
670
- // Skip scoped INPUT ports - they're provided by scope function execution, not external connections
671
- if (portConfig.scope)
672
- return;
673
- // Check if instance has an expression for this port
674
- const instancePortConfig = instance?.config?.portConfigs?.find((pc) => pc.portName === portName && (pc.direction == null || pc.direction === 'INPUT'));
675
- const hasInstanceExpression = instancePortConfig?.expression !== undefined;
676
- const isRequired = !portConfig.optional &&
677
- portConfig.default === undefined &&
678
- !portConfig.expression &&
679
- !hasInstanceExpression;
680
- if (isRequired) {
681
- const isConnected = workflow.connections.some((conn) => {
682
- return conn.to.node === instanceId && conn.to.port === portName;
683
- });
684
- if (!isConnected) {
685
- this.errors.push({
686
- type: 'error',
687
- code: 'MISSING_REQUIRED_INPUT',
688
- message: `Node "${instanceId}" has unconnected required input port "${portName}". Connect a value to it, or mark it optional with @input [${portName}].`,
689
- node: instanceId,
690
- location: instance?.sourceLocation,
691
- });
692
- }
693
- }
694
- });
695
- });
696
- }
697
- detectUnusedNodes(workflow, instanceMap) {
698
- const usedNodes = new Set();
699
- workflow.connections.forEach((conn) => {
700
- const fromNode = conn.from.node;
701
- const toNode = conn.to.node;
702
- if (!isStartNode(fromNode) && !isExitNode(fromNode)) {
703
- usedNodes.add(fromNode);
704
- }
705
- if (!isStartNode(toNode) && !isExitNode(toNode)) {
706
- usedNodes.add(toNode);
707
- }
708
- });
709
- instanceMap.forEach((_nodeType, instanceId) => {
710
- if (!usedNodes.has(instanceId)) {
711
- this.warnings.push({
712
- type: 'warning',
713
- code: 'UNUSED_NODE',
714
- message: `Node "${instanceId}" is defined but never used in workflow`,
715
- node: instanceId,
716
- location: this.getInstanceLocation(workflow, instanceId),
717
- });
718
- }
719
- });
720
- }
721
- validateStartAndExit(workflow) {
722
- const hasStartConnections = workflow.connections.some((conn) => {
723
- return isStartNode(conn.from.node);
724
- });
725
- if (!hasStartConnections) {
726
- this.warnings.push({
727
- type: 'warning',
728
- code: 'NO_START_CONNECTIONS',
729
- message: 'Workflow has no connections from Start node',
730
- });
731
- }
732
- const hasExitConnections = workflow.connections.some((conn) => {
733
- return isExitNode(conn.to.node);
734
- });
735
- if (!hasExitConnections) {
736
- this.warnings.push({
737
- type: 'warning',
738
- code: 'NO_EXIT_CONNECTIONS',
739
- message: 'Workflow has no connections to Exit node (no return value)',
740
- });
741
- }
742
- // Validate that onSuccess and onFailure exit ports are STEP type
743
- if (workflow.exitPorts.onSuccess) {
744
- if (workflow.exitPorts.onSuccess.dataType !== 'STEP') {
745
- this.errors.push({
746
- type: 'error',
747
- code: 'INVALID_EXIT_PORT_TYPE',
748
- message: "Exit port 'onSuccess' must be of type STEP (control flow), found: " +
749
- workflow.exitPorts.onSuccess.dataType,
750
- });
751
- }
752
- }
753
- if (workflow.exitPorts.onFailure) {
754
- if (workflow.exitPorts.onFailure.dataType !== 'STEP') {
755
- this.errors.push({
756
- type: 'error',
757
- code: 'INVALID_EXIT_PORT_TYPE',
758
- message: "Exit port 'onFailure' must be of type STEP (control flow), found: " +
759
- workflow.exitPorts.onFailure.dataType,
760
- });
761
- }
762
- }
763
- }
764
- /**
765
- * Validate data flow in the workflow
766
- *
767
- * Checks for:
768
- * - Unused output ports (data produced but never consumed)
769
- * - Unreachable Exit ports (Exit expects data but no connection provides it)
770
- * - Dead-end data paths (data that never reaches Exit)
771
- */
772
- validateDataFlow(workflow, instanceMap) {
773
- // Track which output ports are connected
774
- const connectedOutputPorts = new Set();
775
- workflow.connections.forEach((conn) => {
776
- const portKey = `${conn.from.node}.${conn.from.port}`;
777
- connectedOutputPorts.add(portKey);
778
- });
779
- // Check for unused output ports (excluding control flow ports and scoped ports)
780
- instanceMap.forEach((nodeType, instanceId) => {
781
- Object.keys(nodeType.outputs).forEach((portName) => {
782
- const portKey = `${instanceId}.${portName}`;
783
- const portDef = nodeType.outputs[portName];
784
- // Skip control flow ports (onSuccess, onFailure)
785
- if (portDef.isControlFlow || portDef.failure) {
786
- return;
787
- }
788
- // Skip scoped output ports - they flow through the scope function, not external connections
789
- if (portDef.scope) {
790
- return;
791
- }
792
- if (!connectedOutputPorts.has(portKey)) {
793
- this.warnings.push({
794
- type: 'warning',
795
- code: 'UNUSED_OUTPUT_PORT',
796
- message: `Output port "${portName}" of node "${instanceId}" is never connected. Data will be discarded.`,
797
- node: instanceId,
798
- location: this.getInstanceLocation(workflow, instanceId),
799
- });
800
- }
801
- });
802
- });
803
- // Check for unreachable Exit ports and multiple connections to same Exit port
804
- // Build a map of Exit ports to their incoming connections
805
- const exitPortConnections = new Map();
806
- workflow.connections.forEach((conn) => {
807
- if (isExitNode(conn.to.node)) {
808
- const port = conn.to.port;
809
- if (!exitPortConnections.has(port)) {
810
- exitPortConnections.set(port, []);
811
- }
812
- exitPortConnections.get(port).push(conn);
813
- }
814
- });
815
- // Check if all Exit ports have connections
816
- Object.entries(workflow.exitPorts).forEach(([portName, portDef]) => {
817
- // Skip control flow ports
818
- if (portDef.isControlFlow) {
819
- return;
820
- }
821
- if (!exitPortConnections.has(portName)) {
822
- this.warnings.push({
823
- type: 'warning',
824
- code: 'UNREACHABLE_EXIT_PORT',
825
- message: `Exit port "${portName}" has no incoming connection. Return value will be undefined.`,
826
- });
827
- }
828
- });
829
- // Check for multiple connections to the same Exit port
830
- exitPortConnections.forEach((connections, portName) => {
831
- if (connections.length > 1) {
832
- // Skip control flow ports — multiple STEP connections to Exit.onSuccess
833
- // is the standard convergence pattern for parallel terminal nodes
834
- const exitPort = workflow.exitPorts[portName];
835
- if (exitPort?.isControlFlow || exitPort?.dataType === 'STEP') {
836
- return;
837
- }
838
- const sourceNodes = connections.map((c) => c.from.node);
839
- if (this.areMutuallyExclusive(sourceNodes, workflow, instanceMap)) {
840
- return; // Suppress — mutually exclusive branches
841
- }
842
- const sources = connections.map((c) => `${c.from.node}.${c.from.port}`).join(', ');
843
- this.warnings.push({
844
- type: 'warning',
845
- code: 'MULTIPLE_EXIT_CONNECTIONS',
846
- message: `Exit port "${portName}" has ${connections.length} incoming connections (${sources}). Only one value will be used - consider using separate Exit ports.`,
847
- });
848
- }
849
- });
850
- }
851
- /**
852
- * Validate for cycles (loops) in the workflow graph.
853
- * Cycles are connections that form a loop back to an earlier node.
854
- * Scoped nodes handle loops internally, so cycles within same scope are checked.
855
- */
856
- validateCycles(workflow) {
857
- // Group instances by parent (scope layer)
858
- const instancesByParent = new Map();
859
- instancesByParent.set(null, []);
860
- for (const instance of workflow.instances) {
861
- const parentId = instance.parent?.id || null;
862
- if (!instancesByParent.has(parentId)) {
863
- instancesByParent.set(parentId, []);
864
- }
865
- instancesByParent.get(parentId).push(instance);
866
- }
867
- // Group connections by parent (only connections where both ends are in same scope)
868
- const connectionsByParent = new Map();
869
- connectionsByParent.set(null, []);
870
- for (const connection of workflow.connections) {
871
- const sourceInstance = workflow.instances.find((n) => n.id === connection.from.node);
872
- const targetInstance = workflow.instances.find((n) => n.id === connection.to.node);
873
- // Skip connections involving Start/Exit (they're virtual)
874
- if (!sourceInstance || !targetInstance)
875
- continue;
876
- const sourceParent = sourceInstance.parent?.id || null;
877
- const targetParent = targetInstance.parent?.id || null;
878
- // Only check connections within the same scope
879
- if (sourceParent === targetParent) {
880
- if (!connectionsByParent.has(sourceParent)) {
881
- connectionsByParent.set(sourceParent, []);
882
- }
883
- connectionsByParent.get(sourceParent).push(connection);
884
- }
885
- }
886
- // Run cycle detection per scope layer
887
- for (const [parentId, instances] of instancesByParent.entries()) {
888
- const connections = connectionsByParent.get(parentId) || [];
889
- this.detectCyclesInLayer(parentId, instances, connections);
890
- }
891
- }
892
- detectCyclesInLayer(parentId, instances, connections) {
893
- const visited = new Set();
894
- const recursionStack = new Set();
895
- const reportedCycles = new Set(); // Track reported cycles to avoid duplicates
896
- // Self-loops are allowed (used for iteration patterns)
897
- const selfLoopNodes = new Set(connections.filter((c) => c.from.node === c.to.node).map((c) => c.from.node));
898
- // Exclude self-loops from cycle detection
899
- const nonSelfLoopConnections = connections.filter((c) => c.from.node !== c.to.node);
900
- const dfs = (nodeName, path) => {
901
- if (recursionStack.has(nodeName)) {
902
- // Node with self-loop is not considered a cycle entry point
903
- if (selfLoopNodes.has(nodeName)) {
904
- return false;
905
- }
906
- const cycleStart = path.indexOf(nodeName);
907
- const cyclePath = [...path.slice(cycleStart), nodeName];
908
- // Normalize cycle for deduplication (start from smallest node name)
909
- const cycleNodes = cyclePath.slice(0, -1); // Remove duplicate end node
910
- const sortedCycle = [...cycleNodes].sort();
911
- const cycleKey = sortedCycle.join(',');
912
- // Only report if not already reported
913
- if (!reportedCycles.has(cycleKey)) {
914
- reportedCycles.add(cycleKey);
915
- const parentContext = parentId ? ` in scope "${parentId}"` : '';
916
- const instance = instances.find((n) => n.id === nodeName);
917
- this.errors.push({
918
- type: 'error',
919
- code: 'CYCLE_DETECTED',
920
- message: `Loop detected${parentContext}: ${cyclePath.join(' -> ')}`,
921
- node: nodeName,
922
- location: instance?.sourceLocation,
923
- });
924
- }
925
- return true;
926
- }
927
- if (visited.has(nodeName)) {
928
- return false;
929
- }
930
- recursionStack.add(nodeName);
931
- const newPath = [...path, nodeName];
932
- const instance = instances.find((n) => n.id === nodeName);
933
- if (!instance) {
934
- recursionStack.delete(nodeName);
935
- return false;
936
- }
937
- const outgoing = nonSelfLoopConnections.filter((c) => c.from.node === nodeName);
938
- let hasCycle = false;
939
- for (const conn of outgoing) {
940
- if (dfs(conn.to.node, newPath)) {
941
- hasCycle = true;
942
- }
943
- }
944
- recursionStack.delete(nodeName);
945
- if (!hasCycle) {
946
- visited.add(nodeName);
947
- }
948
- return hasCycle;
949
- };
950
- // Run DFS from each node (but use shared visited/reportedCycles sets)
951
- for (const instance of instances) {
952
- if (!visited.has(instance.id)) {
953
- dfs(instance.id, []);
954
- }
955
- }
956
- }
957
- /**
958
- * Validate that no input port has multiple connections.
959
- * Only one value can be received per input port.
960
- * (STEP ports can have multiple connections as they're control flow)
961
- */
962
- validateMultipleInputConnections(workflow, instanceMap) {
963
- const inputConnections = new Map();
964
- for (const conn of workflow.connections) {
965
- const targetKey = `${conn.to.node}.${conn.to.port}`;
966
- // Skip Exit node (handled separately in validateDataFlow)
967
- if (isExitNode(conn.to.node))
968
- continue;
969
- // Get target port type to check if it's STEP or has mergeStrategy
970
- const targetNodeType = instanceMap.get(conn.to.node);
971
- if (targetNodeType) {
972
- const targetPortDef = targetNodeType.inputs[conn.to.port];
973
- // STEP ports can have multiple connections (control flow)
974
- if (targetPortDef?.dataType === 'STEP')
975
- continue;
976
- // Ports with mergeStrategy can have multiple connections (fan-in)
977
- if (targetPortDef?.mergeStrategy)
978
- continue;
979
- }
980
- if (!inputConnections.has(targetKey)) {
981
- inputConnections.set(targetKey, []);
982
- }
983
- inputConnections.get(targetKey).push(conn);
984
- }
985
- for (const [, connections] of inputConnections) {
986
- if (connections.length > 1) {
987
- const [firstConn] = connections;
988
- const sources = connections.map((c) => `${c.from.node}.${c.from.port}`).join(', ');
989
- this.errors.push({
990
- type: 'error',
991
- code: 'MULTIPLE_CONNECTIONS_TO_INPUT',
992
- message: `Input port "${firstConn.to.port}" on node "${firstConn.to.node}" has ${connections.length} connections (${sources}). Only one value can be received.`,
993
- node: firstConn.to.node,
994
- connection: firstConn,
995
- location: this.getConnectionLocation(firstConn),
996
- });
997
- }
998
- }
999
- }
1000
- /**
1001
- * Cross-check @input annotations against TypeScript function signatures.
1002
- * Warns on optionality and type mismatches between annotations and actual code.
1003
- */
1004
- validateAnnotationSignatureConsistency(workflow) {
1005
- for (const nodeType of workflow.nodeTypes) {
1006
- if (!nodeType.functionText)
1007
- continue;
1008
- let sigParams;
1009
- try {
1010
- const sig = parseFunctionSignature(nodeType.functionText);
1011
- sigParams = sig.params;
1012
- }
1013
- catch {
1014
- continue; // Can't parse signature, skip
1015
- }
1016
- // Skip the first param (execute: boolean) - it's a control flow param
1017
- const sigParamMap = new Map();
1018
- for (const p of sigParams.slice(1)) {
1019
- sigParamMap.set(p.name, p);
1020
- }
1021
- for (const [portName, portDef] of Object.entries(nodeType.inputs)) {
1022
- if (portName === 'execute')
1023
- continue; // Skip control flow port
1024
- const sigParam = sigParamMap.get(portName);
1025
- if (!sigParam)
1026
- continue; // Port not in signature (may be added by framework)
1027
- // Check optionality mismatch: annotation says required but sig says optional
1028
- if (!portDef.optional && sigParam.optional) {
1029
- this.warnings.push({
1030
- type: 'warning',
1031
- code: 'ANNOTATION_SIGNATURE_MISMATCH',
1032
- message: `Port "${portName}" in node type "${nodeType.functionName}" is optional in signature but required in annotation. Consider using @input [${portName}] to mark it optional.`,
1033
- node: nodeType.functionName,
1034
- location: nodeType.sourceLocation,
1035
- });
1036
- }
1037
- // Check type mismatch: annotation specifies a type that differs from signature
1038
- if (portDef.tsType && sigParam.tsType) {
1039
- const annotationType = this.normalizeTypeString(portDef.tsType);
1040
- const signatureType = this.normalizeTypeString(sigParam.tsType);
1041
- // Skip if no real type info (untyped JS)
1042
- if (!signatureType || signatureType === 'any')
1043
- continue;
1044
- if (annotationType !== signatureType) {
1045
- this.warnings.push({
1046
- type: 'warning',
1047
- code: 'ANNOTATION_SIGNATURE_TYPE_MISMATCH',
1048
- message: `Port "${portName}" in node type "${nodeType.functionName}" has type "${portDef.tsType}" in annotation but "${sigParam.tsType}" in function signature.`,
1049
- node: nodeType.functionName,
1050
- location: nodeType.sourceLocation,
1051
- });
1052
- }
1053
- }
1054
- }
1055
- }
1056
- }
1057
- /**
1058
- * Check if a set of source nodes are mutually exclusive — i.e., they descend
1059
- * from opposite branches (onSuccess vs onFailure) of the same branching node.
1060
- */
1061
- areMutuallyExclusive(sourceNodes, workflow, instanceMap) {
1062
- if (sourceNodes.length < 2)
1063
- return false;
1064
- // Build reverse connection map: targetNode -> [{fromNode, fromPort}]
1065
- const reverseMap = new Map();
1066
- for (const conn of workflow.connections) {
1067
- if (!reverseMap.has(conn.to.node)) {
1068
- reverseMap.set(conn.to.node, []);
1069
- }
1070
- reverseMap.get(conn.to.node).push({ fromNode: conn.from.node, fromPort: conn.from.port });
1071
- }
1072
- const findBranchAncestor = (nodeId) => {
1073
- const visited = new Set();
1074
- const queue = [nodeId];
1075
- while (queue.length > 0) {
1076
- const current = queue.shift();
1077
- if (visited.has(current))
1078
- continue;
1079
- visited.add(current);
1080
- const incomingEdges = reverseMap.get(current);
1081
- if (!incomingEdges)
1082
- continue;
1083
- for (const edge of incomingEdges) {
1084
- // Check if this incoming edge is from a branching port
1085
- if (edge.fromPort === 'onSuccess' || edge.fromPort === 'onFailure') {
1086
- const parentNodeType = instanceMap.get(edge.fromNode);
1087
- if (parentNodeType?.hasSuccessPort && parentNodeType?.hasFailurePort) {
1088
- return { branchNode: edge.fromNode, branch: edge.fromPort };
1089
- }
1090
- }
1091
- queue.push(edge.fromNode);
1092
- }
1093
- }
1094
- return null;
1095
- };
1096
- // Get branch info for all source nodes
1097
- const branchInfos = sourceNodes.map(findBranchAncestor);
1098
- // All must have a branch ancestor
1099
- if (branchInfos.some((info) => info === null))
1100
- return false;
1101
- // All must share the same branch node
1102
- const branchNode = branchInfos[0].branchNode;
1103
- if (!branchInfos.every((info) => info.branchNode === branchNode))
1104
- return false;
1105
- // They must be on different branches (not all on the same one)
1106
- const branches = new Set(branchInfos.map((info) => info.branch));
1107
- return branches.size > 1;
1108
- }
1109
- /**
1110
- * Validate inner graph topology for nodes that have scoped ports.
1111
- *
1112
- * For each scoped node instance, checks that:
1113
- * 1. Inner nodes (children) have their required inputs connected within the scope
1114
- * 2. Scoped input ports (callback returns) have connections from inner nodes
1115
- */
1116
- validateScopeTopology(workflow, instanceMap) {
1117
- // P: Scope consistency - check if any instance appears in multiple scope arrays
1118
- if (workflow.scopes) {
1119
- const instanceToScope = new Map();
1120
- for (const [scopeKey, childIds] of Object.entries(workflow.scopes)) {
1121
- for (const childId of childIds) {
1122
- const existing = instanceToScope.get(childId);
1123
- if (existing && existing !== scopeKey) {
1124
- this.errors.push({
1125
- type: 'error',
1126
- code: 'SCOPE_INCONSISTENT',
1127
- message: `Instance "${childId}" appears in multiple scopes: "${existing}" and "${scopeKey}". A node can only belong to one scope.`,
1128
- node: childId,
1129
- location: this.getInstanceLocation(workflow, childId),
1130
- });
1131
- }
1132
- instanceToScope.set(childId, scopeKey);
1133
- }
1134
- }
1135
- }
1136
- // Find all instances that have scoped ports
1137
- for (const instance of workflow.instances) {
1138
- const nodeType = instanceMap.get(instance.id);
1139
- if (!nodeType)
1140
- continue;
1141
- // Collect scoped port pairs per scope name
1142
- const scopeNames = new Set();
1143
- for (const portDef of Object.values(nodeType.outputs)) {
1144
- if (portDef.scope)
1145
- scopeNames.add(portDef.scope);
1146
- }
1147
- for (const portDef of Object.values(nodeType.inputs)) {
1148
- if (portDef.scope)
1149
- scopeNames.add(portDef.scope);
1150
- }
1151
- if (scopeNames.size === 0)
1152
- continue;
1153
- // Check: connections with scope qualifiers must reference valid scope names on this instance
1154
- for (const conn of workflow.connections) {
1155
- if (conn.from.scope && conn.from.node === instance.id) {
1156
- if (!scopeNames.has(conn.from.scope)) {
1157
- this.errors.push({
1158
- type: 'error',
1159
- code: 'SCOPE_WRONG_SCOPE_NAME',
1160
- message: `Connection from "${instance.id}.${conn.from.port}" uses scope qualifier ":${conn.from.scope}" but node "${instance.id}" does not define scope "${conn.from.scope}". Available scopes: ${[...scopeNames].join(', ')}.`,
1161
- connection: conn,
1162
- location: this.getConnectionLocation(conn),
1163
- });
1164
- }
1165
- }
1166
- if (conn.to.scope && conn.to.node === instance.id) {
1167
- if (!scopeNames.has(conn.to.scope)) {
1168
- this.errors.push({
1169
- type: 'error',
1170
- code: 'SCOPE_WRONG_SCOPE_NAME',
1171
- message: `Connection to "${instance.id}.${conn.to.port}" uses scope qualifier ":${conn.to.scope}" but node "${instance.id}" does not define scope "${conn.to.scope}". Available scopes: ${[...scopeNames].join(', ')}.`,
1172
- connection: conn,
1173
- location: this.getConnectionLocation(conn),
1174
- });
1175
- }
1176
- }
1177
- }
1178
- for (const scopeName of scopeNames) {
1179
- // Find children in this scope
1180
- const childIds = [];
1181
- for (const child of workflow.instances) {
1182
- if (child.parent &&
1183
- child.parent.id === instance.id &&
1184
- child.parent.scope === scopeName) {
1185
- childIds.push(child.id);
1186
- }
1187
- }
1188
- // O: Empty scope warning
1189
- if (childIds.length === 0) {
1190
- this.warnings.push({
1191
- type: 'warning',
1192
- code: 'SCOPE_EMPTY',
1193
- message: `Scope "${scopeName}" on node "${instance.id}" has no child nodes.`,
1194
- node: instance.id,
1195
- location: this.getInstanceLocation(workflow, instance.id),
1196
- });
1197
- continue;
1198
- }
1199
- // Collect scoped connections (connections with scope tags)
1200
- const scopedConnections = workflow.connections.filter((conn) => (conn.from.scope === scopeName && conn.from.node === instance.id) ||
1201
- (conn.to.scope === scopeName && conn.to.node === instance.id) ||
1202
- (conn.from.scope === scopeName && childIds.includes(conn.from.node)) ||
1203
- (conn.to.scope === scopeName && childIds.includes(conn.to.node)));
1204
- // Check: scoped connections reference actual scoped ports on the parent
1205
- for (const conn of scopedConnections) {
1206
- if (conn.from.node === instance.id && conn.from.scope === scopeName) {
1207
- const portDef = nodeType.outputs[conn.from.port];
1208
- if (!portDef) {
1209
- const availablePorts = Object.entries(nodeType.outputs)
1210
- .filter(([, p]) => p.scope === scopeName)
1211
- .map(([n]) => n);
1212
- this.errors.push({
1213
- type: 'error',
1214
- code: 'SCOPE_UNKNOWN_PORT',
1215
- message: `Scoped connection references non-existent output port "${conn.from.port}" on "${instance.id}" in scope "${scopeName}". Available scoped outputs: ${availablePorts.join(', ') || 'none'}.`,
1216
- connection: conn,
1217
- location: this.getConnectionLocation(conn),
1218
- });
1219
- }
1220
- else if (portDef.scope !== scopeName) {
1221
- this.errors.push({
1222
- type: 'error',
1223
- code: 'SCOPE_UNKNOWN_PORT',
1224
- message: `Output port "${conn.from.port}" on "${instance.id}" is not a scoped port of scope "${scopeName}"${portDef.scope ? ` (it belongs to scope "${portDef.scope}")` : ' (it is an unscoped port)'}.`,
1225
- connection: conn,
1226
- location: this.getConnectionLocation(conn),
1227
- });
1228
- }
1229
- }
1230
- if (conn.to.node === instance.id && conn.to.scope === scopeName) {
1231
- const portDef = nodeType.inputs[conn.to.port];
1232
- if (!portDef) {
1233
- const availablePorts = Object.entries(nodeType.inputs)
1234
- .filter(([, p]) => p.scope === scopeName)
1235
- .map(([n]) => n);
1236
- this.errors.push({
1237
- type: 'error',
1238
- code: 'SCOPE_UNKNOWN_PORT',
1239
- message: `Scoped connection references non-existent input port "${conn.to.port}" on "${instance.id}" in scope "${scopeName}". Available scoped inputs: ${availablePorts.join(', ') || 'none'}.`,
1240
- connection: conn,
1241
- location: this.getConnectionLocation(conn),
1242
- });
1243
- }
1244
- else if (portDef.scope !== scopeName) {
1245
- this.errors.push({
1246
- type: 'error',
1247
- code: 'SCOPE_UNKNOWN_PORT',
1248
- message: `Input port "${conn.to.port}" on "${instance.id}" is not a scoped port of scope "${scopeName}"${portDef.scope ? ` (it belongs to scope "${portDef.scope}")` : ' (it is an unscoped port)'}.`,
1249
- connection: conn,
1250
- location: this.getConnectionLocation(conn),
1251
- });
1252
- }
1253
- }
1254
- }
1255
- // Check: scoped connections must stay within the scope boundary
1256
- for (const conn of scopedConnections) {
1257
- if (conn.from.scope === scopeName && childIds.includes(conn.from.node)) {
1258
- if (conn.to.node !== instance.id && !childIds.includes(conn.to.node)) {
1259
- this.errors.push({
1260
- type: 'error',
1261
- code: 'SCOPE_CONNECTION_OUTSIDE',
1262
- message: `Scoped connection from "${conn.from.node}.${conn.from.port}" targets "${conn.to.node}" which is not inside scope "${scopeName}" of "${instance.id}".`,
1263
- connection: conn,
1264
- location: this.getConnectionLocation(conn),
1265
- });
1266
- }
1267
- }
1268
- if (conn.to.scope === scopeName && childIds.includes(conn.to.node)) {
1269
- if (conn.from.node !== instance.id && !childIds.includes(conn.from.node)) {
1270
- this.errors.push({
1271
- type: 'error',
1272
- code: 'SCOPE_CONNECTION_OUTSIDE',
1273
- message: `Scoped connection to "${conn.to.node}.${conn.to.port}" sources from "${conn.from.node}" which is not inside scope "${scopeName}" of "${instance.id}".`,
1274
- connection: conn,
1275
- location: this.getConnectionLocation(conn),
1276
- });
1277
- }
1278
- }
1279
- }
1280
- // Check: type compatibility for scoped connections between parent and children
1281
- for (const conn of scopedConnections) {
1282
- // Parent scoped output -> child input
1283
- if (conn.from.node === instance.id && conn.from.scope === scopeName) {
1284
- const parentPort = nodeType.outputs[conn.from.port];
1285
- const childType = instanceMap.get(conn.to.node);
1286
- const childPort = childType?.inputs[conn.to.port];
1287
- if (parentPort && childPort && parentPort.dataType !== 'STEP' && childPort.dataType !== 'STEP') {
1288
- if (parentPort.dataType !== childPort.dataType && parentPort.dataType !== 'ANY' && childPort.dataType !== 'ANY') {
1289
- this.warnings.push({
1290
- type: 'warning',
1291
- code: 'SCOPE_PORT_TYPE_MISMATCH',
1292
- message: `Type mismatch in scope "${scopeName}": "${instance.id}.${conn.from.port}" outputs ${this.formatType(parentPort.dataType, parentPort.tsType)} but "${conn.to.node}.${conn.to.port}" expects ${this.formatType(childPort.dataType, childPort.tsType)}.`,
1293
- connection: conn,
1294
- location: this.getConnectionLocation(conn),
1295
- });
1296
- }
1297
- }
1298
- }
1299
- // Child output -> parent scoped input
1300
- if (conn.to.node === instance.id && conn.to.scope === scopeName) {
1301
- const parentPort = nodeType.inputs[conn.to.port];
1302
- const childType = instanceMap.get(conn.from.node);
1303
- const childPort = childType?.outputs[conn.from.port];
1304
- if (parentPort && childPort && parentPort.dataType !== 'STEP' && childPort.dataType !== 'STEP') {
1305
- if (parentPort.dataType !== childPort.dataType && parentPort.dataType !== 'ANY' && childPort.dataType !== 'ANY') {
1306
- this.warnings.push({
1307
- type: 'warning',
1308
- code: 'SCOPE_PORT_TYPE_MISMATCH',
1309
- message: `Type mismatch in scope "${scopeName}": "${conn.from.node}.${conn.from.port}" outputs ${this.formatType(childPort.dataType, childPort.tsType)} but "${instance.id}.${conn.to.port}" expects ${this.formatType(parentPort.dataType, parentPort.tsType)}.`,
1310
- connection: conn,
1311
- location: this.getConnectionLocation(conn),
1312
- });
1313
- }
1314
- }
1315
- }
1316
- }
1317
- // Check: each child's required inputs must be satisfied within the scope
1318
- for (const childId of childIds) {
1319
- const childType = instanceMap.get(childId);
1320
- if (!childType)
1321
- continue;
1322
- for (const [portName, portConfig] of Object.entries(childType.inputs)) {
1323
- if (isExecutePort(portName))
1324
- continue;
1325
- if (portConfig.scope)
1326
- continue; // Skip scoped ports on children
1327
- if (portConfig.optional || portConfig.default !== undefined)
1328
- continue;
1329
- // Check instance expression overrides
1330
- const childInstance = workflow.instances.find((i) => i.id === childId);
1331
- const instancePortConfig = childInstance?.config?.portConfigs?.find((pc) => pc.portName === portName && (pc.direction == null || pc.direction === 'INPUT'));
1332
- if (portConfig.expression || instancePortConfig?.expression !== undefined)
1333
- continue;
1334
- // Check if connected by any connection (scoped, inter-child, or outer)
1335
- const isConnected = workflow.connections.some((conn) => conn.to.node === childId && conn.to.port === portName);
1336
- if (!isConnected) {
1337
- this.errors.push({
1338
- type: 'error',
1339
- code: 'SCOPE_MISSING_REQUIRED_INPUT',
1340
- message: `Scoped child "${childId}" has unconnected required input "${portName}" within scope "${scopeName}" of "${instance.id}".`,
1341
- node: childId,
1342
- location: childInstance?.sourceLocation,
1343
- });
1344
- }
1345
- }
1346
- }
1347
- // Check: scoped INPUT ports should have connections from inner nodes
1348
- const scopedInputPorts = Object.entries(nodeType.inputs).filter(([_, portDef]) => portDef.scope === scopeName);
1349
- for (const [portName] of scopedInputPorts) {
1350
- const hasConnection = scopedConnections.some((conn) => conn.to.node === instance.id &&
1351
- conn.to.port === portName &&
1352
- conn.to.scope === scopeName);
1353
- if (!hasConnection) {
1354
- this.warnings.push({
1355
- type: 'warning',
1356
- code: 'SCOPE_UNUSED_INPUT',
1357
- message: `Scoped input port "${portName}" of "${instance.id}" (scope "${scopeName}") has no connection from inner nodes. Data will not flow back from the scope.`,
1358
- node: instance.id,
1359
- location: this.getInstanceLocation(workflow, instance.id),
1360
- });
1361
- }
1362
- }
1363
- // Check: each child should have at least one scoped connection to/from the parent
1364
- for (const childId of childIds) {
1365
- const hasConnectionFromParent = scopedConnections.some((conn) => conn.from.node === instance.id &&
1366
- conn.from.scope === scopeName &&
1367
- conn.to.node === childId);
1368
- const hasConnectionToParent = scopedConnections.some((conn) => conn.to.node === instance.id &&
1369
- conn.to.scope === scopeName &&
1370
- conn.from.node === childId);
1371
- if (!hasConnectionFromParent && !hasConnectionToParent) {
1372
- this.warnings.push({
1373
- type: 'warning',
1374
- code: 'SCOPE_ORPHANED_CHILD',
1375
- message: `Child node "${childId}" is declared inside scope "${scopeName}" of "${instance.id}" but has no scoped connections to or from the parent. It is disconnected from the scope's data flow.`,
1376
- node: childId,
1377
- location: this.getInstanceLocation(workflow, childId),
1378
- });
1379
- }
1380
- }
1381
- }
1382
- }
1383
- // Check: non-scoped connections must not cross scope boundaries
1384
- // when the parent is a scoped node type (has scoped ports).
1385
- // A child in scope "a" cannot connect to a child in scope "b" (or root),
1386
- // because they execute in separate callback contexts.
1387
- // Only applies to per-port scoped parents (not flat grouping scopes).
1388
- const parentOf = new Map();
1389
- for (const inst of workflow.instances) {
1390
- parentOf.set(inst.id, inst.parent ?? undefined);
1391
- }
1392
- // Build set of node IDs that are scoped parent types (have scoped ports)
1393
- const scopedParentIds = new Set();
1394
- for (const inst of workflow.instances) {
1395
- const nt = instanceMap.get(inst.id);
1396
- if (!nt)
1397
- continue;
1398
- const hasScopedPorts = [
1399
- ...Object.values(nt.inputs ?? {}),
1400
- ...Object.values(nt.outputs ?? {}),
1401
- ].some((p) => p.scope);
1402
- if (hasScopedPorts)
1403
- scopedParentIds.add(inst.id);
1404
- }
1405
- for (const conn of workflow.connections) {
1406
- // Skip scoped connections (already validated above)
1407
- if (conn.from.scope || conn.to.scope)
1408
- continue;
1409
- const fromParent = parentOf.get(conn.from.node);
1410
- const toParent = parentOf.get(conn.to.node);
1411
- // Both must exist in the workflow
1412
- if (!parentOf.has(conn.from.node) || !parentOf.has(conn.to.node))
1413
- continue;
1414
- // If neither node is inside a scope, skip (root-to-root is fine)
1415
- if (!fromParent && !toParent)
1416
- continue;
1417
- // Only validate when the parent is a scoped node type (has scoped ports).
1418
- // Flat grouping scopes (createScope without scoped ports) are allowed to cross.
1419
- const fromInScopedParent = fromParent && scopedParentIds.has(fromParent.id);
1420
- const toInScopedParent = toParent && scopedParentIds.has(toParent.id);
1421
- if (!fromInScopedParent && !toInScopedParent)
1422
- continue;
1423
- // Allow connections where one side is the scoped PARENT itself (not a child)
1424
- const fromIsParentOfTo = toParent && toParent.id === conn.from.node;
1425
- const toIsParentOfFrom = fromParent && fromParent.id === conn.to.node;
1426
- if (fromIsParentOfTo || toIsParentOfFrom)
1427
- continue;
1428
- // Check if they share the same parent+scope
1429
- const sameScope = fromParent && toParent &&
1430
- fromParent.id === toParent.id &&
1431
- fromParent.scope === toParent.scope;
1432
- if (!sameScope) {
1433
- const fromCtx = fromParent ? `${fromParent.id}.${fromParent.scope}` : 'root';
1434
- const toCtx = toParent ? `${toParent.id}.${toParent.scope}` : 'root';
1435
- this.errors.push({
1436
- type: 'error',
1437
- code: 'CROSS_SCOPE_CONNECTION',
1438
- message: `Connection from "${conn.from.node}.${conn.from.port}" (in ${fromCtx}) to "${conn.to.node}.${conn.to.port}" (in ${toCtx}) crosses scope boundaries. Nodes in different scopes cannot connect directly.`,
1439
- connection: conn,
1440
- location: this.getConnectionLocation(conn),
1441
- });
1442
- }
1443
- }
1444
- }
1445
- // ── H: Duplicate instance IDs ──────────────────────────────────────────
1446
- validateDuplicateInstanceIds(workflow) {
1447
- const seen = new Set();
1448
- for (const instance of workflow.instances) {
1449
- if (seen.has(instance.id)) {
1450
- this.errors.push({
1451
- type: 'error',
1452
- code: 'DUPLICATE_INSTANCE_ID',
1453
- message: `Duplicate instance ID "${instance.id}" in workflow. Each @node must have a unique ID.`,
1454
- node: instance.id,
1455
- location: instance.sourceLocation,
1456
- });
1457
- }
1458
- seen.add(instance.id);
1459
- }
1460
- }
1461
- // ── I: Duplicate connections ──────────────────────────────────────────
1462
- validateDuplicateConnections(workflow) {
1463
- const seen = new Set();
1464
- for (const conn of workflow.connections) {
1465
- const key = `${conn.from.node}.${conn.from.port}->${conn.to.node}.${conn.to.port}`;
1466
- if (seen.has(key)) {
1467
- this.errors.push({
1468
- type: 'error',
1469
- code: 'DUPLICATE_CONNECTION',
1470
- message: `Duplicate connection: ${key}`,
1471
- connection: conn,
1472
- location: this.getConnectionLocation(conn),
1473
- });
1474
- }
1475
- seen.add(key);
1476
- }
1477
- }
1478
- // ── J+K: Visual annotation validation ────────────────────────────────
1479
- validateVisualAnnotations(workflow, instanceMap) {
1480
- const validColors = VALID_NODE_COLORS;
1481
- const validIcons = VALID_NODE_ICONS;
1482
- // Check node type colors and icons (stored in visuals)
1483
- for (const nodeType of workflow.nodeTypes) {
1484
- const color = nodeType.visuals?.color;
1485
- const icon = nodeType.visuals?.icon;
1486
- if (color && !validColors.includes(color)) {
1487
- const suggestions = findClosestMatches(color, [...validColors]);
1488
- const hint = suggestions.length > 0 ? ` Did you mean "${suggestions[0]}"?` : '';
1489
- this.warnings.push({
1490
- type: 'warning',
1491
- code: 'INVALID_COLOR',
1492
- message: `Node type "${nodeType.functionName}" has invalid color "${color}".${hint} Valid colors: ${validColors.join(', ')}.`,
1493
- node: nodeType.functionName,
1494
- location: nodeType.sourceLocation,
1495
- });
1496
- }
1497
- if (icon && !validIcons.includes(icon)) {
1498
- const suggestions = findClosestMatches(icon, [...validIcons]);
1499
- const hint = suggestions.length > 0 ? ` Did you mean "${suggestions[0]}"?` : '';
1500
- this.warnings.push({
1501
- type: 'warning',
1502
- code: 'INVALID_ICON',
1503
- message: `Node type "${nodeType.functionName}" has invalid icon "${icon}".${hint}`,
1504
- node: nodeType.functionName,
1505
- location: nodeType.sourceLocation,
1506
- });
1507
- }
1508
- }
1509
- // Check instance-level color and icon overrides
1510
- for (const instance of workflow.instances) {
1511
- if (instance.config?.color && !validColors.includes(instance.config.color)) {
1512
- const suggestions = findClosestMatches(instance.config.color, [...validColors]);
1513
- const hint = suggestions.length > 0 ? ` Did you mean "${suggestions[0]}"?` : '';
1514
- this.warnings.push({
1515
- type: 'warning',
1516
- code: 'INVALID_COLOR',
1517
- message: `Instance "${instance.id}" has invalid color "${instance.config.color}".${hint} Valid colors: ${validColors.join(', ')}.`,
1518
- node: instance.id,
1519
- location: instance.sourceLocation,
1520
- });
1521
- }
1522
- if (instance.config?.icon && !validIcons.includes(instance.config.icon)) {
1523
- const suggestions = findClosestMatches(instance.config.icon, [...validIcons]);
1524
- const hint = suggestions.length > 0 ? ` Did you mean "${suggestions[0]}"?` : '';
1525
- this.warnings.push({
1526
- type: 'warning',
1527
- code: 'INVALID_ICON',
1528
- message: `Instance "${instance.id}" has invalid icon "${instance.config.icon}".${hint}`,
1529
- node: instance.id,
1530
- location: instance.sourceLocation,
1531
- });
1532
- }
1533
- }
1534
- }
1535
- // ── L: Port type validation ──────────────────────────────────────────
1536
- validatePortTypes(workflow) {
1537
- for (const nodeType of workflow.nodeTypes) {
1538
- for (const [portName, portDef] of Object.entries(nodeType.inputs)) {
1539
- if (!isValidPortType(portDef.dataType)) {
1540
- this.warnings.push({
1541
- type: 'warning',
1542
- code: 'INVALID_PORT_TYPE',
1543
- message: `Port "${portName}" on node type "${nodeType.functionName}" has invalid type "${portDef.dataType}".`,
1544
- node: nodeType.functionName,
1545
- location: nodeType.sourceLocation,
1546
- });
1547
- }
1548
- }
1549
- for (const [portName, portDef] of Object.entries(nodeType.outputs)) {
1550
- if (!isValidPortType(portDef.dataType)) {
1551
- this.warnings.push({
1552
- type: 'warning',
1553
- code: 'INVALID_PORT_TYPE',
1554
- message: `Port "${portName}" on node type "${nodeType.functionName}" has invalid type "${portDef.dataType}".`,
1555
- node: nodeType.functionName,
1556
- location: nodeType.sourceLocation,
1557
- });
1558
- }
1559
- }
1560
- }
1561
- }
1562
- // ── M: portOrder/portLabel reference validation ──────────────────────
1563
- validatePortConfigReferences(workflow, instanceMap) {
1564
- for (const instance of workflow.instances) {
1565
- const portConfigs = instance.config?.portConfigs;
1566
- if (!portConfigs)
1567
- continue;
1568
- const nodeType = instanceMap.get(instance.id);
1569
- if (!nodeType)
1570
- continue;
1571
- const allPorts = new Set([
1572
- ...Object.keys(nodeType.inputs),
1573
- ...Object.keys(nodeType.outputs),
1574
- ]);
1575
- for (const pc of portConfigs) {
1576
- if (!allPorts.has(pc.portName)) {
1577
- const suggestions = findClosestMatches(pc.portName, [...allPorts]);
1578
- const hint = suggestions.length > 0 ? ` Did you mean "${suggestions[0]}"?` : '';
1579
- this.warnings.push({
1580
- type: 'warning',
1581
- code: 'INVALID_PORT_CONFIG_REF',
1582
- message: `Instance "${instance.id}" references port "${pc.portName}" in portConfig, but this port does not exist on node type "${instance.nodeType}".${hint}`,
1583
- node: instance.id,
1584
- location: instance.sourceLocation,
1585
- });
1586
- }
1587
- }
1588
- }
1589
- }
1590
- // ── N: @executeWhen value validation ─────────────────────────────────
1591
- validateExecuteWhen(workflow) {
1592
- const validStrategies = Object.values(EXECUTION_STRATEGIES);
1593
- for (const nodeType of workflow.nodeTypes) {
1594
- if (nodeType.executeWhen && !validStrategies.includes(nodeType.executeWhen)) {
1595
- const suggestions = findClosestMatches(nodeType.executeWhen, validStrategies);
1596
- const hint = suggestions.length > 0 ? ` Did you mean "${suggestions[0]}"?` : '';
1597
- this.warnings.push({
1598
- type: 'warning',
1599
- code: 'INVALID_EXECUTE_WHEN',
1600
- message: `Node type "${nodeType.functionName}" has invalid @executeWhen value "${nodeType.executeWhen}".${hint} Valid values: ${validStrategies.join(', ')}.`,
1601
- node: nodeType.functionName,
1602
- location: nodeType.sourceLocation,
1603
- });
1604
- }
1605
- }
1606
- }
1607
- /**
1608
- * Format a type for display in error messages.
1609
- * Prefers the structural TypeScript type when available, falling back to the enum name.
1610
- */
1611
- formatType(dataType, tsType) {
1612
- if (tsType) {
1613
- return `${tsType} (${dataType})`;
1614
- }
1615
- return dataType;
1616
- }
1617
- normalizeTypeString(type) {
1618
- let n = type;
1619
- // Remove all whitespace
1620
- n = n.replace(/\s+/g, '');
1621
- // Normalize Array<T> → T[]
1622
- n = n.replace(/Array<(.+?)>/g, '$1[]');
1623
- // Remove trailing semicolons before closing braces/brackets
1624
- n = n.replace(/;(?=[}\]])/g, '');
1625
- // Lowercase for case-insensitive compare
1626
- n = n.toLowerCase();
1627
- return n;
1628
- }
1629
- }
1630
- export const validator = new WorkflowValidator();
1631
- //# sourceMappingURL=validator.js.map