@synergenius/flow-weaver 0.33.1 → 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 -244
  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 -89498
  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 +22 -29
  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 +15 -51
  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 +3 -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 -1267
  781. package/dist/diagram/html-viewer.d.ts +0 -21
  782. package/dist/diagram/html-viewer.js +0 -1689
  783. package/dist/diagram/layout.js +0 -143
  784. package/dist/diagram/orthogonal-router.js +0 -568
  785. package/dist/diagram/renderer.d.ts +0 -3
  786. package/dist/diagram/renderer.js +0 -266
  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
@@ -0,0 +1,4256 @@
1
+ import {
2
+ COERCE_TYPE_MAP,
3
+ COERCION_NODE_TYPES,
4
+ collectModuleBindings,
5
+ expandExpressionReferences
6
+ } from "./chunk-4KDUEOFD.js";
7
+ import {
8
+ getErrorMessage
9
+ } from "./chunk-DUO6H5PR.js";
10
+ import {
11
+ assignImplicitPortOrders,
12
+ generateJSDocPortTag,
13
+ impliedPathDataEdgesInto,
14
+ tagHandlerRegistry
15
+ } from "./chunk-VP2P3BPA.js";
16
+ import {
17
+ extractFunctionLikes,
18
+ getPackageExports,
19
+ getSharedProject,
20
+ nestedAnnotationWarnings,
21
+ resolvePackageTypesPath
22
+ } from "./chunk-B6HQ6YS5.js";
23
+ import {
24
+ inferDataTypeFromTS,
25
+ isValidPortType,
26
+ stripOptionalUndefined
27
+ } from "./chunk-E5WN7IGO.js";
28
+ import {
29
+ parseCancelOnLine,
30
+ parseCoerceLine,
31
+ parseConnectLine,
32
+ parseFanInLine,
33
+ parseFanOutLine,
34
+ parseMapLine,
35
+ parseNodeLine,
36
+ parsePathLine,
37
+ parseRetriesLine,
38
+ parseScopeLine,
39
+ parseThrottleLine,
40
+ parseTimeoutLine,
41
+ parseTriggerLine
42
+ } from "./chunk-KMWCCOUJ.js";
43
+ import {
44
+ parsePortLine
45
+ } from "./chunk-QYPORSLO.js";
46
+ import {
47
+ EXECUTION_STRATEGIES,
48
+ KNOWN_NODETYPE_TAGS,
49
+ RESERVED_PORT_NAMES,
50
+ STANDARD_JSDOC_TAGS,
51
+ getKnownWorkflowTags,
52
+ isControlFlowPort,
53
+ isExecutePort,
54
+ isFailurePort,
55
+ isScopedMandatoryPort,
56
+ isSuccessPort
57
+ } from "./chunk-R4QGNK34.js";
58
+
59
+ // src/parser/generated-sections.ts
60
+ var MARKERS = {
61
+ RUNTIME_START: "// @flow-weaver-runtime-start",
62
+ RUNTIME_END: "// @flow-weaver-runtime-end",
63
+ BODY_START: "// @flow-weaver-body-start",
64
+ BODY_END: "// @flow-weaver-body-end",
65
+ IMPORTS_START: "// @flow-weaver-imports-start",
66
+ IMPORTS_END: "// @flow-weaver-imports-end"
67
+ };
68
+ function hasInPlaceMarkers(source) {
69
+ return source.includes(MARKERS.RUNTIME_START) && source.includes(MARKERS.RUNTIME_END) && source.includes(MARKERS.BODY_START) && source.includes(MARKERS.BODY_END);
70
+ }
71
+ function stripGeneratedSections(source) {
72
+ let result = source;
73
+ const runtimeStartIdx = result.indexOf(MARKERS.RUNTIME_START);
74
+ const runtimeEndIdx = result.indexOf(MARKERS.RUNTIME_END);
75
+ if (runtimeStartIdx !== -1 && runtimeEndIdx !== -1) {
76
+ const lineStart = result.lastIndexOf("\n", runtimeStartIdx);
77
+ const lineEnd = result.indexOf("\n", runtimeEndIdx + MARKERS.RUNTIME_END.length);
78
+ result = result.slice(0, lineStart === -1 ? 0 : lineStart) + result.slice(lineEnd === -1 ? result.length : lineEnd);
79
+ }
80
+ while (true) {
81
+ const bodyStartIdx = result.indexOf(MARKERS.BODY_START);
82
+ const bodyEndIdx = result.indexOf(MARKERS.BODY_END);
83
+ if (bodyStartIdx === -1 || bodyEndIdx === -1 || bodyEndIdx < bodyStartIdx) break;
84
+ const before = result.slice(0, bodyStartIdx);
85
+ const after = result.slice(bodyEndIdx + MARKERS.BODY_END.length);
86
+ result = before + `throw new Error('Not implemented');` + after;
87
+ }
88
+ return result;
89
+ }
90
+
91
+ // src/parser/npm-node-types.ts
92
+ function resolveNpmNodeTypes(ast, workdir) {
93
+ if (!ast.nodeTypes || ast.nodeTypes.length === 0) {
94
+ return ast;
95
+ }
96
+ const resolvedNodeTypes = ast.nodeTypes.map((nodeType) => {
97
+ if (!nodeType.importSource) {
98
+ return nodeType;
99
+ }
100
+ const packageExports = getPackageExports(nodeType.importSource, workdir);
101
+ const matchingExport = packageExports.find(
102
+ (exp) => exp.name === nodeType.name || exp.function === nodeType.functionName
103
+ );
104
+ if (!matchingExport) {
105
+ return nodeType;
106
+ }
107
+ const inputs = {};
108
+ const outputs = {};
109
+ for (const port of matchingExport.ports) {
110
+ if (port.direction === "INPUT") {
111
+ inputs[port.name] = {
112
+ dataType: port.type,
113
+ label: port.defaultLabel
114
+ };
115
+ } else if (port.direction === "OUTPUT") {
116
+ outputs[port.name] = {
117
+ dataType: port.type,
118
+ label: port.defaultLabel
119
+ };
120
+ }
121
+ }
122
+ return {
123
+ ...nodeType,
124
+ inputs,
125
+ outputs,
126
+ isAsync: matchingExport.synchronicity === "ASYNC"
127
+ };
128
+ });
129
+ return {
130
+ ...ast,
131
+ nodeTypes: resolvedNodeTypes
132
+ };
133
+ }
134
+
135
+ // src/parser/annotation-parser.ts
136
+ import { createHash } from "node:crypto";
137
+ import * as fs3 from "node:fs";
138
+
139
+ // src/utils/lru-cache.ts
140
+ var LRUCache = class {
141
+ map = /* @__PURE__ */ new Map();
142
+ maxSize;
143
+ constructor(maxSize) {
144
+ this.maxSize = maxSize;
145
+ }
146
+ get(key) {
147
+ const value = this.map.get(key);
148
+ if (value !== void 0) {
149
+ this.map.delete(key);
150
+ this.map.set(key, value);
151
+ }
152
+ return value;
153
+ }
154
+ has(key) {
155
+ return this.map.has(key);
156
+ }
157
+ set(key, value) {
158
+ if (this.map.has(key)) {
159
+ this.map.delete(key);
160
+ }
161
+ this.map.set(key, value);
162
+ while (this.map.size > this.maxSize) {
163
+ const firstKey = this.map.keys().next().value;
164
+ this.map.delete(firstKey);
165
+ }
166
+ }
167
+ clear() {
168
+ this.map.clear();
169
+ }
170
+ get size() {
171
+ return this.map.size;
172
+ }
173
+ };
174
+
175
+ // src/utils/string-distance.ts
176
+ function levenshteinDistance(a, b) {
177
+ const la = a.length;
178
+ const lb = b.length;
179
+ if (la === 0) return lb;
180
+ if (lb === 0) return la;
181
+ let prev = Array.from({ length: lb + 1 }, (_, i) => i);
182
+ let curr = new Array(lb + 1);
183
+ for (let i = 1; i <= la; i++) {
184
+ curr[0] = i;
185
+ for (let j = 1; j <= lb; j++) {
186
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
187
+ curr[j] = Math.min(
188
+ curr[j - 1] + 1,
189
+ // insertion
190
+ prev[j] + 1,
191
+ // deletion
192
+ prev[j - 1] + cost
193
+ // substitution
194
+ );
195
+ }
196
+ [prev, curr] = [curr, prev];
197
+ }
198
+ return prev[lb];
199
+ }
200
+ function adaptiveMaxDistance(target) {
201
+ const len = target.length;
202
+ if (len <= 3) return 1;
203
+ if (len <= 6) return 2;
204
+ return 3;
205
+ }
206
+ function findClosestMatches(target, candidates, maxDistance) {
207
+ const effectiveMax = maxDistance ?? adaptiveMaxDistance(target);
208
+ const scored = candidates.filter((c) => c !== target).map((c) => ({ name: c, distance: levenshteinDistance(target, c) })).filter((s) => s.distance <= effectiveMax).sort((a, b) => a.distance - b.distance);
209
+ return scored.map((s) => s.name);
210
+ }
211
+
212
+ // src/parser/jsdoc/signature-types.ts
213
+ function unwrapPromise(type) {
214
+ if (type.getText().startsWith("Promise<")) {
215
+ const typeArgs = type.getTypeArguments();
216
+ if (typeArgs.length > 0) {
217
+ return typeArgs[0];
218
+ }
219
+ }
220
+ return type;
221
+ }
222
+ function resolveCallSignatures(callbackType) {
223
+ let sigs = callbackType.getCallSignatures();
224
+ if (sigs.length > 0) return sigs;
225
+ try {
226
+ sigs = callbackType.getApparentType().getCallSignatures();
227
+ if (sigs.length > 0) return sigs;
228
+ } catch {
229
+ }
230
+ try {
231
+ const symbol = callbackType.getSymbol() ?? callbackType.getAliasSymbol();
232
+ const decl = symbol?.getDeclarations()?.[0];
233
+ if (decl) {
234
+ sigs = decl.getType().getCallSignatures();
235
+ if (sigs.length > 0) return sigs;
236
+ }
237
+ } catch {
238
+ }
239
+ return sigs;
240
+ }
241
+ function extractCallbackReturnFieldType(callbackType, fieldName) {
242
+ const callSignatures = resolveCallSignatures(callbackType);
243
+ if (callSignatures.length === 0) {
244
+ return void 0;
245
+ }
246
+ const returnType = unwrapPromise(callSignatures[0].getReturnType());
247
+ const property = returnType.getProperty(fieldName);
248
+ if (!property) {
249
+ return void 0;
250
+ }
251
+ const propertyType = getPropertyType(property, returnType);
252
+ if (!propertyType) {
253
+ return void 0;
254
+ }
255
+ return propertyType.getText(void 0, 0);
256
+ }
257
+ function getPropertyType(property, containerType) {
258
+ const valueDecl = property.getValueDeclaration();
259
+ if (valueDecl) {
260
+ return valueDecl.getType();
261
+ }
262
+ const declaredType = containerType.getPropertyOrThrow(property.getName());
263
+ if (declaredType) {
264
+ const decls = declaredType.getDeclarations();
265
+ if (decls.length > 0) {
266
+ return decls[0].getType();
267
+ }
268
+ }
269
+ return void 0;
270
+ }
271
+ function extractCallbackParamType(callbackType, paramName) {
272
+ const callSignatures = resolveCallSignatures(callbackType);
273
+ if (callSignatures.length === 0) {
274
+ return void 0;
275
+ }
276
+ const parameters = callSignatures[0].getParameters();
277
+ for (const param of parameters) {
278
+ if (param.getName() === paramName) {
279
+ const valueDecl = param.getValueDeclaration();
280
+ if (valueDecl) {
281
+ const paramType = valueDecl.getType();
282
+ return paramType.getText(void 0, 0);
283
+ }
284
+ }
285
+ }
286
+ return void 0;
287
+ }
288
+ function typeScopedPort(direction, name, scope, func, warnings) {
289
+ const nodeTypeName = func.getName() || "unknown";
290
+ const scopeParam = func.getParameters().find((p) => p.getName() === scope);
291
+ if (!scopeParam) {
292
+ const callbackShape = direction === "INPUT" ? `(...) => { ${name}: YourType }` : `(${name}: YourType, ...) => { ... }`;
293
+ warnings.push(
294
+ `Scoped ${direction} port '${name}' references scope '${scope}', but no callback parameter named '${scope}' was found in node type '${nodeTypeName}'. Add a callback parameter: ${scope}: ${callbackShape}`
295
+ );
296
+ return { type: "ANY" };
297
+ }
298
+ const extract = direction === "INPUT" ? extractCallbackReturnFieldType : extractCallbackParamType;
299
+ const tsType = extract(scopeParam.getType(), name);
300
+ if (tsType) return { type: inferDataTypeFromTS(tsType), tsType };
301
+ const expectation = direction === "INPUT" ? `should have a return type that includes '${name}'` : `should have a parameter named '${name}'`;
302
+ warnings.push(
303
+ `Cannot infer type for scoped ${direction} port '${name}' in scope '${scope}' of node type '${nodeTypeName}'. The callback parameter '${scope}' ${expectation}. Consider adding an explicit type annotation to the callback signature.`
304
+ );
305
+ return { type: "ANY" };
306
+ }
307
+ function applyDeclaredType(direction, name, declared, inferred, tsType, func, warnings) {
308
+ if (!declared) return inferred;
309
+ const nodeTypeName = func.getName() || "unknown";
310
+ if (!isValidPortType(declared)) {
311
+ warnings.push(
312
+ `@${direction} ${name} in node type '${nodeTypeName}' declares [type:${declared}], which is not a port type. Use one of STRING, NUMBER, BOOLEAN, ARRAY, OBJECT, FUNCTION, ANY or STEP.`
313
+ );
314
+ return inferred;
315
+ }
316
+ if (inferred === "ANY") return declared;
317
+ if (declared !== inferred && declared !== "ANY") {
318
+ warnings.push(
319
+ `@${direction} ${name} in node type '${nodeTypeName}' declares [type:${declared}] but the signature gives ${inferred}${tsType ? ` (${tsType})` : ""}. The signature type is used; change one to match.`
320
+ );
321
+ }
322
+ return inferred;
323
+ }
324
+ function objectFieldPattern(name) {
325
+ const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
326
+ return new RegExp(`(?:^|[{;,\\s])${escaped}\\??\\s*:\\s*([^;},]+)`);
327
+ }
328
+
329
+ // src/parser/jsdoc/port-tags.ts
330
+ function workflowParameterDefault(tagText, name) {
331
+ const escaped = name.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
332
+ const match = tagText.match(new RegExp(`\\[\\s*${escaped}\\s*=\\s*([^\\]\\r\\n]*)\\]`, "u"));
333
+ return match?.[1]?.trim();
334
+ }
335
+ function parseDefaultValue(value) {
336
+ try {
337
+ return JSON.parse(value);
338
+ } catch {
339
+ return value;
340
+ }
341
+ }
342
+ function parseInputTag(tag, config, func, warnings) {
343
+ const comment = tag.getCommentText() || "";
344
+ const result = parsePortLine(`@input ${comment}`, warnings);
345
+ if (!result) {
346
+ return;
347
+ }
348
+ const { name, defaultValue, isOptional, scope, order, mergeStrategy, hidden, description, customMetadata } = result;
349
+ let type;
350
+ let tsType;
351
+ const isScopedStepInput = scope && isScopedMandatoryPort(name);
352
+ if (isExecutePort(name) || isScopedStepInput) {
353
+ if (result.dataType && result.dataType !== "STEP") {
354
+ warnings.push(`Port "${name}" is a reserved control port. Its type will always be STEP.`);
355
+ }
356
+ type = "STEP";
357
+ } else if (scope) {
358
+ ({ type, tsType } = typeScopedPort("INPUT", name, scope, func, warnings));
359
+ } else {
360
+ const param = func.getParameters().find((p) => {
361
+ const pName = p.getName();
362
+ return pName === name || pName === `_${name}`;
363
+ });
364
+ if (param) {
365
+ const rawTsType = param.getType().getText(param);
366
+ tsType = param.isOptional() || param.hasInitializer() ? stripOptionalUndefined(rawTsType) : rawTsType;
367
+ type = inferDataTypeFromTS(tsType);
368
+ } else {
369
+ type = "ANY";
370
+ }
371
+ type = applyDeclaredType("input", name, result.dataType, type, tsType, func, warnings);
372
+ }
373
+ let label = description?.trim();
374
+ let expression = void 0;
375
+ if (label && label.startsWith("Expression:")) {
376
+ expression = label.substring("Expression:".length).trim();
377
+ label = void 0;
378
+ }
379
+ if (Object.prototype.hasOwnProperty.call(config.inputs, name)) {
380
+ warnings.push(`Duplicate @input "${name}". The second declaration will overwrite the first.`);
381
+ }
382
+ config.inputs[name] = {
383
+ type,
384
+ defaultValue: defaultValue === void 0 ? void 0 : parseDefaultValue(defaultValue),
385
+ ...isOptional && { optional: true },
386
+ label,
387
+ ...expression && { expression },
388
+ ...scope && { scope },
389
+ ...mergeStrategy && { mergeStrategy },
390
+ ...hidden && { hidden },
391
+ ...(order !== void 0 || customMetadata) && {
392
+ metadata: { ...order !== void 0 && { order }, ...customMetadata }
393
+ },
394
+ ...tsType && { tsType }
395
+ };
396
+ }
397
+ function parseOutputTag(tag, config, func, warnings) {
398
+ const comment = tag.getCommentText() || "";
399
+ const result = parsePortLine(`@output ${comment}`, warnings);
400
+ if (!result) {
401
+ return;
402
+ }
403
+ const { name, scope, order, hidden, description, customMetadata } = result;
404
+ let type;
405
+ let tsType;
406
+ const isScopedStepOutput = scope && isScopedMandatoryPort(name);
407
+ if (isSuccessPort(name) || isFailurePort(name) || isScopedStepOutput) {
408
+ if (result.dataType && result.dataType !== "STEP") {
409
+ warnings.push(`Port "${name}" is a reserved control port. Its type will always be STEP.`);
410
+ }
411
+ type = "STEP";
412
+ } else if (scope) {
413
+ ({ type, tsType } = typeScopedPort("OUTPUT", name, scope, func, warnings));
414
+ } else {
415
+ const returnType = unwrapPromise(func.getReturnType());
416
+ const property = returnType.getProperty(name);
417
+ if (property) {
418
+ const propertyType = getPropertyType(property, returnType);
419
+ if (propertyType) {
420
+ tsType = propertyType.getText(void 0, 0);
421
+ type = inferDataTypeFromTS(tsType);
422
+ } else {
423
+ type = "ANY";
424
+ }
425
+ } else {
426
+ type = "ANY";
427
+ }
428
+ type = applyDeclaredType("output", name, result.dataType, type, tsType, func, warnings);
429
+ }
430
+ if (Object.prototype.hasOwnProperty.call(config.outputs, name)) {
431
+ warnings.push(`Duplicate @output "${name}". The second declaration will overwrite the first.`);
432
+ }
433
+ config.outputs[name] = {
434
+ type,
435
+ label: description?.trim(),
436
+ ...scope && { scope },
437
+ ...hidden && { hidden },
438
+ ...(order !== void 0 || customMetadata) && {
439
+ metadata: { ...order !== void 0 && { order }, ...customMetadata }
440
+ },
441
+ ...tsType && { tsType }
442
+ };
443
+ }
444
+ function parseStepTag(tag, config, func, warnings) {
445
+ const comment = tag.getCommentText() || "";
446
+ const result = parsePortLine(`@step ${comment}`, warnings);
447
+ if (!result) {
448
+ return;
449
+ }
450
+ const { name, description } = result;
451
+ const param = func.getParameters().find((p) => p.getName() === name);
452
+ if (param) {
453
+ config.inputs[name] = {
454
+ type: "STEP",
455
+ label: description?.trim()
456
+ };
457
+ } else {
458
+ config.outputs[name] = {
459
+ type: "STEP",
460
+ label: description?.trim()
461
+ };
462
+ }
463
+ }
464
+ function parseReturnTag(tag, config, func, warnings) {
465
+ const comment = tag.getCommentText() || "";
466
+ const result = parsePortLine(`@output ${comment}`, warnings);
467
+ if (!result) {
468
+ return;
469
+ }
470
+ const { name, order, description, customMetadata } = result;
471
+ let type = "ANY";
472
+ if (isSuccessPort(name) || isFailurePort(name)) {
473
+ type = "STEP";
474
+ } else if (func) {
475
+ const returnType = func.getReturnType();
476
+ const returnTypeText = returnType.getText();
477
+ const fieldMatch = returnTypeText.match(objectFieldPattern(name));
478
+ if (fieldMatch) {
479
+ type = inferDataTypeFromTS(fieldMatch[1].trim());
480
+ } else {
481
+ warnings.push(`Could not infer type for @returns "${name}", defaulting to ANY.`);
482
+ }
483
+ }
484
+ config.returnPorts = config.returnPorts || {};
485
+ if (Object.prototype.hasOwnProperty.call(config.returnPorts, name)) {
486
+ warnings.push(`Duplicate @returns "${name}". The second declaration will overwrite the first.`);
487
+ }
488
+ config.returnPorts[name] = {
489
+ dataType: type,
490
+ label: description?.trim(),
491
+ ...(order !== void 0 || customMetadata) && {
492
+ metadata: { ...order !== void 0 && { order }, ...customMetadata }
493
+ }
494
+ };
495
+ }
496
+ function parseParamTag(tag, config, func, warnings) {
497
+ const compilerNode = tag.compilerNode;
498
+ const tagWithGetName = tag;
499
+ const name = compilerNode.name?.getText?.() || tagWithGetName.getName && tagWithGetName.getName();
500
+ if (!name) {
501
+ return;
502
+ }
503
+ const comment = tag.getCommentText() || "";
504
+ const result = parsePortLine(`@input ${name} ${comment}`, warnings);
505
+ const order = result?.order;
506
+ const description = result?.description;
507
+ const optional = compilerNode.isBracketed === true;
508
+ const defaultSource = workflowParameterDefault(tag.getText(), name);
509
+ let type = "ANY";
510
+ if (isExecutePort(name)) {
511
+ type = "STEP";
512
+ } else if (func) {
513
+ const params = func.getParameters();
514
+ const paramsParam = params.find((p) => p.getName() === "params");
515
+ if (paramsParam) {
516
+ const paramType = paramsParam.getType();
517
+ const paramTypeText = paramType.getText();
518
+ const isCatchAllRecord = /^Record<string,\s*(never|any|unknown)>$/.test(paramTypeText) || paramTypeText === "{}" || /^\{\s*\[[\w]+:\s*string\]:\s*(never|any|unknown);\s*\}$/.test(paramTypeText);
519
+ if (!isCatchAllRecord) {
520
+ const fieldMatch = paramTypeText.match(objectFieldPattern(name));
521
+ if (fieldMatch) {
522
+ type = inferDataTypeFromTS(fieldMatch[1].trim());
523
+ } else {
524
+ warnings.push(`@param "${name}" does not match any field in the params object. Type defaults to ANY.`);
525
+ }
526
+ }
527
+ }
528
+ }
529
+ config.startPorts = config.startPorts || {};
530
+ if (Object.prototype.hasOwnProperty.call(config.startPorts, name)) {
531
+ warnings.push(`Duplicate @param "${name}". The second declaration will overwrite the first.`);
532
+ }
533
+ config.startPorts[name] = {
534
+ dataType: type,
535
+ label: description?.trim(),
536
+ ...optional && { optional: true },
537
+ ...defaultSource === void 0 ? {} : { default: parseDefaultValue(defaultSource) },
538
+ ...order !== void 0 && { metadata: { order } }
539
+ };
540
+ }
541
+
542
+ // src/parser/jsdoc/parse-line-once.ts
543
+ function parseLineOnce(parse, line, warnings, fallback) {
544
+ const before = warnings.length;
545
+ const result = parse(line, warnings);
546
+ if (result === null && warnings.length === before) warnings.push(fallback);
547
+ return result;
548
+ }
549
+
550
+ // src/parser/jsdoc/runtime-tags.ts
551
+ var HTTP_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE"]);
552
+ function parseTriggerTag(tag, config, warnings, tagRegistry) {
553
+ const comment = (tag.getCommentText() || "").trim();
554
+ const result = parseTriggerLine(`@trigger ${comment}`, warnings);
555
+ if (result) {
556
+ config.trigger = config.trigger || {};
557
+ if (result.event) config.trigger.event = result.event;
558
+ if (result.cron) config.trigger.cron = result.cron;
559
+ return;
560
+ }
561
+ if (tagRegistry && tagRegistry.has("_trigger")) {
562
+ if (!config.deploy) config.deploy = {};
563
+ tagRegistry.handle("_trigger", comment, "workflow", config.deploy, warnings);
564
+ return;
565
+ }
566
+ warnings.push(`Invalid @trigger format: @trigger ${comment}`);
567
+ }
568
+ function parseCancelOnTag(tag, config, warnings) {
569
+ const comment = tag.getCommentText() || "";
570
+ const result = parseLineOnce(parseCancelOnLine, `@cancelOn ${comment}`, warnings, `Invalid @cancelOn format: @cancelOn ${comment}`);
571
+ if (!result) {
572
+ return;
573
+ }
574
+ config.cancelOn = result;
575
+ }
576
+ function parseThrottleTag(tag, config, warnings) {
577
+ const comment = tag.getCommentText() || "";
578
+ const result = parseLineOnce(parseThrottleLine, `@throttle ${comment}`, warnings, `Invalid @throttle format: @throttle ${comment}`);
579
+ if (!result) {
580
+ return;
581
+ }
582
+ config.throttle = result;
583
+ }
584
+ function parseRetriesTag(tag, config, warnings) {
585
+ const comment = tag.getCommentText() || "";
586
+ const result = parseRetriesLine(`@retries ${comment.trim()}`, warnings);
587
+ if (result && result.retries >= 0) config.retries = result.retries;
588
+ }
589
+ function parseTimeoutTag(tag, config, warnings) {
590
+ const comment = tag.getCommentText() || "";
591
+ const raw = comment.trim();
592
+ const quoted = /^"(?:[^"\\]|\\.)*"$/.test(raw) ? raw : `"${raw.replace(/^['"]|['"]$/g, "")}"`;
593
+ const result = parseTimeoutLine(`@timeout ${quoted}`, warnings);
594
+ if (result && result.timeout) config.timeout = result.timeout;
595
+ }
596
+ function parseHttpTag(tag, config, warnings) {
597
+ const text = (tag.getCommentText() || "").trim();
598
+ const parts = text.split(/\s+/).filter(Boolean);
599
+ const fail = (why) => {
600
+ warnings.push(`Invalid @http: "${text}". ${why} Format: @http METHOD /path [mode=sync|async] [auth=bearer|none] [callback]`);
601
+ };
602
+ if (parts.length < 2) return fail("Give a method and a path.");
603
+ const method = parts[0].toUpperCase();
604
+ if (!HTTP_METHODS.has(method)) return fail(`"${parts[0]}" is not one of GET, POST, PUT, PATCH, DELETE.`);
605
+ const routePath = parts[1];
606
+ if (!/^\/(?:[A-Za-z0-9_\-.~%]+|:[A-Za-z_][A-Za-z0-9_]*)(?:\/(?:[A-Za-z0-9_\-.~%]+|:[A-Za-z_][A-Za-z0-9_]*))*\/?$|^\/$/.test(routePath)) {
607
+ return fail(`"${routePath}" is not a path: it starts with / and its segments are words or :params.`);
608
+ }
609
+ const route = { method, path: routePath.length > 1 ? routePath.replace(/\/$/, "") : routePath };
610
+ for (const opt of parts.slice(2)) {
611
+ const [key, raw] = opt.includes("=") ? opt.split("=", 2) : [opt, void 0];
612
+ const value = raw?.replace(/^["']|["']$/g, "");
613
+ if (key === "mode" && (value === "sync" || value === "async")) {
614
+ if (value === "async") route.mode = "async";
615
+ } else if (key === "auth" && (value === "bearer" || value === "none")) {
616
+ if (value === "none") route.auth = "none";
617
+ } else if (key === "callback" && (value === void 0 || value === "true" || value === "false")) {
618
+ if (value !== "false") route.callback = true;
619
+ } else return fail(`"${opt}" is not an option.`);
620
+ }
621
+ config.http = config.http || [];
622
+ if (config.http.some((r) => r.method === route.method && r.path === route.path)) {
623
+ warnings.push(`Duplicate @http route ${route.method} ${route.path}. The first one stands.`);
624
+ return;
625
+ }
626
+ config.http.push(route);
627
+ }
628
+ function parseDeployTag(tag, deployMap) {
629
+ const text = (tag.getCommentText() || "").trim();
630
+ if (!text) return;
631
+ const spaceIdx = text.indexOf(" ");
632
+ const targetName = spaceIdx === -1 ? text : text.substring(0, spaceIdx);
633
+ const rest = spaceIdx === -1 ? "" : text.substring(spaceIdx + 1);
634
+ if (!targetName) return;
635
+ if (!deployMap[targetName]) deployMap[targetName] = {};
636
+ if (!rest) return;
637
+ const kvRegex = /(\w[\w-]*)\s*=\s*(?:"((?:[^"\\]|\\.)*)"|([\S]+))/g;
638
+ let match;
639
+ while ((match = kvRegex.exec(rest)) !== null) {
640
+ const key = match[1];
641
+ const quotedVal = match[2];
642
+ const bareVal = match[3];
643
+ if (quotedVal !== void 0) {
644
+ if (quotedVal.includes(",")) {
645
+ deployMap[targetName][key] = quotedVal.split(",").map((v) => v.trim());
646
+ } else {
647
+ deployMap[targetName][key] = quotedVal;
648
+ }
649
+ } else if (bareVal !== void 0) {
650
+ if (bareVal === "true") {
651
+ deployMap[targetName][key] = true;
652
+ } else if (bareVal === "false") {
653
+ deployMap[targetName][key] = false;
654
+ } else {
655
+ const num = Number(bareVal);
656
+ deployMap[targetName][key] = isNaN(num) ? bareVal : num;
657
+ }
658
+ }
659
+ }
660
+ }
661
+
662
+ // src/parser/jsdoc/node-type-block.ts
663
+ function parseResilience(comment, config, warnings) {
664
+ const resilience = {};
665
+ const attributes = comment.matchAll(/(\w+)=(?:"([^"]*)"|'([^']*)'|(\S+))/g);
666
+ for (const match of attributes) {
667
+ const key = match[1];
668
+ const value = match[2] ?? match[3] ?? match[4];
669
+ if (key === "retries") {
670
+ const retries = Number(value);
671
+ if (Number.isInteger(retries) && retries > 0) {
672
+ resilience.retries = retries;
673
+ } else {
674
+ warnings.push("@resilience retries must be a positive integer.");
675
+ }
676
+ } else if (key === "fallback") {
677
+ if (value.trim()) resilience.fallback = value.trim();
678
+ } else {
679
+ warnings.push(`Unknown @resilience option "${key}". Supported options: retries, fallback.`);
680
+ }
681
+ }
682
+ if (resilience.retries !== void 0 || resilience.fallback !== void 0) {
683
+ config.resilience = resilience;
684
+ } else {
685
+ warnings.push('@resilience requires retries=N and/or fallback="provider".');
686
+ }
687
+ }
688
+ function parseNodeType(func, warnings, tagRegistry) {
689
+ const jsdocs = func.getJsDocs();
690
+ if (jsdocs.length === 0) return null;
691
+ let jsdoc = null;
692
+ let flowWeaverTag = null;
693
+ let isNodeShorthand = false;
694
+ for (const doc of jsdocs) {
695
+ const tags2 = doc.getTags();
696
+ const tag = tags2.find(
697
+ (t) => {
698
+ if (t.getTagName() !== "flowWeaver") return false;
699
+ const comment = t.getCommentText()?.trim();
700
+ return comment === "nodeType" || comment === "node";
701
+ }
702
+ );
703
+ if (tag) {
704
+ jsdoc = doc;
705
+ flowWeaverTag = tag;
706
+ isNodeShorthand = flowWeaverTag.getCommentText()?.trim() === "node";
707
+ break;
708
+ }
709
+ }
710
+ if (!jsdoc || !flowWeaverTag) return null;
711
+ const tags = jsdoc.getTags();
712
+ const config = {
713
+ inputs: {},
714
+ outputs: {}
715
+ };
716
+ if (isNodeShorthand) {
717
+ config.expression = true;
718
+ }
719
+ const descriptionText = jsdoc.getDescription();
720
+ if (descriptionText && descriptionText.trim()) {
721
+ config.description = descriptionText.trim();
722
+ }
723
+ tags.forEach((tag) => {
724
+ const tagName = tag.getTagName();
725
+ const comment = tag.getCommentText() || "";
726
+ switch (tagName) {
727
+ case "name":
728
+ config.name = comment.trim();
729
+ break;
730
+ case "label":
731
+ config.label = comment.trim();
732
+ break;
733
+ case "description":
734
+ config.description = comment.trim();
735
+ break;
736
+ case "color":
737
+ config.color = comment.trim().replace(/^["']|["']$/g, "");
738
+ break;
739
+ case "icon":
740
+ config.icon = comment.trim().replace(/^["']|["']$/g, "");
741
+ break;
742
+ case "tag": {
743
+ config.tags = config.tags || [];
744
+ const tagMatch = comment.match(/^(\S+)(?:\s+"([^"]+)")?$/);
745
+ if (tagMatch) {
746
+ config.tags.push({
747
+ label: tagMatch[1],
748
+ ...tagMatch[2] && { tooltip: tagMatch[2] }
749
+ });
750
+ }
751
+ break;
752
+ }
753
+ case "executeWhen":
754
+ config.executeWhen = comment.trim();
755
+ break;
756
+ case "scope":
757
+ config.scope = comment.trim();
758
+ break;
759
+ case "expression":
760
+ config.expression = true;
761
+ break;
762
+ case "pullExecution": {
763
+ const pullValue = comment.trim();
764
+ if (pullValue) {
765
+ config.defaultConfig = config.defaultConfig || {};
766
+ config.defaultConfig.pullExecution = { triggerPort: pullValue };
767
+ }
768
+ break;
769
+ }
770
+ case "resilience":
771
+ parseResilience(comment, config, warnings);
772
+ break;
773
+ case "input":
774
+ parseInputTag(tag, config, func, warnings);
775
+ break;
776
+ case "output":
777
+ parseOutputTag(tag, config, func, warnings);
778
+ break;
779
+ case "step":
780
+ parseStepTag(tag, config, func, warnings);
781
+ break;
782
+ case "deploy":
783
+ config.deploy = config.deploy || {};
784
+ parseDeployTag(tag, config.deploy);
785
+ break;
786
+ default: {
787
+ if (tagName === "param" || tagName === "returns" || tagName === "return") {
788
+ warnings.push(`@${tagName} is for workflows, not node types. Use @input/@output instead.`);
789
+ } else if (tagRegistry && tagRegistry.has(tagName)) {
790
+ if (!config.deploy) config.deploy = {};
791
+ tagRegistry.handle(tagName, comment, "nodeType", config.deploy, warnings);
792
+ } else if (!KNOWN_NODETYPE_TAGS.has(tagName) && !STANDARD_JSDOC_TAGS.has(tagName)) {
793
+ const suggestions = findClosestMatches(tagName, [...KNOWN_NODETYPE_TAGS]);
794
+ const hint = suggestions.length > 0 ? ` Did you mean @${suggestions[0]}?` : "";
795
+ warnings.push(`Unknown annotation @${tagName} in nodeType block.${hint}`);
796
+ }
797
+ break;
798
+ }
799
+ }
800
+ });
801
+ return config;
802
+ }
803
+
804
+ // src/parser/jsdoc/graph-tags.ts
805
+ var POSITION_ATTR = /\s*\[position:\s*-?\d+\s+-?\d+\]|,\s*position:\s*-?\d+\s+-?\d+(?=\s*[,\]])|(?<=\[)\s*position:\s*-?\d+\s+-?\d+\s*,\s*/g;
806
+ var positionGone = (where) => `${where}: node positions are no longer part of the grammar and this was ignored. Remove it, or run \`fw compile\` / \`fw migrate\` to rewrite the block without it.`;
807
+ function parseImportTag(tag, config, warnings) {
808
+ const comment = tag.getCommentText()?.trim() || "";
809
+ const match = comment.match(/^(\S+)\s+(\S+)\s+from\s+["']([^"']+)["']$/);
810
+ if (match) {
811
+ const [, name, functionName, importSource] = match;
812
+ config.imports.push({ name, functionName, importSource });
813
+ } else {
814
+ warnings.push(
815
+ `Invalid @fwImport tag format: "${comment}". Expected: @fwImport nodeName functionName from "packageName"`
816
+ );
817
+ }
818
+ }
819
+ function parseNodeTag(tag, config, warnings) {
820
+ let comment = tag.getCommentText() || "";
821
+ if (POSITION_ATTR.test(comment)) {
822
+ POSITION_ATTR.lastIndex = 0;
823
+ comment = comment.replace(POSITION_ATTR, "");
824
+ warnings.push(positionGone(`@node ${comment.trim().split(/\s+/)[0]} [position:]`));
825
+ }
826
+ POSITION_ATTR.lastIndex = 0;
827
+ const result = parseNodeLine(`@node ${comment}`, warnings);
828
+ if (!result) {
829
+ return;
830
+ }
831
+ const {
832
+ instanceId,
833
+ nodeType,
834
+ parentScope,
835
+ label,
836
+ expressions,
837
+ portOrder,
838
+ portLabel,
839
+ minimized,
840
+ pullExecution,
841
+ size,
842
+ color,
843
+ icon,
844
+ tags,
845
+ attributes,
846
+ suppress
847
+ } = result;
848
+ const line = tag.getStartLineNumber();
849
+ let portConfigs;
850
+ if (portOrder) {
851
+ portConfigs = Object.entries(portOrder).map(([portName, order]) => ({
852
+ portName,
853
+ order
854
+ }));
855
+ }
856
+ if (portLabel) {
857
+ portConfigs = portConfigs || [];
858
+ for (const [portName, labelVal] of Object.entries(portLabel)) {
859
+ const existingIndex = portConfigs.findIndex((pc) => pc.portName === portName);
860
+ if (existingIndex >= 0) {
861
+ portConfigs[existingIndex] = { ...portConfigs[existingIndex], label: labelVal };
862
+ } else {
863
+ portConfigs.push({ portName, label: labelVal });
864
+ }
865
+ }
866
+ }
867
+ if (expressions) {
868
+ portConfigs = portConfigs || [];
869
+ for (const [portName, expression] of Object.entries(expressions)) {
870
+ const existingIndex = portConfigs.findIndex((pc) => pc.portName === portName);
871
+ if (existingIndex >= 0) {
872
+ portConfigs[existingIndex] = { ...portConfigs[existingIndex], expression };
873
+ } else {
874
+ portConfigs.push({ portName, expression });
875
+ }
876
+ }
877
+ }
878
+ config.instances.push({
879
+ id: instanceId,
880
+ type: nodeType,
881
+ ...parentScope && { parentScope },
882
+ ...label && { label },
883
+ ...portConfigs && portConfigs.length > 0 && { portConfigs },
884
+ ...pullExecution && { pullExecution: { triggerPort: pullExecution } },
885
+ ...minimized && { minimized },
886
+ ...color && { color },
887
+ ...icon && { icon },
888
+ ...tags && tags.length > 0 && { tags },
889
+ ...size && { width: size.width, height: size.height },
890
+ ...attributes && Object.keys(attributes).length > 0 && { attributes },
891
+ ...suppress && suppress.length > 0 && { suppressWarnings: suppress },
892
+ sourceLocation: { line, column: 0 }
893
+ });
894
+ }
895
+ function parseConnectTag(tag, config, warnings) {
896
+ const comment = tag.getCommentText() || "";
897
+ const result = parseLineOnce(parseConnectLine, `@connect ${comment}`, warnings, `Invalid @connect tag format: @connect ${comment}`);
898
+ if (!result) {
899
+ return;
900
+ }
901
+ const { source, target, coerce } = result;
902
+ const line = tag.getStartLineNumber();
903
+ config.connections.push({
904
+ from: {
905
+ node: source.nodeId,
906
+ port: source.portName,
907
+ ...source.scope && { scope: source.scope }
908
+ },
909
+ to: {
910
+ node: target.nodeId,
911
+ port: target.portName,
912
+ ...target.scope && { scope: target.scope }
913
+ },
914
+ sourceLocation: { line, column: 0 },
915
+ ...coerce && { coerce }
916
+ });
917
+ }
918
+ function parseScopeTag(tag, config, warnings) {
919
+ const comment = tag.getCommentText() || "";
920
+ const result = parseLineOnce(parseScopeLine, `@scope ${comment}`, warnings, `Invalid @scope tag format: ${comment}`);
921
+ if (!result) {
922
+ return;
923
+ }
924
+ config.scopes[result.scopeName] = result.children;
925
+ }
926
+ function parseMapTag(tag, config, warnings) {
927
+ const comment = tag.getCommentText() || "";
928
+ const result = parseLineOnce(parseMapLine, `@map ${comment}`, warnings, `Invalid @map tag format: ${comment}`);
929
+ if (!result) {
930
+ return;
931
+ }
932
+ config.maps = config.maps || [];
933
+ config.maps.push({
934
+ instanceId: result.instanceId,
935
+ childId: result.childId,
936
+ sourceNode: result.sourceNode,
937
+ sourcePort: result.sourcePort,
938
+ ...result.inputPort && { inputPort: result.inputPort },
939
+ ...result.outputPort && { outputPort: result.outputPort }
940
+ });
941
+ }
942
+ function parsePathTag(tag, config, warnings) {
943
+ const comment = tag.getCommentText() || "";
944
+ const results = parseLineOnce(parsePathLine, `@path ${comment}`, warnings, `Invalid @path tag format: ${comment}`);
945
+ if (!results) {
946
+ return;
947
+ }
948
+ config.paths = config.paths || [];
949
+ for (const result of results) {
950
+ config.paths.push({
951
+ steps: result.steps
952
+ });
953
+ }
954
+ }
955
+ function parseFanOutTag(tag, config, warnings) {
956
+ const comment = tag.getCommentText() || "";
957
+ const result = parseLineOnce(parseFanOutLine, `@fanOut ${comment}`, warnings, `Invalid @fanOut tag format: ${comment}`);
958
+ if (!result) {
959
+ return;
960
+ }
961
+ if (!result.source.port) {
962
+ warnings.push(`@fanOut source must specify a port: ${comment}`);
963
+ return;
964
+ }
965
+ config.fanOuts = config.fanOuts || [];
966
+ config.fanOuts.push({
967
+ source: { node: result.source.node, port: result.source.port },
968
+ targets: result.targets
969
+ });
970
+ }
971
+ function parseFanInTag(tag, config, warnings) {
972
+ const comment = tag.getCommentText() || "";
973
+ const result = parseLineOnce(parseFanInLine, `@fanIn ${comment}`, warnings, `Invalid @fanIn tag format: ${comment}`);
974
+ if (!result) {
975
+ return;
976
+ }
977
+ if (!result.target.port) {
978
+ warnings.push(`@fanIn target must specify a port: ${comment}`);
979
+ return;
980
+ }
981
+ config.fanIns = config.fanIns || [];
982
+ config.fanIns.push({
983
+ sources: result.sources,
984
+ target: { node: result.target.node, port: result.target.port }
985
+ });
986
+ }
987
+ function parseCoerceTag(tag, config, warnings) {
988
+ const comment = tag.getCommentText() || "";
989
+ const result = parseLineOnce(parseCoerceLine, `@coerce ${comment}`, warnings, `Invalid @coerce tag format: ${comment}`);
990
+ if (!result) {
991
+ return;
992
+ }
993
+ config.coercions = config.coercions || [];
994
+ config.coercions.push({
995
+ instanceId: result.instanceId,
996
+ source: result.source,
997
+ target: result.target,
998
+ targetType: result.targetType
999
+ });
1000
+ }
1001
+
1002
+ // src/parser/jsdoc/workflow-block.ts
1003
+ function parseWorkflow(func, warnings, tagRegistry) {
1004
+ const jsdocs = func.getJsDocs();
1005
+ if (jsdocs.length === 0) return null;
1006
+ let jsdoc = null;
1007
+ let flowWeaverTag = null;
1008
+ for (const doc of jsdocs) {
1009
+ const tags2 = doc.getTags();
1010
+ const tag = tags2.find(
1011
+ (t) => t.getTagName() === "flowWeaver" && t.getCommentText()?.trim() === "workflow"
1012
+ );
1013
+ if (tag) {
1014
+ jsdoc = doc;
1015
+ flowWeaverTag = tag;
1016
+ break;
1017
+ }
1018
+ }
1019
+ if (!jsdoc || !flowWeaverTag) return null;
1020
+ const tags = jsdoc.getTags();
1021
+ const config = {
1022
+ imports: [],
1023
+ instances: [],
1024
+ connections: [],
1025
+ scopes: {}
1026
+ };
1027
+ const descriptionText = jsdoc.getDescription();
1028
+ if (descriptionText && descriptionText.trim()) {
1029
+ config.description = descriptionText.trim();
1030
+ }
1031
+ tags.forEach((tag) => {
1032
+ const tagName = tag.getTagName();
1033
+ const comment = tag.getCommentText() || "";
1034
+ switch (tagName) {
1035
+ case "name":
1036
+ config.name = comment.trim();
1037
+ break;
1038
+ case "fwImport":
1039
+ parseImportTag(tag, config, warnings);
1040
+ break;
1041
+ case "description":
1042
+ config.description = comment.trim();
1043
+ break;
1044
+ case "strictTypes":
1045
+ config.strictTypes = comment.trim().toLowerCase() !== "false";
1046
+ break;
1047
+ case "autoConnect":
1048
+ config.autoConnect = true;
1049
+ break;
1050
+ case "node":
1051
+ parseNodeTag(tag, config, warnings);
1052
+ break;
1053
+ case "position":
1054
+ warnings.push(positionGone(`@position ${comment.trim()}`));
1055
+ break;
1056
+ case "connect":
1057
+ parseConnectTag(tag, config, warnings);
1058
+ break;
1059
+ case "scope":
1060
+ parseScopeTag(tag, config, warnings);
1061
+ break;
1062
+ case "map":
1063
+ parseMapTag(tag, config, warnings);
1064
+ break;
1065
+ case "path":
1066
+ parsePathTag(tag, config, warnings);
1067
+ break;
1068
+ case "fanOut":
1069
+ parseFanOutTag(tag, config, warnings);
1070
+ break;
1071
+ case "fanIn":
1072
+ parseFanInTag(tag, config, warnings);
1073
+ break;
1074
+ case "coerce":
1075
+ parseCoerceTag(tag, config, warnings);
1076
+ break;
1077
+ case "trigger":
1078
+ parseTriggerTag(tag, config, warnings, tagRegistry);
1079
+ break;
1080
+ case "http":
1081
+ parseHttpTag(tag, config, warnings);
1082
+ break;
1083
+ case "cancelOn":
1084
+ parseCancelOnTag(tag, config, warnings);
1085
+ break;
1086
+ case "retries":
1087
+ parseRetriesTag(tag, config, warnings);
1088
+ break;
1089
+ case "timeout":
1090
+ parseTimeoutTag(tag, config, warnings);
1091
+ break;
1092
+ case "throttle":
1093
+ parseThrottleTag(tag, config, warnings);
1094
+ break;
1095
+ case "deploy":
1096
+ config.deploy = config.deploy || {};
1097
+ parseDeployTag(tag, config.deploy);
1098
+ break;
1099
+ case "param":
1100
+ parseParamTag(tag, config, func, warnings);
1101
+ break;
1102
+ case "return":
1103
+ case "returns":
1104
+ parseReturnTag(tag, config, func, warnings);
1105
+ break;
1106
+ default: {
1107
+ if (tagName === "color" || tagName === "icon" || tagName === "tag") {
1108
+ warnings.push(`@${tagName} is for node types, not workflows. Use it on @flowWeaver nodeType instead.`);
1109
+ } else if (tagName === "input" || tagName === "output" || tagName === "step") {
1110
+ warnings.push(`@${tagName} is for node types, not workflows. Use @param/@returns for workflows.`);
1111
+ } else if (tagRegistry && tagRegistry.has(tagName)) {
1112
+ if (!config.deploy) config.deploy = {};
1113
+ tagRegistry.handle(tagName, comment, "workflow", config.deploy, warnings);
1114
+ } else {
1115
+ const knownTags = getKnownWorkflowTags(tagRegistry?.getRegisteredTags());
1116
+ if (!knownTags.has(tagName) && !STANDARD_JSDOC_TAGS.has(tagName)) {
1117
+ const suggestions = findClosestMatches(tagName, [...knownTags]);
1118
+ const hint = suggestions.length > 0 ? ` Did you mean @${suggestions[0]}?` : "";
1119
+ warnings.push(`Unknown annotation @${tagName} in workflow block.${hint}`);
1120
+ }
1121
+ }
1122
+ break;
1123
+ }
1124
+ }
1125
+ });
1126
+ return config;
1127
+ }
1128
+
1129
+ // src/parser/jsdoc-parser.ts
1130
+ var jsdocParser = {
1131
+ parseNodeType,
1132
+ parseWorkflow
1133
+ };
1134
+
1135
+ // src/built-in-nodes/generated-registry.ts
1136
+ var BUILT_IN_NODE_TYPES = [
1137
+ {
1138
+ type: "NodeType",
1139
+ name: "delay",
1140
+ functionName: "delay",
1141
+ isAsync: true,
1142
+ receivesAbortSignal: true,
1143
+ receivesRuntime: true,
1144
+ durablePure: true,
1145
+ hasSuccessPort: true,
1146
+ hasFailurePort: true,
1147
+ executeWhen: "CONJUNCTION",
1148
+ variant: "FUNCTION",
1149
+ inputs: {
1150
+ execute: { dataType: "STEP", label: "Execute" },
1151
+ duration: { dataType: "STRING", label: 'Duration to sleep (e.g. "30s", "5m", "1h", "2d")', tsType: "string" }
1152
+ },
1153
+ outputs: {
1154
+ elapsed: { dataType: "BOOLEAN", label: "Always true after sleep completes", tsType: "boolean" },
1155
+ onSuccess: { dataType: "STEP", label: "On Success", isControlFlow: true },
1156
+ onFailure: { dataType: "STEP", label: "On Failure", isControlFlow: true, failure: true }
1157
+ },
1158
+ helperText: `
1159
+ function __fw_getMockConfig(runtime?: NodeExecutionRuntime): FwMockConfig | undefined {
1160
+ return runtime?.runtime.services.mocks;
1161
+ }
1162
+
1163
+ function __fw_lookupMock<T>(
1164
+ section: Record<string, T> | undefined,
1165
+ key: string,
1166
+ runtime?: NodeExecutionRuntime,
1167
+ ): T | undefined {
1168
+ if (!section) return undefined;
1169
+
1170
+ const nodeId = runtime?.nodeId;
1171
+ if (nodeId) {
1172
+ const qualified = section[\`\${nodeId}:\${key}\`];
1173
+ if (qualified !== undefined) return qualified;
1174
+ const any = section[\`\${nodeId}:*\`];
1175
+ if (any !== undefined) return any;
1176
+ }
1177
+
1178
+ return section[key];
1179
+ }
1180
+ `.trim(),
1181
+ helperTextProduction: void 0,
1182
+ functionText: `
1183
+ async function delay(
1184
+ execute: boolean,
1185
+ duration: string,
1186
+ abortSignal?: AbortSignal,
1187
+ runtime?: NodeExecutionRuntime,
1188
+ ): Promise<{ onSuccess: boolean; onFailure: boolean; elapsed: boolean }> {
1189
+ if (!execute) return { onSuccess: false, onFailure: false, elapsed: false };
1190
+
1191
+ const mocks = __fw_getMockConfig(runtime);
1192
+ if (mocks?.fast) {
1193
+ // Fast mode: skip real sleep, keep async behavior with 1ms
1194
+ await __fw_waitForDuration(1, abortSignal);
1195
+ } else {
1196
+ const ms = __fw_parseDuration(duration) ?? 0;
1197
+ // setTimeout holds a signed 32-bit delay. Past 2^31-1 ms (24.8 days) it
1198
+ // fires at once with a warning instead of waiting, so a longer duration
1199
+ // is refused rather than silently cut short. A run that waits that long
1200
+ // wants \`sleep\`, which holds no process.
1201
+ if (ms > 2147483647) {
1202
+ throw new Error(
1203
+ 'delay: "' + duration + '" is longer than setTimeout can wait (24.8 days); use sleep for a wait this long',
1204
+ );
1205
+ }
1206
+ await __fw_waitForDuration(ms, abortSignal);
1207
+ }
1208
+
1209
+ return { onSuccess: true, onFailure: false, elapsed: true };
1210
+ }
1211
+
1212
+ function __fw_waitForDuration(ms: number, abortSignal?: AbortSignal): Promise<void> {
1213
+ if (abortSignal?.aborted) return Promise.reject(new CancellationError());
1214
+
1215
+ return new Promise((resolve, reject) => {
1216
+ let settled = false;
1217
+ const onAbort = () => {
1218
+ if (settled) return;
1219
+ settled = true;
1220
+ clearTimeout(timer);
1221
+ abortSignal?.removeEventListener('abort', onAbort);
1222
+ reject(new CancellationError());
1223
+ };
1224
+ const timer = setTimeout(() => {
1225
+ if (settled) return;
1226
+ settled = true;
1227
+ abortSignal?.removeEventListener('abort', onAbort);
1228
+ resolve();
1229
+ }, ms);
1230
+
1231
+ abortSignal?.addEventListener('abort', onAbort, { once: true });
1232
+ if (abortSignal?.aborted) onAbort();
1233
+ });
1234
+ }
1235
+
1236
+ // \`<number><unit>\` with unit \`ms\`, \`s\`, \`m\`, \`h\` or \`d\`, whitespace around
1237
+ // either allowed; \`undefined\` for anything else, including an empty string.
1238
+ // This is the one reading of a duration string in the package: the
1239
+ // coordinator's clock (\`src/coordinator/time.ts\`) re-exports it for a
1240
+ // \`sleep\` duration and a gate \`timeout\`, and this file's body is inlined into
1241
+ // compiled workflows, which is why the function lives here and not there.
1242
+ function __fw_parseDuration(text: unknown): number | undefined {
1243
+ if (typeof text !== 'string') return undefined;
1244
+ const match = /^\\s*(\\d+)\\s*(ms|s|m|h|d)\\s*$/.exec(text);
1245
+ if (!match) return undefined;
1246
+ const units: Record<string, number> = { ms: 1, s: 1000, m: 60000, h: 3600000, d: 86400000 };
1247
+ return Number(match[1]) * units[match[2]];
1248
+ }
1249
+ `.trim(),
1250
+ functionTextProduction: `
1251
+ async function delay(
1252
+ execute: boolean,
1253
+ duration: string,
1254
+ abortSignal?: AbortSignal,
1255
+ runtime?: NodeExecutionRuntime,
1256
+ ): Promise<{ onSuccess: boolean; onFailure: boolean; elapsed: boolean }> {
1257
+ if (!execute) return { onSuccess: false, onFailure: false, elapsed: false };
1258
+
1259
+ const ms = __fw_parseDuration(duration) ?? 0;
1260
+ // setTimeout holds a signed 32-bit delay. Past 2^31-1 ms (24.8 days) it
1261
+ // fires at once with a warning instead of waiting, so a longer duration
1262
+ // is refused rather than silently cut short. A run that waits that long
1263
+ // wants \`sleep\`, which holds no process.
1264
+ if (ms > 2147483647) {
1265
+ throw new Error(
1266
+ 'delay: "' + duration + '" is longer than setTimeout can wait (24.8 days); use sleep for a wait this long',
1267
+ );
1268
+ }
1269
+ await __fw_waitForDuration(ms, abortSignal);
1270
+
1271
+ return { onSuccess: true, onFailure: false, elapsed: true };
1272
+ }
1273
+
1274
+ function __fw_waitForDuration(ms: number, abortSignal?: AbortSignal): Promise<void> {
1275
+ if (abortSignal?.aborted) return Promise.reject(new CancellationError());
1276
+
1277
+ return new Promise((resolve, reject) => {
1278
+ let settled = false;
1279
+ const onAbort = () => {
1280
+ if (settled) return;
1281
+ settled = true;
1282
+ clearTimeout(timer);
1283
+ abortSignal?.removeEventListener('abort', onAbort);
1284
+ reject(new CancellationError());
1285
+ };
1286
+ const timer = setTimeout(() => {
1287
+ if (settled) return;
1288
+ settled = true;
1289
+ abortSignal?.removeEventListener('abort', onAbort);
1290
+ resolve();
1291
+ }, ms);
1292
+
1293
+ abortSignal?.addEventListener('abort', onAbort, { once: true });
1294
+ if (abortSignal?.aborted) onAbort();
1295
+ });
1296
+ }
1297
+
1298
+ // \`<number><unit>\` with unit \`ms\`, \`s\`, \`m\`, \`h\` or \`d\`, whitespace around
1299
+ // either allowed; \`undefined\` for anything else, including an empty string.
1300
+ // This is the one reading of a duration string in the package: the
1301
+ // coordinator's clock (\`src/coordinator/time.ts\`) re-exports it for a
1302
+ // \`sleep\` duration and a gate \`timeout\`, and this file's body is inlined into
1303
+ // compiled workflows, which is why the function lives here and not there.
1304
+ function __fw_parseDuration(text: unknown): number | undefined {
1305
+ if (typeof text !== 'string') return undefined;
1306
+ const match = /^\\s*(\\d+)\\s*(ms|s|m|h|d)\\s*$/.exec(text);
1307
+ if (!match) return undefined;
1308
+ const units: Record<string, number> = { ms: 1, s: 1000, m: 60000, h: 3600000, d: 86400000 };
1309
+ return Number(match[1]) * units[match[2]];
1310
+ }
1311
+ `.trim()
1312
+ },
1313
+ {
1314
+ type: "NodeType",
1315
+ name: "sleep",
1316
+ functionName: "sleep",
1317
+ isAsync: true,
1318
+ receivesAbortSignal: false,
1319
+ receivesRuntime: true,
1320
+ durableGate: "timer",
1321
+ hasSuccessPort: true,
1322
+ hasFailurePort: true,
1323
+ executeWhen: "CONJUNCTION",
1324
+ variant: "FUNCTION",
1325
+ inputs: {
1326
+ execute: { dataType: "STEP", label: "Execute" },
1327
+ duration: { dataType: "STRING", label: 'How long the run sleeps before it goes on (e.g. "30s", "2h", "3d")', tsType: "string" }
1328
+ },
1329
+ outputs: {
1330
+ wokeAt: { dataType: "STRING", label: "When the run went on, as an ISO 8601 time", tsType: "string" },
1331
+ onSuccess: { dataType: "STEP", label: "On Success", isControlFlow: true },
1332
+ onFailure: { dataType: "STEP", label: "On Failure", isControlFlow: true, failure: true }
1333
+ },
1334
+ helperText: `
1335
+ function __fw_getMockConfig(runtime?: NodeExecutionRuntime): FwMockConfig | undefined {
1336
+ return runtime?.runtime.services.mocks;
1337
+ }
1338
+
1339
+ function __fw_lookupMock<T>(
1340
+ section: Record<string, T> | undefined,
1341
+ key: string,
1342
+ runtime?: NodeExecutionRuntime,
1343
+ ): T | undefined {
1344
+ if (!section) return undefined;
1345
+
1346
+ const nodeId = runtime?.nodeId;
1347
+ if (nodeId) {
1348
+ const qualified = section[\`\${nodeId}:\${key}\`];
1349
+ if (qualified !== undefined) return qualified;
1350
+ const any = section[\`\${nodeId}:*\`];
1351
+ if (any !== undefined) return any;
1352
+ }
1353
+
1354
+ return section[key];
1355
+ }
1356
+ `.trim(),
1357
+ helperTextProduction: void 0,
1358
+ functionText: `
1359
+ async function sleep(
1360
+ execute: boolean,
1361
+ duration: string,
1362
+ runtime?: NodeExecutionRuntime,
1363
+ ): Promise<{ onSuccess: boolean; onFailure: boolean; wokeAt: string }> {
1364
+ if (!execute) return { onSuccess: false, onFailure: false, wokeAt: '' };
1365
+
1366
+ // A timer gate. The compiler replaces this call with a durable yield, and
1367
+ // whoever keeps the run (the coordinator's clock, or a host of its own)
1368
+ // resumes it once \`duration\` has passed; under test \`fast\` wakes it at
1369
+ // once (see \`FwMockConfig\` in \`src/built-in-nodes/mock-types.ts\`).
1370
+ // Reaching this body means the generated program did not apply the gate
1371
+ // boundary, so it fails closed. A wait that holds the process is what
1372
+ // \`delay\` is for.
1373
+ void duration;
1374
+ void runtime;
1375
+ throw new Error('sleep requires a generated durable timer gate');
1376
+ }
1377
+ `.trim(),
1378
+ functionTextProduction: `
1379
+ async function sleep(
1380
+ execute: boolean,
1381
+ duration: string,
1382
+ runtime?: NodeExecutionRuntime,
1383
+ ): Promise<{ onSuccess: boolean; onFailure: boolean; wokeAt: string }> {
1384
+ if (!execute) return { onSuccess: false, onFailure: false, wokeAt: '' };
1385
+
1386
+ // A timer gate. The compiler replaces this call with a durable yield, and
1387
+ // whoever keeps the run (the coordinator's clock, or a host of its own)
1388
+ // resumes it once \`duration\` has passed; under test \`fast\` wakes it at
1389
+ // Reaching this body means the generated program did not apply the gate
1390
+ // boundary, so it fails closed. A wait that holds the process is what
1391
+ // \`delay\` is for.
1392
+ void duration;
1393
+ void runtime;
1394
+ throw new Error('sleep requires a generated durable timer gate');
1395
+ }
1396
+ `.trim()
1397
+ },
1398
+ {
1399
+ type: "NodeType",
1400
+ name: "waitForEvent",
1401
+ functionName: "waitForEvent",
1402
+ isAsync: true,
1403
+ receivesAbortSignal: false,
1404
+ receivesRuntime: true,
1405
+ durableGate: "input",
1406
+ hasSuccessPort: true,
1407
+ hasFailurePort: true,
1408
+ executeWhen: "CONJUNCTION",
1409
+ variant: "FUNCTION",
1410
+ inputs: {
1411
+ execute: { dataType: "STEP", label: "Execute" },
1412
+ eventName: { dataType: "STRING", label: 'Event name to wait for (e.g. "app/approval.received")', tsType: "string" },
1413
+ match: { dataType: "STRING", label: 'Field to match between trigger and waited event (e.g. "data.requestId")', tsType: "string", optional: true },
1414
+ timeout: { dataType: "STRING", label: 'Max wait time (e.g. "24h", "7d"). Empty = no timeout', tsType: "string", optional: true }
1415
+ },
1416
+ outputs: {
1417
+ eventData: { dataType: "OBJECT", label: "The received event's data payload", tsType: "object" },
1418
+ onSuccess: { dataType: "STEP", label: "On Success", isControlFlow: true },
1419
+ onFailure: { dataType: "STEP", label: "On Failure", isControlFlow: true, failure: true }
1420
+ },
1421
+ helperText: `
1422
+ function __fw_getMockConfig(runtime?: NodeExecutionRuntime): FwMockConfig | undefined {
1423
+ return runtime?.runtime.services.mocks;
1424
+ }
1425
+
1426
+ function __fw_lookupMock<T>(
1427
+ section: Record<string, T> | undefined,
1428
+ key: string,
1429
+ runtime?: NodeExecutionRuntime,
1430
+ ): T | undefined {
1431
+ if (!section) return undefined;
1432
+
1433
+ const nodeId = runtime?.nodeId;
1434
+ if (nodeId) {
1435
+ const qualified = section[\`\${nodeId}:\${key}\`];
1436
+ if (qualified !== undefined) return qualified;
1437
+ const any = section[\`\${nodeId}:*\`];
1438
+ if (any !== undefined) return any;
1439
+ }
1440
+
1441
+ return section[key];
1442
+ }
1443
+ `.trim(),
1444
+ helperTextProduction: void 0,
1445
+ functionText: `
1446
+ async function waitForEvent(
1447
+ execute: boolean,
1448
+ eventName: string,
1449
+ match?: string,
1450
+ timeout?: string,
1451
+ runtime?: NodeExecutionRuntime,
1452
+ ): Promise<{ onSuccess: boolean; onFailure: boolean; eventData: object }> {
1453
+ if (!execute) return { onSuccess: false, onFailure: false, eventData: {} };
1454
+
1455
+ // An input gate. The compiler replaces this call with a durable yield, and
1456
+ // the engine answers the gate: from a person, or under test from the run's
1457
+ // canned answers (see \`FwMockConfig\` in \`src/built-in-nodes/mock-types.ts\`
1458
+ // for how those are read). Reaching this body means the generated program
1459
+ // did not apply the gate boundary, so it fails closed.
1460
+ void eventName;
1461
+ void match;
1462
+ void timeout;
1463
+ void runtime;
1464
+ throw new Error('waitForEvent requires a generated durable input gate');
1465
+ }
1466
+ `.trim(),
1467
+ functionTextProduction: `
1468
+ async function waitForEvent(
1469
+ execute: boolean,
1470
+ eventName: string,
1471
+ match?: string,
1472
+ timeout?: string,
1473
+ runtime?: NodeExecutionRuntime,
1474
+ ): Promise<{ onSuccess: boolean; onFailure: boolean; eventData: object }> {
1475
+ if (!execute) return { onSuccess: false, onFailure: false, eventData: {} };
1476
+
1477
+ // An input gate. The compiler replaces this call with a durable yield, and
1478
+ // the engine answers the gate: from a person, or under test from the run's
1479
+ // for how those are read). Reaching this body means the generated program
1480
+ // did not apply the gate boundary, so it fails closed.
1481
+ void eventName;
1482
+ void match;
1483
+ void timeout;
1484
+ void runtime;
1485
+ throw new Error('waitForEvent requires a generated durable input gate');
1486
+ }
1487
+ `.trim()
1488
+ },
1489
+ {
1490
+ type: "NodeType",
1491
+ name: "invokeWorkflow",
1492
+ functionName: "invokeWorkflow",
1493
+ isAsync: true,
1494
+ receivesAbortSignal: true,
1495
+ receivesRuntime: true,
1496
+ durablePure: true,
1497
+ hasSuccessPort: true,
1498
+ hasFailurePort: true,
1499
+ executeWhen: "CONJUNCTION",
1500
+ variant: "FUNCTION",
1501
+ inputs: {
1502
+ execute: { dataType: "STEP", label: "Execute" },
1503
+ functionId: { dataType: "STRING", label: 'Function ID of the workflow to invoke (e.g. "my-service/sub-workflow")', tsType: "string" },
1504
+ payload: { dataType: "OBJECT", label: "Data to pass as event.data to the invoked function", tsType: "object" },
1505
+ timeout: { dataType: "STRING", label: 'Max wait time (e.g. "1h")', tsType: "string", optional: true }
1506
+ },
1507
+ outputs: {
1508
+ result: { dataType: "OBJECT", label: "Return value from the invoked function", tsType: "object" },
1509
+ onSuccess: { dataType: "STEP", label: "On Success", isControlFlow: true },
1510
+ onFailure: { dataType: "STEP", label: "On Failure", isControlFlow: true, failure: true }
1511
+ },
1512
+ helperText: `
1513
+ function __fw_getMockConfig(runtime?: NodeExecutionRuntime): FwMockConfig | undefined {
1514
+ return runtime?.runtime.services.mocks;
1515
+ }
1516
+
1517
+ function __fw_lookupMock<T>(
1518
+ section: Record<string, T> | undefined,
1519
+ key: string,
1520
+ runtime?: NodeExecutionRuntime,
1521
+ ): T | undefined {
1522
+ if (!section) return undefined;
1523
+
1524
+ const nodeId = runtime?.nodeId;
1525
+ if (nodeId) {
1526
+ const qualified = section[\`\${nodeId}:\${key}\`];
1527
+ if (qualified !== undefined) return qualified;
1528
+ const any = section[\`\${nodeId}:*\`];
1529
+ if (any !== undefined) return any;
1530
+ }
1531
+
1532
+ return section[key];
1533
+ }
1534
+ `.trim(),
1535
+ helperTextProduction: void 0,
1536
+ functionText: `
1537
+ async function invokeWorkflow(
1538
+ execute: boolean,
1539
+ functionId: string,
1540
+ payload: object,
1541
+ timeout?: string,
1542
+ abortSignal?: AbortSignal,
1543
+ runtime?: NodeExecutionRuntime,
1544
+ ): Promise<{ onSuccess: boolean; onFailure: boolean; result: object }> {
1545
+ if (!execute) return { onSuccess: false, onFailure: false, result: {} };
1546
+
1547
+ const mocks = __fw_getMockConfig(runtime);
1548
+ if (mocks) {
1549
+ // Mock mode: look up result by functionId (supports instance-qualified keys)
1550
+ const mockResult = __fw_lookupMock(mocks.invocations, functionId, runtime);
1551
+ if (mockResult !== undefined) {
1552
+ return { onSuccess: true, onFailure: false, result: mockResult };
1553
+ }
1554
+ // No mock data for this functionId, so simulate failure
1555
+ return { onSuccess: false, onFailure: true, result: {} };
1556
+ }
1557
+
1558
+ // Check local workflow registry (populated by executeWorkflow)
1559
+ const registry = runtime?.runtime.services.workflowRegistry;
1560
+ if (registry?.[functionId]) {
1561
+ const nodeRuntime = runtime!;
1562
+ if (
1563
+ !Number.isSafeInteger(nodeRuntime.recursionDepth) ||
1564
+ nodeRuntime.recursionDepth < 0 ||
1565
+ nodeRuntime.recursionDepth >= 999
1566
+ ) {
1567
+ throw new Error('Max recursion depth exceeded (1000) in dynamic workflow invocation');
1568
+ }
1569
+ try {
1570
+ const result = await registry[functionId](
1571
+ true,
1572
+ { ...payload, __rd__: nodeRuntime.recursionDepth + 1 },
1573
+ nodeRuntime.createNestedRuntime(functionId),
1574
+ );
1575
+ return { onSuccess: true, onFailure: false, result: (result as object) ?? {} };
1576
+ } catch (error) {
1577
+ const controlFlowCode =
1578
+ typeof error === 'object' && error !== null
1579
+ ? (error as { code?: unknown }).code
1580
+ : undefined;
1581
+ if (
1582
+ CancellationError.isCancellationError(error) ||
1583
+ controlFlowCode === 'FLOW_WEAVER_DURABLE_GATE_YIELD' ||
1584
+ controlFlowCode === 'FLOW_WEAVER_AMBIGUOUS_EFFECT'
1585
+ ) {
1586
+ throw error;
1587
+ }
1588
+ return { onSuccess: false, onFailure: true, result: {} };
1589
+ }
1590
+ }
1591
+
1592
+ // No mocks, no registry match: original no-op behavior (always succeeds)
1593
+ return { onSuccess: true, onFailure: false, result: {} };
1594
+ }
1595
+ `.trim(),
1596
+ functionTextProduction: `
1597
+ async function invokeWorkflow(
1598
+ execute: boolean,
1599
+ functionId: string,
1600
+ payload: object,
1601
+ timeout?: string,
1602
+ abortSignal?: AbortSignal,
1603
+ runtime?: NodeExecutionRuntime,
1604
+ ): Promise<{ onSuccess: boolean; onFailure: boolean; result: object }> {
1605
+ if (!execute) return { onSuccess: false, onFailure: false, result: {} };
1606
+
1607
+
1608
+ // Check local workflow registry (populated by executeWorkflow)
1609
+ const registry = runtime?.runtime.services.workflowRegistry;
1610
+ if (registry?.[functionId]) {
1611
+ const nodeRuntime = runtime!;
1612
+ if (
1613
+ !Number.isSafeInteger(nodeRuntime.recursionDepth) ||
1614
+ nodeRuntime.recursionDepth < 0 ||
1615
+ nodeRuntime.recursionDepth >= 999
1616
+ ) {
1617
+ throw new Error('Max recursion depth exceeded (1000) in dynamic workflow invocation');
1618
+ }
1619
+ try {
1620
+ const result = await registry[functionId](
1621
+ true,
1622
+ { ...payload, __rd__: nodeRuntime.recursionDepth + 1 },
1623
+ nodeRuntime.createNestedRuntime(functionId),
1624
+ );
1625
+ return { onSuccess: true, onFailure: false, result: (result as object) ?? {} };
1626
+ } catch (error) {
1627
+ const controlFlowCode =
1628
+ typeof error === 'object' && error !== null
1629
+ ? (error as { code?: unknown }).code
1630
+ : undefined;
1631
+ if (
1632
+ CancellationError.isCancellationError(error) ||
1633
+ controlFlowCode === 'FLOW_WEAVER_DURABLE_GATE_YIELD' ||
1634
+ controlFlowCode === 'FLOW_WEAVER_AMBIGUOUS_EFFECT'
1635
+ ) {
1636
+ throw error;
1637
+ }
1638
+ return { onSuccess: false, onFailure: true, result: {} };
1639
+ }
1640
+ }
1641
+
1642
+ return { onSuccess: true, onFailure: false, result: {} };
1643
+ }
1644
+ `.trim()
1645
+ },
1646
+ {
1647
+ type: "NodeType",
1648
+ name: "waitForAgent",
1649
+ functionName: "waitForAgent",
1650
+ isAsync: true,
1651
+ receivesAbortSignal: true,
1652
+ receivesRuntime: true,
1653
+ durableGate: "agent",
1654
+ hasSuccessPort: true,
1655
+ hasFailurePort: true,
1656
+ executeWhen: "CONJUNCTION",
1657
+ variant: "FUNCTION",
1658
+ inputs: {
1659
+ execute: { dataType: "STEP", label: "Execute" },
1660
+ agentId: { dataType: "STRING", label: "Agent/task identifier", tsType: "string" },
1661
+ context: { dataType: "OBJECT", label: "Context data to send to the agent", tsType: "object" },
1662
+ prompt: { dataType: "STRING", label: "Message to display when requesting input", tsType: "string", optional: true }
1663
+ },
1664
+ outputs: {
1665
+ agentResult: { dataType: "OBJECT", label: "Result returned by the agent", tsType: "object" },
1666
+ onSuccess: { dataType: "STEP", label: "On Success", isControlFlow: true },
1667
+ onFailure: { dataType: "STEP", label: "On Failure", isControlFlow: true, failure: true }
1668
+ },
1669
+ helperText: `
1670
+ function __fw_getMockConfig(runtime?: NodeExecutionRuntime): FwMockConfig | undefined {
1671
+ return runtime?.runtime.services.mocks;
1672
+ }
1673
+
1674
+ function __fw_lookupMock<T>(
1675
+ section: Record<string, T> | undefined,
1676
+ key: string,
1677
+ runtime?: NodeExecutionRuntime,
1678
+ ): T | undefined {
1679
+ if (!section) return undefined;
1680
+
1681
+ const nodeId = runtime?.nodeId;
1682
+ if (nodeId) {
1683
+ const qualified = section[\`\${nodeId}:\${key}\`];
1684
+ if (qualified !== undefined) return qualified;
1685
+ const any = section[\`\${nodeId}:*\`];
1686
+ if (any !== undefined) return any;
1687
+ }
1688
+
1689
+ return section[key];
1690
+ }
1691
+ `.trim(),
1692
+ helperTextProduction: void 0,
1693
+ functionText: `
1694
+ async function waitForAgent(
1695
+ execute: boolean,
1696
+ agentId: string,
1697
+ context: object,
1698
+ prompt?: string,
1699
+ _abortSignal?: AbortSignal,
1700
+ runtime?: NodeExecutionRuntime,
1701
+ ): Promise<{ onSuccess: boolean; onFailure: boolean; agentResult: object }> {
1702
+ if (!execute) return { onSuccess: false, onFailure: false, agentResult: {} };
1703
+
1704
+ // An agent gate. The compiler replaces this call with a durable yield, and
1705
+ // the engine answers the gate: from a person, or under test from the run's
1706
+ // canned answers (see \`FwMockConfig\` in \`src/built-in-nodes/mock-types.ts\`
1707
+ // for how those are read). Reaching this body means the generated program
1708
+ // did not apply the gate boundary, so it fails closed.
1709
+ void agentId;
1710
+ void context;
1711
+ void prompt;
1712
+ void runtime;
1713
+ throw new Error('waitForAgent requires a generated durable agent gate');
1714
+ }
1715
+ `.trim(),
1716
+ functionTextProduction: `
1717
+ async function waitForAgent(
1718
+ execute: boolean,
1719
+ agentId: string,
1720
+ context: object,
1721
+ prompt?: string,
1722
+ _abortSignal?: AbortSignal,
1723
+ runtime?: NodeExecutionRuntime,
1724
+ ): Promise<{ onSuccess: boolean; onFailure: boolean; agentResult: object }> {
1725
+ if (!execute) return { onSuccess: false, onFailure: false, agentResult: {} };
1726
+
1727
+ // An agent gate. The compiler replaces this call with a durable yield, and
1728
+ // the engine answers the gate: from a person, or under test from the run's
1729
+ // for how those are read). Reaching this body means the generated program
1730
+ // did not apply the gate boundary, so it fails closed.
1731
+ void agentId;
1732
+ void context;
1733
+ void prompt;
1734
+ void runtime;
1735
+ throw new Error('waitForAgent requires a generated durable agent gate');
1736
+ }
1737
+ `.trim()
1738
+ }
1739
+ ];
1740
+
1741
+ // src/parser/port-inference.ts
1742
+ import * as path from "node:path";
1743
+ function parseStartPorts(fn, config) {
1744
+ const ports = {};
1745
+ const params = fn.getParameters();
1746
+ if (params.length === 0) {
1747
+ ports.execute = { dataType: "STEP", label: "Execute" };
1748
+ return ports;
1749
+ }
1750
+ const firstParam = params[0];
1751
+ const firstParamName = firstParam.getName();
1752
+ const firstParamType = firstParam.getType();
1753
+ const firstParamTypeText = firstParamType.getText();
1754
+ const isExecutePort2 = firstParamName === "execute" && (firstParamTypeText === "boolean" || firstParamTypeText === "any" && config?.startPorts?.["execute"]);
1755
+ if (isExecutePort2) {
1756
+ if (config?.startPorts && config.startPorts["execute"]) {
1757
+ ports.execute = {
1758
+ dataType: "STEP",
1759
+ tsType: "boolean",
1760
+ ...config.startPorts["execute"]
1761
+ };
1762
+ } else {
1763
+ ports.execute = { dataType: "STEP", tsType: "boolean", label: "Execute" };
1764
+ }
1765
+ if (params.length > 1) {
1766
+ const dataParams = params.slice(1).filter(
1767
+ (p) => p.getName() !== "__runtime__" && !["AbortSignal", "TDebugger"].includes(p.getType().getText(p))
1768
+ );
1769
+ const shouldExpandProperties = dataParams.length === 1 && isExpandableObjectType(dataParams[0].getType());
1770
+ const declaresNoPorts = dataParams.length === 1 && isPropertylessObjectType(dataParams[0].getType());
1771
+ if (declaresNoPorts) {
1772
+ } else if (shouldExpandProperties) {
1773
+ const dataParam = dataParams[0];
1774
+ const dataParamType = dataParam.getType();
1775
+ const properties = dataParamType.getProperties();
1776
+ properties.forEach((prop) => {
1777
+ const propName = prop.getName();
1778
+ const propType = prop.getTypeAtLocation(dataParam);
1779
+ const portType = inferPortType(propType);
1780
+ const propTypeText = propType.getText();
1781
+ const tsSchema = portType === "OBJECT" ? extractTypeSchema(propType) : void 0;
1782
+ const startPortConfig = config?.startPorts?.[propName];
1783
+ ports[propName] = {
1784
+ dataType: portType,
1785
+ label: startPortConfig?.label || capitalize(propName),
1786
+ ...startPortConfig?.optional === true && { optional: true },
1787
+ ...startPortConfig !== void 0 && Object.hasOwn(startPortConfig, "default") ? { default: startPortConfig.default } : {},
1788
+ ...startPortConfig?.metadata && { metadata: startPortConfig.metadata },
1789
+ ...propTypeText && { tsType: propTypeText },
1790
+ ...tsSchema && Object.keys(tsSchema).length > 0 && { tsSchema }
1791
+ };
1792
+ });
1793
+ } else {
1794
+ for (const param of dataParams) {
1795
+ const paramName = param.getName();
1796
+ const paramType = param.getType();
1797
+ const portType = inferPortType(paramType);
1798
+ const rawParamTypeText = paramType.getText(param);
1799
+ const paramTypeText = param.isOptional() || param.hasInitializer() ? stripOptionalUndefined(rawParamTypeText) : rawParamTypeText;
1800
+ const tsSchema = portType === "OBJECT" ? extractTypeSchema(paramType) : void 0;
1801
+ const startPortConfig = config?.startPorts?.[paramName];
1802
+ ports[paramName] = {
1803
+ dataType: portType,
1804
+ label: startPortConfig?.label || capitalize(paramName),
1805
+ ...startPortConfig?.optional === true && { optional: true },
1806
+ ...startPortConfig !== void 0 && Object.hasOwn(startPortConfig, "default") ? { default: startPortConfig.default } : {},
1807
+ ...startPortConfig?.metadata && { metadata: startPortConfig.metadata },
1808
+ ...paramTypeText && { tsType: paramTypeText },
1809
+ ...tsSchema && Object.keys(tsSchema).length > 0 && { tsSchema }
1810
+ };
1811
+ }
1812
+ }
1813
+ }
1814
+ } else {
1815
+ throw new Error(
1816
+ `Invalid workflow function signature for "${fn.getName()}". Expected first parameter to be "execute: boolean", but got "${firstParamName}: ${firstParamTypeText}". Correct format: export function ${fn.getName()}(execute: boolean, params: {...}): { onSuccess: boolean; onFailure: boolean; ... }`
1817
+ );
1818
+ }
1819
+ assignImplicitPortOrders(ports);
1820
+ return ports;
1821
+ }
1822
+ function parseExitPorts(fn, config, warnings) {
1823
+ const ports = {};
1824
+ let returnType = fn.getReturnType();
1825
+ const typeText = returnType?.getText();
1826
+ const sourceFile = fn.getSourceFile();
1827
+ const filePath = sourceFile?.getFilePath() || "unknown file";
1828
+ const fileName = path.basename(filePath);
1829
+ if (!typeText || typeText === "void") {
1830
+ warnings?.push(
1831
+ `Could not determine the return type of workflow "${fn.getName()}" in ${fileName}, so it has no Exit ports. Add an explicit return type like: Promise<{ onSuccess: boolean; onFailure: boolean }>`
1832
+ );
1833
+ return ports;
1834
+ }
1835
+ if (typeText.startsWith("Promise<")) {
1836
+ const typeArgs = returnType.getTypeArguments();
1837
+ if (typeArgs && typeArgs.length > 0) {
1838
+ returnType = typeArgs[0];
1839
+ }
1840
+ }
1841
+ const properties = returnType.getProperties();
1842
+ properties.forEach((prop) => {
1843
+ const propName = prop.getName();
1844
+ if (propName === "onSuccess" || propName === "onFailure") {
1845
+ const returnPortConfig = config?.returnPorts?.[propName];
1846
+ ports[propName] = {
1847
+ dataType: "STEP",
1848
+ label: returnPortConfig?.label || (propName === "onSuccess" ? "On Success" : "On Failure"),
1849
+ isControlFlow: true,
1850
+ ...propName === "onFailure" && { failure: true },
1851
+ ...returnPortConfig?.metadata && { metadata: returnPortConfig.metadata }
1852
+ };
1853
+ } else {
1854
+ const propType = prop.getTypeAtLocation(fn.getTypeResolutionNode());
1855
+ const portType = inferPortType(propType);
1856
+ const propTypeText = propType.getText();
1857
+ const tsSchema = portType === "OBJECT" ? extractTypeSchema(propType) : void 0;
1858
+ const returnPortConfig = config?.returnPorts?.[propName];
1859
+ ports[propName] = {
1860
+ dataType: portType,
1861
+ label: returnPortConfig?.label || capitalize(propName),
1862
+ ...returnPortConfig?.metadata && { metadata: returnPortConfig.metadata },
1863
+ // Include original TS type for rich type display (e.g., "ResearchReport" instead of "object")
1864
+ ...propTypeText && propTypeText !== portType.toLowerCase() && { tsType: propTypeText },
1865
+ // Include schema breakdown for complex types
1866
+ ...tsSchema && Object.keys(tsSchema).length > 0 && { tsSchema }
1867
+ };
1868
+ }
1869
+ });
1870
+ assignImplicitPortOrders(ports);
1871
+ return ports;
1872
+ }
1873
+ function extractTypeSchema(tsType) {
1874
+ const schema = {};
1875
+ const properties = tsType.getProperties();
1876
+ if (!properties || properties.length === 0) {
1877
+ return void 0;
1878
+ }
1879
+ for (const prop of properties) {
1880
+ const propName = prop.getName();
1881
+ if (propName.startsWith("_")) continue;
1882
+ const propType = prop.getValueDeclaration()?.getType();
1883
+ if (propType) {
1884
+ schema[propName] = propType.getText();
1885
+ } else {
1886
+ const declarations = prop.getDeclarations();
1887
+ if (declarations && declarations.length > 0) {
1888
+ const decl = declarations[0];
1889
+ schema[propName] = decl.getType().getText();
1890
+ }
1891
+ }
1892
+ }
1893
+ return Object.keys(schema).length > 0 ? schema : void 0;
1894
+ }
1895
+ function isPropertylessObjectType(tsType) {
1896
+ return tsType.isObject() && !tsType.isArray() && tsType.getCallSignatures().length === 0 && tsType.getProperties().length === 0;
1897
+ }
1898
+ function isExpandableObjectType(tsType) {
1899
+ const typeText = tsType.getText();
1900
+ const primitiveTypes = /* @__PURE__ */ new Set(["string", "number", "boolean", "any", "unknown", "never", "object", "Object"]);
1901
+ if (primitiveTypes.has(typeText)) return false;
1902
+ if (typeText.endsWith("[]") || typeText.startsWith("Array<")) return false;
1903
+ return tsType.isObject() && tsType.getProperties().length > 0;
1904
+ }
1905
+ function inferPortType(tsType) {
1906
+ const typeText = tsType.getText();
1907
+ return inferDataTypeFromTS(typeText);
1908
+ }
1909
+ function capitalize(str) {
1910
+ return str.charAt(0).toUpperCase() + str.slice(1);
1911
+ }
1912
+
1913
+ // src/parser/durable-effect-contract.ts
1914
+ function jsDocTagComment(fn, tagName) {
1915
+ for (const doc of fn.getJsDocs()) {
1916
+ for (const tag of doc.getTags()) {
1917
+ if (tag.getTagName() === tagName) {
1918
+ return tag.getCommentText?.()?.trim() ?? "";
1919
+ }
1920
+ }
1921
+ }
1922
+ return void 0;
1923
+ }
1924
+ function hasJsDocTag(fn, tagName) {
1925
+ return jsDocTagComment(fn, tagName) !== void 0;
1926
+ }
1927
+ function durableGateKind(fn) {
1928
+ const kind = jsDocTagComment(fn, "durableGate")?.split(/\s+/)[0];
1929
+ return kind === "approval" || kind === "input" || kind === "agent" || kind === "timer" ? kind : void 0;
1930
+ }
1931
+ function describeType(type, fn) {
1932
+ return type.getText(fn.getTypeResolutionNode());
1933
+ }
1934
+ function nonUndefinedUnionMembers(type) {
1935
+ const members = type.isUnion() ? type.getUnionTypes() : [type];
1936
+ return members.filter((member) => !member.isUndefined());
1937
+ }
1938
+ function wireTypeFailure(type, path4 = "$", seen = /* @__PURE__ */ new Set()) {
1939
+ const identity = type.compilerType;
1940
+ if (seen.has(identity)) return void 0;
1941
+ seen.add(identity);
1942
+ const members = nonUndefinedUnionMembers(type);
1943
+ if (members.length === 0) return `${path4} has no defined member`;
1944
+ if (members.length > 1 || type.isUnion()) {
1945
+ for (const member of members) {
1946
+ const failure = wireTypeFailure(member, path4, new Set(seen));
1947
+ if (failure !== void 0) return failure;
1948
+ }
1949
+ return void 0;
1950
+ }
1951
+ const candidate = members[0];
1952
+ if (candidate.isAny() || candidate.isUnknown() || candidate.isNever() || candidate.isVoid() || candidate.isBigInt() || candidate.isBigIntLiteral()) {
1953
+ return `${path4} is ${candidate.getText()}`;
1954
+ }
1955
+ if (candidate.isNull() || candidate.isString() || candidate.isStringLiteral() || candidate.isNumber() || candidate.isNumberLiteral() || candidate.isBoolean() || candidate.isBooleanLiteral() || candidate.isTemplateLiteral()) {
1956
+ return void 0;
1957
+ }
1958
+ if (candidate.isTuple()) {
1959
+ for (const [index, element] of candidate.getTupleElements().entries()) {
1960
+ const failure = wireTypeFailure(element, `${path4}[${index}]`, new Set(seen));
1961
+ if (failure !== void 0) return failure;
1962
+ }
1963
+ return void 0;
1964
+ }
1965
+ if (candidate.isArray() || candidate.isReadonlyArray()) {
1966
+ const element = candidate.getArrayElementType();
1967
+ return element === void 0 ? `${path4} has no array element type` : wireTypeFailure(element, `${path4}[]`, new Set(seen));
1968
+ }
1969
+ if (!candidate.isObject() || candidate.isClass()) return `${path4} is not a plain object`;
1970
+ if (candidate.getCallSignatures().length > 0 || candidate.getConstructSignatures().length > 0) {
1971
+ return `${path4} is callable or constructable`;
1972
+ }
1973
+ const indexTypes = [
1974
+ candidate.getStringIndexType(),
1975
+ candidate.getNumberIndexType()
1976
+ ].filter((indexType) => indexType !== void 0);
1977
+ for (const indexType of indexTypes) {
1978
+ const failure = wireTypeFailure(indexType, `${path4}[key]`, new Set(seen));
1979
+ if (failure !== void 0) return failure;
1980
+ }
1981
+ for (const property of candidate.getProperties()) {
1982
+ const location = property.getValueDeclaration() ?? property.getDeclarations()[0];
1983
+ if (location === void 0) return `${path4}.${property.getName()} has no declaration`;
1984
+ const failure = wireTypeFailure(
1985
+ property.getTypeAtLocation(location),
1986
+ `${path4}.${property.getName()}`,
1987
+ new Set(seen)
1988
+ );
1989
+ if (failure !== void 0) return failure;
1990
+ }
1991
+ return void 0;
1992
+ }
1993
+ function matchesPortType(type, dataType) {
1994
+ const members = nonUndefinedUnionMembers(type);
1995
+ if (members.length === 0) return false;
1996
+ return members.every((member) => {
1997
+ switch (dataType) {
1998
+ case "STRING":
1999
+ return member.isString() || member.isStringLiteral() || member.isTemplateLiteral();
2000
+ case "NUMBER":
2001
+ return member.isNumber() || member.isNumberLiteral();
2002
+ case "BOOLEAN":
2003
+ case "STEP":
2004
+ return member.isBoolean() || member.isBooleanLiteral();
2005
+ case "ARRAY":
2006
+ return member.isArray() || member.isReadonlyArray() || member.isTuple();
2007
+ case "OBJECT":
2008
+ return member.isObject() && !member.isArray() && !member.isReadonlyArray();
2009
+ case "FUNCTION":
2010
+ return member.getCallSignatures().length > 0;
2011
+ case "ANY":
2012
+ return true;
2013
+ }
2014
+ });
2015
+ }
2016
+ function validateEnvelopeMember(envelope, outputs, fn) {
2017
+ const diagnostics = [];
2018
+ if (!envelope.isObject() || envelope.isArray() || envelope.isReadonlyArray()) {
2019
+ return [
2020
+ `return type must be exactly { receipt, result }, got ${describeType(envelope, fn)}`
2021
+ ];
2022
+ }
2023
+ if (envelope.getStringIndexType() || envelope.getNumberIndexType()) {
2024
+ diagnostics.push("return envelope must not declare an index signature");
2025
+ }
2026
+ const envelopeProperties = envelope.getProperties();
2027
+ const envelopeNames = envelopeProperties.map((property) => property.getName()).sort();
2028
+ if (envelopeNames.join(",") !== "receipt,result") {
2029
+ diagnostics.push(
2030
+ `return envelope must have exactly the required receipt and result fields. Found ${envelopeNames.join(", ") || "none"}`
2031
+ );
2032
+ }
2033
+ const receiptProperty = envelope.getProperty("receipt");
2034
+ const resultProperty = envelope.getProperty("result");
2035
+ if (receiptProperty?.isOptional()) diagnostics.push("receipt must be required");
2036
+ if (resultProperty?.isOptional()) diagnostics.push("result must be required");
2037
+ const location = fn.getTypeResolutionNode();
2038
+ if (receiptProperty) {
2039
+ const receiptType = receiptProperty.getTypeAtLocation(location);
2040
+ const failure = wireTypeFailure(receiptType);
2041
+ if (failure !== void 0) {
2042
+ diagnostics.push(
2043
+ `receipt must be a durable wire value, got ${describeType(receiptType, fn)} (${failure})`
2044
+ );
2045
+ }
2046
+ }
2047
+ if (!resultProperty) {
2048
+ const expectedNames2 = Object.entries(outputs).filter(([, output]) => output.scope === void 0).map(([name]) => name).sort();
2049
+ const plainResultNames = envelopeProperties.map((property) => property.getName()).sort();
2050
+ const missing = expectedNames2.filter((name) => !plainResultNames.includes(name));
2051
+ const extra = plainResultNames.filter((name) => !expectedNames2.includes(name));
2052
+ diagnostics.push(
2053
+ [
2054
+ "result fields must exactly match the node outputs",
2055
+ missing.length > 0 ? `missing ${missing.join(", ")}` : void 0,
2056
+ extra.length > 0 ? `unexpected ${extra.join(", ")}` : void 0
2057
+ ].filter(Boolean).join("; ")
2058
+ );
2059
+ return diagnostics;
2060
+ }
2061
+ const resultType = resultProperty.getTypeAtLocation(location);
2062
+ if (!resultType.isObject() || resultType.isArray() || resultType.isReadonlyArray()) {
2063
+ diagnostics.push(
2064
+ `result must be an object matching the node outputs, got ${describeType(resultType, fn)}`
2065
+ );
2066
+ return diagnostics;
2067
+ }
2068
+ const resultFailure = wireTypeFailure(resultType);
2069
+ if (resultFailure !== void 0) {
2070
+ diagnostics.push(
2071
+ `result must be a durable wire value, got ${describeType(resultType, fn)} (${resultFailure})`
2072
+ );
2073
+ }
2074
+ const expectedNames = Object.entries(outputs).filter(([, output]) => output.scope === void 0).map(([name]) => name).sort();
2075
+ const actualNames = resultType.getProperties().map((property) => property.getName()).sort();
2076
+ if (actualNames.join(",") !== expectedNames.join(",")) {
2077
+ const missing = expectedNames.filter((name) => !actualNames.includes(name));
2078
+ const extra = actualNames.filter((name) => !expectedNames.includes(name));
2079
+ diagnostics.push(
2080
+ [
2081
+ "result fields must exactly match the node outputs",
2082
+ missing.length > 0 ? `missing ${missing.join(", ")}` : void 0,
2083
+ extra.length > 0 ? `unexpected ${extra.join(", ")}` : void 0
2084
+ ].filter(Boolean).join("; ")
2085
+ );
2086
+ }
2087
+ for (const [name, output] of Object.entries(outputs)) {
2088
+ if (output.scope !== void 0) continue;
2089
+ const property = resultType.getProperty(name);
2090
+ if (!property) continue;
2091
+ if (property.isOptional()) {
2092
+ diagnostics.push(`result.${name} must be required`);
2093
+ continue;
2094
+ }
2095
+ const propertyType = property.getTypeAtLocation(location);
2096
+ if (!matchesPortType(propertyType, output.dataType)) {
2097
+ diagnostics.push(
2098
+ `result.${name} is ${describeType(propertyType, fn)}, incompatible with ${output.dataType}`
2099
+ );
2100
+ }
2101
+ }
2102
+ return diagnostics;
2103
+ }
2104
+ function analyzeDurableEffectContract(fn, inputs, outputs) {
2105
+ const diagnostics = [];
2106
+ const parameters = fn.getParameters();
2107
+ const operationKey = parameters.at(-1);
2108
+ if (!operationKey) {
2109
+ diagnostics.push("callable must accept a required final operationKey: string parameter");
2110
+ } else {
2111
+ if (operationKey.isOptional() || operationKey.hasInitializer() || operationKey.isRestParameter()) {
2112
+ diagnostics.push("final operationKey parameter must be required and non-rest");
2113
+ }
2114
+ const operationKeyType = operationKey.getType();
2115
+ if (!operationKeyType.isString() || operationKeyType.isStringLiteral()) {
2116
+ diagnostics.push(
2117
+ `final operationKey parameter must be string, got ${describeType(operationKeyType, fn)}`
2118
+ );
2119
+ }
2120
+ if (Object.hasOwn(inputs, operationKey.getName())) {
2121
+ diagnostics.push(
2122
+ "callable must accept an injected final operationKey: string after every declared node input"
2123
+ );
2124
+ }
2125
+ }
2126
+ const declaredReturn = fn.getReturnType();
2127
+ const resolvedReturn = declaredReturn.getAwaitedType() ?? declaredReturn;
2128
+ const returnMembers = resolvedReturn.isUnion() ? resolvedReturn.getUnionTypes() : [resolvedReturn];
2129
+ for (const returnMember of returnMembers) {
2130
+ diagnostics.push(...validateEnvelopeMember(returnMember, outputs, fn));
2131
+ }
2132
+ return { valid: diagnostics.length === 0, diagnostics };
2133
+ }
2134
+
2135
+ // src/parser/node-inference.ts
2136
+ function returnsPromise(fn) {
2137
+ return fn.isAsync() || fn.getReturnType().getText().startsWith("Promise<");
2138
+ }
2139
+ function extractNodeTypes(sourceFile, warnings, tagRegistry) {
2140
+ const nodeTypes = [];
2141
+ warnings.push(...nestedAnnotationWarnings(sourceFile));
2142
+ extractFunctionLikes(sourceFile).forEach((fn) => {
2143
+ const config = jsdocParser.parseNodeType(fn, warnings, tagRegistry);
2144
+ if (!config) {
2145
+ const jsdocText = fn.getJsDocs().map((d) => d.getFullText()).join("");
2146
+ if (jsdocText.includes("@flowWeaver nodeType")) {
2147
+ warnings.push(
2148
+ `Function "${fn.getName() || "anonymous"}" has @flowWeaver annotation but could not be parsed. Check for special characters (---) or malformed JSDoc syntax.`
2149
+ );
2150
+ }
2151
+ return;
2152
+ }
2153
+ const functionName = fn.getName() || "anonymous";
2154
+ const nodeTypeName = config.name || functionName;
2155
+ const durableGate = durableGateKind(fn);
2156
+ const durableEffect = hasJsDocTag(fn, "durableEffect");
2157
+ const durablePure = hasJsDocTag(fn, "durablePure");
2158
+ const builtIn = BUILT_IN_NODE_TYPES.find((nt) => nt.functionName === functionName);
2159
+ const paramTypes = builtIn ? fn.getParameters().map((p) => p.getTypeNode()?.getText()) : [];
2160
+ const receivesAbortSignal = builtIn?.receivesAbortSignal === true && paramTypes.includes("AbortSignal");
2161
+ const receivesRuntime = builtIn?.receivesRuntime === true && paramTypes.includes("NodeExecutionRuntime");
2162
+ const inputs = {};
2163
+ if (config.inputs) {
2164
+ for (const [portName, portDef] of Object.entries(config.inputs)) {
2165
+ inputs[portName] = {
2166
+ dataType: portDef.type,
2167
+ default: portDef.defaultValue,
2168
+ optional: portDef.optional,
2169
+ label: portDef.label,
2170
+ expression: portDef.expression,
2171
+ ...portDef.scope && { scope: portDef.scope },
2172
+ ...portDef.hidden && { hidden: portDef.hidden },
2173
+ ...portDef.metadata && { metadata: portDef.metadata },
2174
+ ...portDef.tsType && { tsType: portDef.tsType },
2175
+ // The fan-in strategy is what lets the validator accept several
2176
+ // connections into this port and tells the generator how to combine
2177
+ // them. Dropping it here silently turned every strategy into FIRST.
2178
+ ...portDef.mergeStrategy && { mergeStrategy: portDef.mergeStrategy }
2179
+ };
2180
+ }
2181
+ }
2182
+ const outputs = {};
2183
+ if (config.outputs) {
2184
+ for (const [portName, portDef] of Object.entries(config.outputs)) {
2185
+ outputs[portName] = {
2186
+ dataType: portDef.type,
2187
+ label: portDef.label,
2188
+ ...portDef.scope && { scope: portDef.scope },
2189
+ ...portDef.hidden && { hidden: portDef.hidden },
2190
+ ...portDef.metadata && { metadata: portDef.metadata },
2191
+ ...portDef.tsType && { tsType: portDef.tsType }
2192
+ };
2193
+ }
2194
+ }
2195
+ const isStub = fn.isAmbient?.() ?? false;
2196
+ if (isStub) {
2197
+ config.expression = true;
2198
+ }
2199
+ if (config.expression) {
2200
+ const inferred = inferNodeTypeFromFunction(
2201
+ fn,
2202
+ nodeTypeName,
2203
+ fn.getSourceFile().getFilePath()
2204
+ );
2205
+ const reconcile = (explicit, inferredPorts, isControl) => {
2206
+ const explicitData = Object.entries(explicit).filter(([name]) => !isControl(name));
2207
+ const inferredData = Object.entries(inferredPorts).filter(([name]) => !isControl(name));
2208
+ if (explicitData.length === 0) return Object.fromEntries(inferredData);
2209
+ const inferredNames = new Set(inferredData.map(([name]) => name));
2210
+ const isPartial = explicitData.length < inferredData.length && explicitData.every(([name]) => inferredNames.has(name));
2211
+ if (!isPartial) return Object.fromEntries(explicitData);
2212
+ const explicitByName = new Map(explicitData);
2213
+ return Object.fromEntries(
2214
+ inferredData.map(([name, port]) => {
2215
+ const override = explicitByName.get(name);
2216
+ if (!override) return [name, port];
2217
+ const refined = { ...port };
2218
+ for (const [key, value] of Object.entries(override)) {
2219
+ if (value === void 0) continue;
2220
+ if (key === "dataType" && value === "ANY") continue;
2221
+ if (key === "label" && typeof value === "string" && value.length === 0) continue;
2222
+ refined[key] = value;
2223
+ }
2224
+ return [name, refined];
2225
+ })
2226
+ );
2227
+ };
2228
+ const reconciledInputs = reconcile(inputs, inferred.inputs, (n) => n === "execute");
2229
+ const reconciledOutputs = reconcile(outputs, inferred.outputs, (n) => n === "onSuccess" || n === "onFailure");
2230
+ for (const key of Object.keys(inputs)) if (key !== "execute") delete inputs[key];
2231
+ for (const key of Object.keys(outputs)) if (key !== "onSuccess" && key !== "onFailure") delete outputs[key];
2232
+ Object.assign(inputs, reconciledInputs);
2233
+ Object.assign(outputs, reconciledOutputs);
2234
+ }
2235
+ inputs.execute = {
2236
+ label: "Execute",
2237
+ // Default label
2238
+ ...inputs.execute,
2239
+ // User can override label
2240
+ dataType: "STEP"
2241
+ // But dataType is mandatory
2242
+ };
2243
+ outputs.onSuccess = {
2244
+ label: "On Success",
2245
+ // Default label
2246
+ ...outputs.onSuccess,
2247
+ // User can override label
2248
+ dataType: "STEP",
2249
+ // But dataType is mandatory
2250
+ isControlFlow: true
2251
+ // Always a control flow port
2252
+ };
2253
+ outputs.onFailure = {
2254
+ label: "On Failure",
2255
+ // Default label
2256
+ ...outputs.onFailure,
2257
+ // User can override label
2258
+ dataType: "STEP",
2259
+ // But dataType is mandatory
2260
+ failure: true,
2261
+ // Always a failure port
2262
+ isControlFlow: true
2263
+ // Always a control flow port
2264
+ };
2265
+ assignImplicitPortOrders(inputs);
2266
+ assignImplicitPortOrders(outputs);
2267
+ const jsDocs = fn.getJsDocs();
2268
+ const jsDocText = jsDocs.map((doc) => doc.getText()).join("\n");
2269
+ const functionText = isStub ? void 0 : jsDocText ? `${jsDocText}
2270
+ ${fn.getText()}` : fn.getText();
2271
+ const durableEffectContract = durableEffect ? analyzeDurableEffectContract(fn, inputs, outputs) : void 0;
2272
+ const isAsync = returnsPromise(fn);
2273
+ let defaultConfig = void 0;
2274
+ if (config.defaultConfig) {
2275
+ defaultConfig = {
2276
+ label: config.defaultConfig.label,
2277
+ description: config.defaultConfig.description,
2278
+ pullExecution: config.defaultConfig.pullExecution
2279
+ };
2280
+ }
2281
+ const portScopes = /* @__PURE__ */ new Set();
2282
+ Object.values(inputs).forEach((port) => {
2283
+ if (port.scope) portScopes.add(port.scope);
2284
+ });
2285
+ Object.values(outputs).forEach((port) => {
2286
+ if (port.scope) portScopes.add(port.scope);
2287
+ });
2288
+ let scopes;
2289
+ if (config.scope) {
2290
+ scopes = [config.scope];
2291
+ } else if (portScopes.size > 0) {
2292
+ const orderedScopes = [];
2293
+ try {
2294
+ const params = fn.getParameters();
2295
+ for (const param of params) {
2296
+ const paramName = param.getName();
2297
+ if (portScopes.has(paramName)) {
2298
+ orderedScopes.push(paramName);
2299
+ }
2300
+ }
2301
+ } catch {
2302
+ }
2303
+ for (const scope of portScopes) {
2304
+ if (!orderedScopes.includes(scope)) {
2305
+ orderedScopes.push(scope);
2306
+ }
2307
+ }
2308
+ scopes = orderedScopes;
2309
+ }
2310
+ nodeTypes.push({
2311
+ type: "NodeType",
2312
+ name: nodeTypeName,
2313
+ functionName,
2314
+ variant: isStub ? "STUB" : "FUNCTION",
2315
+ inputs,
2316
+ outputs,
2317
+ hasSuccessPort: RESERVED_PORT_NAMES.ON_SUCCESS in outputs,
2318
+ hasFailurePort: RESERVED_PORT_NAMES.ON_FAILURE in outputs,
2319
+ isAsync,
2320
+ functionText,
2321
+ ...durableGate && { durableGate },
2322
+ ...durableEffect && { durableEffect: true },
2323
+ ...durableEffectContract && { durableEffectContract },
2324
+ ...durablePure && { durablePure: true },
2325
+ ...receivesAbortSignal && { receivesAbortSignal: true },
2326
+ ...receivesRuntime && { receivesRuntime: true },
2327
+ ...config.resilience && { resilience: config.resilience },
2328
+ executeWhen: config.executeWhen || EXECUTION_STRATEGIES.CONJUNCTION,
2329
+ defaultConfig,
2330
+ scope: config.scope,
2331
+ scopes,
2332
+ ...config.expression && { expression: true },
2333
+ ...fn.getDeclarationKind?.() && { declarationKind: fn.getDeclarationKind() },
2334
+ label: config.label,
2335
+ description: config.description,
2336
+ visuals: config.color || config.icon || config.tags ? {
2337
+ color: config.color,
2338
+ icon: config.icon,
2339
+ tags: config.tags
2340
+ } : void 0,
2341
+ ...config.deploy && { deploy: config.deploy },
2342
+ sourceLocation: {
2343
+ file: sourceFile.getFilePath(),
2344
+ line: fn.getStartLineNumber(false),
2345
+ column: 0
2346
+ }
2347
+ });
2348
+ });
2349
+ return nodeTypes;
2350
+ }
2351
+ function inferNodeTypeFromFunction(fn, name, filePath) {
2352
+ const durableGate = durableGateKind(fn);
2353
+ const durableEffect = hasJsDocTag(fn, "durableEffect");
2354
+ const durablePure = hasJsDocTag(fn, "durablePure");
2355
+ const inputs = {};
2356
+ const params = fn.getParameters();
2357
+ const firstParamIsExecute = params.length > 0 && params[0].getName() === "execute";
2358
+ const authoredInputParams = durableEffect ? params.slice(0, -1) : params;
2359
+ for (const param of authoredInputParams) {
2360
+ const paramName = param.getName();
2361
+ const optional = param.isOptional() || param.hasInitializer();
2362
+ const rawTsType = param.getType().getText(param);
2363
+ const tsType = optional ? stripOptionalUndefined(rawTsType) : rawTsType;
2364
+ const dataType = inferDataTypeFromTS(tsType);
2365
+ inputs[paramName] = {
2366
+ dataType,
2367
+ optional: optional || void 0,
2368
+ label: capitalize(paramName),
2369
+ tsType
2370
+ };
2371
+ }
2372
+ const outputs = {};
2373
+ let returnType = fn.getReturnType();
2374
+ const returnTypeText = returnType.getText();
2375
+ if (returnTypeText.startsWith("Promise<")) {
2376
+ const typeArgs = returnType.getTypeArguments();
2377
+ if (typeArgs && typeArgs.length > 0) {
2378
+ returnType = typeArgs[0];
2379
+ }
2380
+ }
2381
+ if (durableEffect) {
2382
+ const effectResult = returnType.getProperty("result");
2383
+ if (effectResult) {
2384
+ returnType = effectResult.getTypeAtLocation(fn.getTypeResolutionNode());
2385
+ }
2386
+ }
2387
+ const unwrappedText = returnType.getText();
2388
+ if (unwrappedText !== "void" && unwrappedText !== "undefined") {
2389
+ const primitiveTypes = /* @__PURE__ */ new Set(["string", "number", "boolean", "any", "unknown", "never"]);
2390
+ const isPrimitive = primitiveTypes.has(unwrappedText);
2391
+ const isArray = unwrappedText.endsWith("[]") || unwrappedText.startsWith("Array<");
2392
+ const properties = returnType.getProperties();
2393
+ const isObjectLike = !isPrimitive && !isArray && returnType.isObject() && properties.length > 0;
2394
+ if (isObjectLike) {
2395
+ for (const prop of properties) {
2396
+ const propName = prop.getName();
2397
+ if (propName === "onSuccess" || propName === "onFailure") continue;
2398
+ const propType = prop.getTypeAtLocation(fn.getTypeResolutionNode());
2399
+ const propTypeText = propType.getText();
2400
+ const dataType = inferDataTypeFromTS(propTypeText);
2401
+ outputs[propName] = {
2402
+ dataType,
2403
+ label: capitalize(propName),
2404
+ tsType: propTypeText
2405
+ };
2406
+ }
2407
+ } else {
2408
+ const dataType = inferDataTypeFromTS(unwrappedText);
2409
+ outputs.result = {
2410
+ dataType,
2411
+ label: "Result",
2412
+ tsType: unwrappedText
2413
+ };
2414
+ }
2415
+ }
2416
+ inputs.execute = { dataType: "STEP", label: "Execute" };
2417
+ outputs.onSuccess = { dataType: "STEP", label: "On Success", isControlFlow: true };
2418
+ outputs.onFailure = {
2419
+ dataType: "STEP",
2420
+ label: "On Failure",
2421
+ failure: true,
2422
+ isControlFlow: true
2423
+ };
2424
+ assignImplicitPortOrders(inputs);
2425
+ assignImplicitPortOrders(outputs);
2426
+ const jsDocs = fn.getJsDocs();
2427
+ const jsDocText = jsDocs.map((doc) => doc.getText()).join("\n");
2428
+ const functionText = jsDocText ? `${jsDocText}
2429
+ ${fn.getText()}` : fn.getText();
2430
+ const durableEffectContract = durableEffect ? analyzeDurableEffectContract(fn, inputs, outputs) : void 0;
2431
+ return {
2432
+ type: "NodeType",
2433
+ name,
2434
+ functionName: name,
2435
+ variant: "FUNCTION",
2436
+ inputs,
2437
+ outputs,
2438
+ hasSuccessPort: true,
2439
+ hasFailurePort: true,
2440
+ isAsync: returnsPromise(fn),
2441
+ executeWhen: EXECUTION_STRATEGIES.CONJUNCTION,
2442
+ expression: !firstParamIsExecute,
2443
+ // Expression only if original function lacks execute as first param
2444
+ inferred: true,
2445
+ functionText,
2446
+ ...durableGate && { durableGate },
2447
+ ...durableEffect && { durableEffect: true },
2448
+ ...durableEffectContract && { durableEffectContract },
2449
+ ...durablePure && { durablePure: true },
2450
+ ...fn.getDeclarationKind?.() && {
2451
+ declarationKind: fn.getDeclarationKind()
2452
+ },
2453
+ sourceLocation: {
2454
+ file: filePath,
2455
+ line: fn.getStartLineNumber(false),
2456
+ column: 0
2457
+ }
2458
+ };
2459
+ }
2460
+ function inferAllUnannotatedFunctions(sourceFile, existingNodeTypes) {
2461
+ const allFunctions = extractFunctionLikes(sourceFile);
2462
+ const existingNames = /* @__PURE__ */ new Set();
2463
+ for (const nt of existingNodeTypes) {
2464
+ existingNames.add(nt.name);
2465
+ existingNames.add(nt.functionName);
2466
+ }
2467
+ const inferred = [];
2468
+ for (const fn of allFunctions) {
2469
+ const fnName = fn.getName();
2470
+ if (!fnName) continue;
2471
+ if (existingNames.has(fnName)) continue;
2472
+ if (hasFlowWeaverAnnotation(fn)) continue;
2473
+ inferred.push(inferNodeTypeFromFunction(fn, fnName, sourceFile.getFilePath()));
2474
+ existingNames.add(fnName);
2475
+ }
2476
+ return inferred;
2477
+ }
2478
+ function inferNodeTypesFromUnannotated(sourceFile, existingNodeTypes, localNodeTypes, warnings) {
2479
+ const allFunctions = extractFunctionLikes(sourceFile);
2480
+ const referencedTypes = /* @__PURE__ */ new Set();
2481
+ for (const fn of allFunctions) {
2482
+ const config = jsdocParser.parseWorkflow(fn, []);
2483
+ if (!config) continue;
2484
+ for (const inst of config.instances || []) {
2485
+ referencedTypes.add(inst.type);
2486
+ }
2487
+ }
2488
+ const existingNames = /* @__PURE__ */ new Set();
2489
+ for (const nt of existingNodeTypes) {
2490
+ existingNames.add(nt.name);
2491
+ existingNames.add(nt.functionName);
2492
+ }
2493
+ const unresolvedTypes = /* @__PURE__ */ new Set();
2494
+ for (const typeName of referencedTypes) {
2495
+ if (!existingNames.has(typeName)) {
2496
+ unresolvedTypes.add(typeName);
2497
+ }
2498
+ }
2499
+ if (unresolvedTypes.size === 0) return [];
2500
+ const inferredNodeTypes = [];
2501
+ const alreadyInferred = /* @__PURE__ */ new Set();
2502
+ const builtInByName = new Map(BUILT_IN_NODE_TYPES.map((nt) => [nt.name, nt]));
2503
+ const annotatedNames = new Set(localNodeTypes.map((nt) => nt.functionName));
2504
+ for (const unresolvedType of unresolvedTypes) {
2505
+ if (alreadyInferred.has(unresolvedType)) continue;
2506
+ const builtIn = builtInByName.get(unresolvedType);
2507
+ if (builtIn) {
2508
+ inferredNodeTypes.push(builtIn);
2509
+ alreadyInferred.add(unresolvedType);
2510
+ if (!annotatedNames.has(unresolvedType)) {
2511
+ const shadowFn = allFunctions.find((fn) => fn.getName() === unresolvedType && !hasFlowWeaverAnnotation(fn));
2512
+ if (shadowFn) {
2513
+ warnings.push(
2514
+ `Function '${unresolvedType}' exists in this file but is not annotated with @flowWeaver nodeType. The built-in '${unresolvedType}' will be used instead. Add @flowWeaver nodeType to use your version.`
2515
+ );
2516
+ }
2517
+ }
2518
+ continue;
2519
+ }
2520
+ const matchedFn = allFunctions.find((fn) => {
2521
+ if (fn.getName() !== unresolvedType) return false;
2522
+ return !hasFlowWeaverAnnotation(fn);
2523
+ });
2524
+ if (!matchedFn) continue;
2525
+ inferredNodeTypes.push(
2526
+ inferNodeTypeFromFunction(matchedFn, unresolvedType, sourceFile.getFilePath())
2527
+ );
2528
+ alreadyInferred.add(unresolvedType);
2529
+ }
2530
+ return inferredNodeTypes;
2531
+ }
2532
+ function hasFlowWeaverAnnotation(fn) {
2533
+ const validTypes = /* @__PURE__ */ new Set(["nodeType", "node", "workflow"]);
2534
+ return fn.getJsDocs().some(
2535
+ (doc) => doc.getTags().some((t) => {
2536
+ if (t.getTagName() !== "flowWeaver") return false;
2537
+ const comment = t.getCommentText?.()?.trim() || "";
2538
+ return validTypes.has(comment.split(/\s/)[0]);
2539
+ })
2540
+ );
2541
+ }
2542
+
2543
+ // src/parser/module-resolution.ts
2544
+ import * as ts from "typescript";
2545
+ import * as path2 from "node:path";
2546
+ import * as fs from "node:fs";
2547
+ var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mts", ".cts", ".mjs", ".cjs"]);
2548
+ function resolveModulePath(moduleSpecifier, currentDir, warnings) {
2549
+ const extensions = [".ts", ".tsx", ".js", ".jsx"];
2550
+ const hasExtension = extensions.some((ext) => moduleSpecifier.endsWith(ext));
2551
+ if (hasExtension) {
2552
+ const fullPath = path2.resolve(currentDir, moduleSpecifier);
2553
+ if (fs.existsSync(fullPath)) return fullPath;
2554
+ if (moduleSpecifier.endsWith(".js")) {
2555
+ const tsPath = fullPath.replace(/\.js$/, ".ts");
2556
+ if (fs.existsSync(tsPath)) return tsPath;
2557
+ const tsxPath = fullPath.replace(/\.js$/, ".tsx");
2558
+ if (fs.existsSync(tsxPath)) return tsxPath;
2559
+ } else if (moduleSpecifier.endsWith(".jsx")) {
2560
+ const tsxPath = fullPath.replace(/\.jsx$/, ".tsx");
2561
+ if (fs.existsSync(tsxPath)) return tsxPath;
2562
+ }
2563
+ return null;
2564
+ }
2565
+ for (const ext of extensions) {
2566
+ const fullPath = path2.resolve(currentDir, moduleSpecifier + ext);
2567
+ if (fs.existsSync(fullPath)) {
2568
+ return fullPath;
2569
+ }
2570
+ }
2571
+ const dirPath = path2.resolve(currentDir, moduleSpecifier);
2572
+ if (fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
2573
+ const pkgPath = path2.join(dirPath, "package.json");
2574
+ if (fs.existsSync(pkgPath)) {
2575
+ try {
2576
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
2577
+ if (pkg.main) {
2578
+ const mainPath = path2.resolve(dirPath, pkg.main);
2579
+ if (fs.existsSync(mainPath)) {
2580
+ return mainPath;
2581
+ }
2582
+ }
2583
+ } catch (e) {
2584
+ warnings?.push(`Could not read ${pkgPath} while resolving "${moduleSpecifier}": ${getErrorMessage(e)}`);
2585
+ }
2586
+ }
2587
+ for (const ext of extensions) {
2588
+ const indexPath = path2.join(dirPath, `index${ext}`);
2589
+ if (fs.existsSync(indexPath)) {
2590
+ return indexPath;
2591
+ }
2592
+ }
2593
+ }
2594
+ return null;
2595
+ }
2596
+ function resolveReExportedDts(baseDir, spec) {
2597
+ const noExt = spec.replace(/\.(js|mjs|cjs|jsx|ts|tsx)$/, "");
2598
+ const candidates = [
2599
+ path2.resolve(baseDir, `${noExt}.d.ts`),
2600
+ path2.resolve(baseDir, noExt, "index.d.ts"),
2601
+ path2.resolve(baseDir, spec)
2602
+ // already a .d.ts path
2603
+ ];
2604
+ for (const c of candidates) {
2605
+ if (c.endsWith(".d.ts") && fs.existsSync(c)) return c;
2606
+ }
2607
+ return null;
2608
+ }
2609
+ function preloadSourceOverrides(project, importer, source, importResolver, sourceLoader, seen) {
2610
+ const parsed = ts.createSourceFile(importer, source, ts.ScriptTarget.Latest, true);
2611
+ for (const statement of parsed.statements) {
2612
+ if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier)) {
2613
+ continue;
2614
+ }
2615
+ const specifier = statement.moduleSpecifier.text;
2616
+ if (!specifier.startsWith(".")) continue;
2617
+ const resolved = importResolver?.(specifier, importer) ?? resolveModulePath(specifier, path2.dirname(importer));
2618
+ if (resolved === void 0 || resolved === null || seen.has(resolved)) continue;
2619
+ const override = sourceLoader(resolved);
2620
+ if (override === void 0) continue;
2621
+ seen.add(resolved);
2622
+ preloadSourceOverrides(project, resolved, override, importResolver, sourceLoader, seen);
2623
+ project.createSourceFile(resolved, override, { overwrite: true });
2624
+ }
2625
+ }
2626
+
2627
+ // src/parser/import-resolution.ts
2628
+ import * as path3 from "node:path";
2629
+ import * as fs2 from "node:fs";
2630
+
2631
+ // src/parser/macro-expansion.ts
2632
+ function expandMapMacro(mapConfig, instances, connections, scopes, availableNodeTypes, macros, errors, _warnings) {
2633
+ const { instanceId, childId, sourceNode, sourcePort } = mapConfig;
2634
+ const scopeName = "iterate";
2635
+ const childInstance = instances.find((inst) => inst.id === childId);
2636
+ if (!childInstance) {
2637
+ errors.push(
2638
+ `@map "${instanceId}": child node "${childId}" not found. Declare it with @node before using @map.`
2639
+ );
2640
+ return;
2641
+ }
2642
+ const childNodeType = availableNodeTypes.find(
2643
+ (nt) => nt.name === childInstance.nodeType || nt.functionName === childInstance.nodeType
2644
+ );
2645
+ if (!childNodeType) {
2646
+ errors.push(
2647
+ `@map "${instanceId}": node type "${childInstance.nodeType}" for child "${childId}" not found.`
2648
+ );
2649
+ return;
2650
+ }
2651
+ let inputPort = mapConfig.inputPort;
2652
+ let outputPort = mapConfig.outputPort;
2653
+ if (!inputPort) {
2654
+ const dataInputs = Object.entries(childNodeType.inputs).filter(
2655
+ ([name, def]) => name !== "execute" && def.dataType !== "STEP"
2656
+ );
2657
+ if (dataInputs.length === 0) {
2658
+ errors.push(
2659
+ `@map "${instanceId}": child node "${childId}" has no data input ports to receive items.`
2660
+ );
2661
+ return;
2662
+ }
2663
+ inputPort = dataInputs[0][0];
2664
+ }
2665
+ if (!outputPort) {
2666
+ const dataOutputs = Object.entries(childNodeType.outputs).filter(
2667
+ ([name, def]) => name !== "onSuccess" && name !== "onFailure" && def.dataType !== "STEP" && !def.isControlFlow && !def.failure
2668
+ );
2669
+ if (dataOutputs.length === 0) {
2670
+ errors.push(
2671
+ `@map "${instanceId}": child node "${childId}" has no data output ports for results.`
2672
+ );
2673
+ return;
2674
+ }
2675
+ outputPort = dataOutputs[0][0];
2676
+ }
2677
+ const childInputDef = childNodeType.inputs[inputPort];
2678
+ const childOutputDef = childNodeType.outputs[outputPort];
2679
+ const syntheticTypeName = `__map_${instanceId}__`;
2680
+ const syntheticNodeType = {
2681
+ type: "NodeType",
2682
+ name: syntheticTypeName,
2683
+ functionName: syntheticTypeName,
2684
+ variant: "MAP_ITERATOR",
2685
+ isAsync: true,
2686
+ executeWhen: "CONJUNCTION",
2687
+ hasSuccessPort: true,
2688
+ hasFailurePort: true,
2689
+ scope: scopeName,
2690
+ scopes: [scopeName],
2691
+ inputs: {
2692
+ execute: { dataType: "STEP", label: "Execute" },
2693
+ items: {
2694
+ dataType: "ARRAY",
2695
+ label: "Items",
2696
+ tsType: childInputDef?.tsType ? `(${childInputDef.tsType})[]` : "unknown[]"
2697
+ },
2698
+ // Scoped INPUT ports (receive from children)
2699
+ success: { dataType: "STEP", scope: scopeName },
2700
+ failure: { dataType: "STEP", scope: scopeName },
2701
+ processed: {
2702
+ dataType: childOutputDef?.dataType || "ANY",
2703
+ scope: scopeName,
2704
+ ...childOutputDef?.tsType && { tsType: childOutputDef.tsType }
2705
+ }
2706
+ },
2707
+ outputs: {
2708
+ onSuccess: { dataType: "STEP", label: "On Success", isControlFlow: true },
2709
+ onFailure: { dataType: "STEP", label: "On Failure", isControlFlow: true, failure: true },
2710
+ results: {
2711
+ dataType: "ARRAY",
2712
+ label: "Results",
2713
+ tsType: childOutputDef?.tsType ? `(${childOutputDef.tsType})[]` : "unknown[]"
2714
+ },
2715
+ // Scoped OUTPUT ports (send to children)
2716
+ start: { dataType: "STEP", scope: scopeName },
2717
+ item: {
2718
+ dataType: childInputDef?.dataType || "ANY",
2719
+ scope: scopeName,
2720
+ ...childInputDef?.tsType && { tsType: childInputDef.tsType }
2721
+ }
2722
+ }
2723
+ };
2724
+ availableNodeTypes.push(syntheticNodeType);
2725
+ const mapInstance = {
2726
+ type: "NodeInstance",
2727
+ id: instanceId,
2728
+ nodeType: syntheticTypeName
2729
+ };
2730
+ instances.push(mapInstance);
2731
+ childInstance.parent = { id: instanceId, scope: scopeName };
2732
+ connections.push({
2733
+ type: "Connection",
2734
+ from: { node: instanceId, port: "start", scope: scopeName },
2735
+ to: { node: childId, port: "execute", scope: scopeName }
2736
+ });
2737
+ connections.push({
2738
+ type: "Connection",
2739
+ from: { node: instanceId, port: "item", scope: scopeName },
2740
+ to: { node: childId, port: inputPort, scope: scopeName }
2741
+ });
2742
+ connections.push({
2743
+ type: "Connection",
2744
+ from: { node: childId, port: outputPort, scope: scopeName },
2745
+ to: { node: instanceId, port: "processed", scope: scopeName }
2746
+ });
2747
+ connections.push({
2748
+ type: "Connection",
2749
+ from: { node: childId, port: "onSuccess", scope: scopeName },
2750
+ to: { node: instanceId, port: "success", scope: scopeName }
2751
+ });
2752
+ connections.push({
2753
+ type: "Connection",
2754
+ from: { node: childId, port: "onFailure", scope: scopeName },
2755
+ to: { node: instanceId, port: "failure", scope: scopeName }
2756
+ });
2757
+ connections.push({
2758
+ type: "Connection",
2759
+ from: { node: sourceNode, port: sourcePort },
2760
+ to: { node: instanceId, port: "items" }
2761
+ });
2762
+ scopes[`${instanceId}.${scopeName}`] = [childId];
2763
+ macros.push({
2764
+ type: "map",
2765
+ instanceId,
2766
+ childId,
2767
+ sourcePort: `${sourceNode}.${sourcePort}`,
2768
+ ...mapConfig.inputPort && { inputPort: mapConfig.inputPort },
2769
+ ...mapConfig.outputPort && { outputPort: mapConfig.outputPort }
2770
+ });
2771
+ }
2772
+ function expandPathMacros(pathConfigs, instances, connections, availableNodeTypes, startPorts, exitPorts, macros, errors, _warnings) {
2773
+ const findNodeType = (nodeTypeName) => availableNodeTypes.find(
2774
+ (nt) => nt.name === nodeTypeName || nt.functionName === nodeTypeName
2775
+ );
2776
+ const getNodeType = (nodeId) => {
2777
+ const instance = instances.find((inst) => inst.id === nodeId);
2778
+ if (!instance) return void 0;
2779
+ return findNodeType(instance.nodeType);
2780
+ };
2781
+ const getOutputPorts = (nodeId) => {
2782
+ if (nodeId === "Start") return startPorts;
2783
+ if (nodeId === "Exit") return exitPorts;
2784
+ const nodeType = getNodeType(nodeId);
2785
+ return nodeType?.outputs || {};
2786
+ };
2787
+ const getInputPorts = (nodeId) => {
2788
+ if (nodeId === "Exit") return exitPorts;
2789
+ if (nodeId === "Start") return startPorts;
2790
+ const nodeType = getNodeType(nodeId);
2791
+ return nodeType?.inputs || {};
2792
+ };
2793
+ const existingKeys = /* @__PURE__ */ new Set();
2794
+ for (const conn of connections) {
2795
+ existingKeys.add(`${conn.from.node}.${conn.from.port}->${conn.to.node}.${conn.to.port}`);
2796
+ }
2797
+ const addConnection = (fromNode, fromPort, toNode, toPort) => {
2798
+ const key = `${fromNode}.${fromPort}->${toNode}.${toPort}`;
2799
+ if (existingKeys.has(key)) return;
2800
+ existingKeys.add(key);
2801
+ connections.push({
2802
+ type: "Connection",
2803
+ from: { node: fromNode, port: fromPort },
2804
+ to: { node: toNode, port: toPort }
2805
+ });
2806
+ };
2807
+ for (const pathConfig of pathConfigs) {
2808
+ const { steps } = pathConfig;
2809
+ if (steps.length < 2) {
2810
+ errors.push(`@path requires at least 2 steps, got ${steps.length}.`);
2811
+ continue;
2812
+ }
2813
+ let valid = true;
2814
+ for (const step of steps) {
2815
+ if (step.node === "Start" || step.node === "Exit") continue;
2816
+ const instance = instances.find((inst) => inst.id === step.node);
2817
+ if (!instance) {
2818
+ errors.push(
2819
+ `@path: node "${step.node}" not found. Declare it with @node before using @path.`
2820
+ );
2821
+ valid = false;
2822
+ }
2823
+ }
2824
+ if (!valid) continue;
2825
+ for (let i = 0; i < steps.length - 1; i++) {
2826
+ const current = steps[i];
2827
+ const next = steps[i + 1];
2828
+ const currentId = current.node;
2829
+ const nextId = next.node;
2830
+ const route = current.route || "ok";
2831
+ if (currentId === "Start") {
2832
+ addConnection("Start", "execute", nextId, nextId === "Exit" ? "onSuccess" : "execute");
2833
+ } else if (nextId === "Exit") {
2834
+ if (route === "fail") {
2835
+ addConnection(currentId, "onFailure", "Exit", "onFailure");
2836
+ } else {
2837
+ addConnection(currentId, "onSuccess", "Exit", "onSuccess");
2838
+ }
2839
+ } else {
2840
+ if (route === "fail") {
2841
+ addConnection(currentId, "onFailure", nextId, "execute");
2842
+ } else {
2843
+ addConnection(currentId, "onSuccess", nextId, "execute");
2844
+ }
2845
+ }
2846
+ for (const edge of impliedPathDataEdgesInto(steps, i + 1, { inputs: getInputPorts, outputs: getOutputPorts })) {
2847
+ const alreadyConnected = connections.some(
2848
+ (c) => c.to.node === edge.to.node && c.to.port === edge.to.port
2849
+ );
2850
+ if (alreadyConnected) continue;
2851
+ addConnection(edge.from.node, edge.from.port, edge.to.node, edge.to.port);
2852
+ }
2853
+ }
2854
+ macros.push({
2855
+ type: "path",
2856
+ steps: steps.map((s) => s.route ? { node: s.node, route: s.route } : { node: s.node })
2857
+ });
2858
+ }
2859
+ }
2860
+ function expandFanOutMacros(fanOutConfigs, instances, connections, startPorts, exitPorts, macros, errors) {
2861
+ const instanceIds = new Set(instances.map((i) => i.id));
2862
+ instanceIds.add("Start");
2863
+ instanceIds.add("Exit");
2864
+ for (const config of fanOutConfigs) {
2865
+ const { source, targets } = config;
2866
+ if (!instanceIds.has(source.node)) {
2867
+ errors.push(`@fanOut: source node "${source.node}" does not exist`);
2868
+ continue;
2869
+ }
2870
+ let valid = true;
2871
+ for (const target of targets) {
2872
+ if (!instanceIds.has(target.node)) {
2873
+ errors.push(`@fanOut: target node "${target.node}" does not exist`);
2874
+ valid = false;
2875
+ }
2876
+ }
2877
+ if (!valid) continue;
2878
+ for (const target of targets) {
2879
+ const targetPort = target.port ?? source.port;
2880
+ const conn = {
2881
+ type: "Connection",
2882
+ from: { node: source.node, port: source.port },
2883
+ to: { node: target.node, port: targetPort }
2884
+ };
2885
+ const exists = connections.some(
2886
+ (c) => c.from.node === conn.from.node && c.from.port === conn.from.port && c.to.node === conn.to.node && c.to.port === conn.to.port
2887
+ );
2888
+ if (!exists) {
2889
+ connections.push(conn);
2890
+ }
2891
+ }
2892
+ macros.push({
2893
+ type: "fanOut",
2894
+ source: { node: source.node, port: source.port },
2895
+ targets: targets.map((t) => t.port ? { node: t.node, port: t.port } : { node: t.node })
2896
+ });
2897
+ }
2898
+ }
2899
+ function expandFanInMacros(fanInConfigs, instances, connections, startPorts, exitPorts, macros, errors) {
2900
+ const instanceIds = new Set(instances.map((i) => i.id));
2901
+ instanceIds.add("Start");
2902
+ instanceIds.add("Exit");
2903
+ for (const config of fanInConfigs) {
2904
+ const { sources, target } = config;
2905
+ if (!instanceIds.has(target.node)) {
2906
+ errors.push(`@fanIn: target node "${target.node}" does not exist`);
2907
+ continue;
2908
+ }
2909
+ let valid = true;
2910
+ for (const source of sources) {
2911
+ if (!instanceIds.has(source.node)) {
2912
+ errors.push(`@fanIn: source node "${source.node}" does not exist`);
2913
+ valid = false;
2914
+ }
2915
+ }
2916
+ if (!valid) continue;
2917
+ for (const source of sources) {
2918
+ const sourcePort = source.port ?? target.port;
2919
+ const conn = {
2920
+ type: "Connection",
2921
+ from: { node: source.node, port: sourcePort },
2922
+ to: { node: target.node, port: target.port }
2923
+ };
2924
+ const exists = connections.some(
2925
+ (c) => c.from.node === conn.from.node && c.from.port === conn.from.port && c.to.node === conn.to.node && c.to.port === conn.to.port
2926
+ );
2927
+ if (!exists) {
2928
+ connections.push(conn);
2929
+ }
2930
+ }
2931
+ macros.push({
2932
+ type: "fanIn",
2933
+ sources: sources.map((s) => s.port ? { node: s.node, port: s.port } : { node: s.node }),
2934
+ target: { node: target.node, port: target.port }
2935
+ });
2936
+ }
2937
+ }
2938
+ function expandCoerceMacros(coerceConfigs, instances, connections, startPorts, exitPorts, macros, errors) {
2939
+ const instanceIds = new Set(instances.map((i) => i.id));
2940
+ instanceIds.add("Start");
2941
+ instanceIds.add("Exit");
2942
+ for (const config of coerceConfigs) {
2943
+ const { instanceId, source, target, targetType } = config;
2944
+ if (!instanceIds.has(source.node)) {
2945
+ errors.push(`@coerce: source node "${source.node}" does not exist`);
2946
+ continue;
2947
+ }
2948
+ if (!instanceIds.has(target.node)) {
2949
+ errors.push(`@coerce: target node "${target.node}" does not exist`);
2950
+ continue;
2951
+ }
2952
+ if (instanceIds.has(instanceId)) {
2953
+ errors.push(`@coerce: instance ID "${instanceId}" already exists`);
2954
+ continue;
2955
+ }
2956
+ const nodeTypeName = COERCE_TYPE_MAP[targetType];
2957
+ if (!nodeTypeName) {
2958
+ errors.push(`@coerce: unknown target type "${targetType}"`);
2959
+ continue;
2960
+ }
2961
+ instances.push({
2962
+ type: "NodeInstance",
2963
+ id: instanceId,
2964
+ nodeType: nodeTypeName
2965
+ });
2966
+ instanceIds.add(instanceId);
2967
+ connections.push({
2968
+ type: "Connection",
2969
+ from: { node: source.node, port: source.port },
2970
+ to: { node: instanceId, port: "value" }
2971
+ });
2972
+ connections.push({
2973
+ type: "Connection",
2974
+ from: { node: instanceId, port: "result" },
2975
+ to: { node: target.node, port: target.port }
2976
+ });
2977
+ macros.push({
2978
+ type: "coerce",
2979
+ instanceId,
2980
+ source: { node: source.node, port: source.port },
2981
+ target: { node: target.node, port: target.port },
2982
+ targetType
2983
+ });
2984
+ }
2985
+ }
2986
+ function generateAutoConnections(instances, availableNodeTypes, startPorts, exitPorts) {
2987
+ const connections = [];
2988
+ const findNodeType = (nodeTypeName) => availableNodeTypes.find(
2989
+ (nt) => nt.name === nodeTypeName || nt.functionName === nodeTypeName
2990
+ );
2991
+ if (instances.length > 0) {
2992
+ const firstInstance = instances[0];
2993
+ const firstNodeType = findNodeType(firstInstance.nodeType);
2994
+ connections.push({
2995
+ type: "Connection",
2996
+ from: { node: "Start", port: "execute" },
2997
+ to: { node: firstInstance.id, port: "execute" }
2998
+ });
2999
+ if (firstNodeType) {
3000
+ for (const [portName, portDef] of Object.entries(startPorts)) {
3001
+ if (portDef.dataType === "STEP") continue;
3002
+ if (portName in firstNodeType.inputs && !isControlFlowPort(portName)) {
3003
+ connections.push({
3004
+ type: "Connection",
3005
+ from: { node: "Start", port: portName },
3006
+ to: { node: firstInstance.id, port: portName }
3007
+ });
3008
+ }
3009
+ }
3010
+ }
3011
+ }
3012
+ for (let i = 0; i < instances.length - 1; i++) {
3013
+ const current = instances[i];
3014
+ const next = instances[i + 1];
3015
+ const currentNodeType = findNodeType(current.nodeType);
3016
+ const nextNodeType = findNodeType(next.nodeType);
3017
+ connections.push({
3018
+ type: "Connection",
3019
+ from: { node: current.id, port: "onSuccess" },
3020
+ to: { node: next.id, port: "execute" }
3021
+ });
3022
+ if (currentNodeType && nextNodeType) {
3023
+ for (const [outputName, outputDef] of Object.entries(currentNodeType.outputs)) {
3024
+ if (outputDef.dataType === "STEP" || isControlFlowPort(outputName)) continue;
3025
+ if (outputName in nextNodeType.inputs && !isControlFlowPort(outputName)) {
3026
+ connections.push({
3027
+ type: "Connection",
3028
+ from: { node: current.id, port: outputName },
3029
+ to: { node: next.id, port: outputName }
3030
+ });
3031
+ }
3032
+ }
3033
+ }
3034
+ }
3035
+ if (instances.length > 0) {
3036
+ const lastInstance = instances[instances.length - 1];
3037
+ const lastNodeType = findNodeType(lastInstance.nodeType);
3038
+ connections.push({
3039
+ type: "Connection",
3040
+ from: { node: lastInstance.id, port: "onSuccess" },
3041
+ to: { node: "Exit", port: "onSuccess" }
3042
+ });
3043
+ if (lastNodeType) {
3044
+ for (const [portName, portDef] of Object.entries(exitPorts)) {
3045
+ if (portDef.dataType === "STEP" || portDef.isControlFlow) continue;
3046
+ if (lastNodeType.outputs[portName] && !isControlFlowPort(portName)) {
3047
+ connections.push({
3048
+ type: "Connection",
3049
+ from: { node: lastInstance.id, port: portName },
3050
+ to: { node: "Exit", port: portName }
3051
+ });
3052
+ }
3053
+ }
3054
+ }
3055
+ }
3056
+ return connections;
3057
+ }
3058
+
3059
+ // src/parser/import-stub.ts
3060
+ function createImportStub(imp) {
3061
+ return {
3062
+ type: "NodeType",
3063
+ name: imp.name,
3064
+ functionName: imp.functionName,
3065
+ importSource: imp.importSource,
3066
+ variant: "FUNCTION",
3067
+ inputs: {},
3068
+ outputs: { result: { dataType: "ANY" } },
3069
+ hasSuccessPort: true,
3070
+ hasFailurePort: true,
3071
+ executeWhen: "CONJUNCTION",
3072
+ isAsync: false,
3073
+ // Mark as expression since most npm functions are pure
3074
+ // This is a reasonable default for stubs
3075
+ expression: true
3076
+ };
3077
+ }
3078
+ function isImportStub(nt) {
3079
+ if (!nt.importSource) return false;
3080
+ const inputKeys = Object.keys(nt.inputs ?? {});
3081
+ const outputKeys = Object.keys(nt.outputs ?? {});
3082
+ return inputKeys.length === 0 && outputKeys.length === 1 && outputKeys[0] === "result";
3083
+ }
3084
+
3085
+ // src/parser/workflow-extraction.ts
3086
+ var RESERVED_OPTION_KEYS = /* @__PURE__ */ new Set([
3087
+ "strictTypes",
3088
+ "autoConnect",
3089
+ "trigger",
3090
+ "http",
3091
+ "cancelOn",
3092
+ "retries",
3093
+ "timeout",
3094
+ "throttle",
3095
+ "deploy"
3096
+ ]);
3097
+ function promoteDeployNamespaces(deploy) {
3098
+ if (!deploy) return {};
3099
+ const promoted = {};
3100
+ for (const [namespace, data] of Object.entries(deploy)) {
3101
+ if (RESERVED_OPTION_KEYS.has(namespace)) continue;
3102
+ if (data && typeof data === "object") promoted[namespace] = data;
3103
+ }
3104
+ return promoted;
3105
+ }
3106
+ function extractWorkflowSignatures(sourceFile, filePath, warnings, tagRegistry) {
3107
+ const workflows = [];
3108
+ extractFunctionLikes(sourceFile).forEach((fn) => {
3109
+ const config = jsdocParser.parseWorkflow(fn, warnings, tagRegistry);
3110
+ if (!config) return;
3111
+ const functionName = fn.getName() || "anonymous";
3112
+ const startPorts = parseStartPorts(fn, config);
3113
+ const exitPorts = parseExitPorts(fn, config, warnings);
3114
+ const userSpecifiedAsync = fn.isAsync();
3115
+ workflows.push({
3116
+ type: "Workflow",
3117
+ sourceFile: filePath,
3118
+ name: config.name || functionName,
3119
+ functionName,
3120
+ nodeTypes: [],
3121
+ instances: [],
3122
+ connections: [],
3123
+ startPorts,
3124
+ exitPorts,
3125
+ imports: [],
3126
+ description: config.description,
3127
+ userSpecifiedAsync
3128
+ });
3129
+ });
3130
+ return workflows;
3131
+ }
3132
+ function workflowToNodeType(workflow) {
3133
+ return {
3134
+ type: "NodeType",
3135
+ name: workflow.name,
3136
+ functionName: workflow.functionName,
3137
+ variant: "IMPORTED_WORKFLOW",
3138
+ path: workflow.sourceFile,
3139
+ inputs: { ...workflow.startPorts },
3140
+ outputs: { ...workflow.exitPorts },
3141
+ hasSuccessPort: "onSuccess" in workflow.exitPorts,
3142
+ hasFailurePort: "onFailure" in workflow.exitPorts,
3143
+ isAsync: workflow.userSpecifiedAsync || false,
3144
+ executeWhen: EXECUTION_STRATEGIES.CONJUNCTION,
3145
+ description: workflow.description,
3146
+ sourceLocation: {
3147
+ file: workflow.sourceFile,
3148
+ line: 0,
3149
+ column: 0
3150
+ }
3151
+ };
3152
+ }
3153
+ function extractWorkflows(sourceFile, availableNodeTypes, filePath, errors, warnings, tagRegistry, resolveImport) {
3154
+ const workflows = [];
3155
+ const allFunctions = extractFunctionLikes(sourceFile);
3156
+ const allFunctionNames = allFunctions.map((fn) => fn.getName()).filter((name) => !!name);
3157
+ allFunctions.forEach((fn) => {
3158
+ const config = jsdocParser.parseWorkflow(fn, warnings, tagRegistry);
3159
+ if (!config) {
3160
+ const jsdocText = fn.getJsDocs().map((d) => d.getFullText()).join("");
3161
+ if (jsdocText.includes("@flowWeaver workflow")) {
3162
+ warnings.push(
3163
+ `Function "${fn.getName() || "anonymous"}" has @flowWeaver annotation but could not be parsed. Check for special characters (---) or malformed JSDoc syntax.`
3164
+ );
3165
+ }
3166
+ return;
3167
+ }
3168
+ const functionName = fn.getName() || "anonymous";
3169
+ if (config.connections) {
3170
+ for (const conn of config.connections) {
3171
+ if (conn.from.node === "IN" || conn.from.node === "OUT") {
3172
+ errors.push(
3173
+ `Workflow "${functionName}" uses "${conn.from.node}", which is not a node. Use "Start" or "Exit" instead.`
3174
+ );
3175
+ }
3176
+ if (conn.to.node === "IN" || conn.to.node === "OUT") {
3177
+ errors.push(
3178
+ `Workflow "${functionName}" uses "${conn.to.node}", which is not a node. Use "Start" or "Exit" instead.`
3179
+ );
3180
+ }
3181
+ }
3182
+ }
3183
+ const userSpecifiedAsync = fn.isAsync();
3184
+ const startPorts = parseStartPorts(fn, config);
3185
+ const exitPorts = parseExitPorts(fn, config, warnings);
3186
+ const importedNpmNodeTypes = (config.imports || []).map(
3187
+ (imp) => resolveImport(imp, filePath, warnings)
3188
+ );
3189
+ for (const nt of importedNpmNodeTypes) {
3190
+ const dataInputs = Object.keys(nt.inputs).filter((p) => p !== "execute");
3191
+ const nonControlOutputs = Object.keys(nt.outputs).filter(
3192
+ (p) => p !== "onSuccess" && p !== "onFailure"
3193
+ );
3194
+ const isStubOnly = nonControlOutputs.length === 1 && nonControlOutputs[0] === "result" && nt.outputs.result?.dataType === "ANY";
3195
+ if (dataInputs.length === 0 && isStubOnly) {
3196
+ warnings.push(
3197
+ `Could not infer ports for "${nt.functionName}" from "${nt.importSource}". Wrap it in a local function with @flowWeaver nodeType annotations instead.`
3198
+ );
3199
+ }
3200
+ }
3201
+ const allAvailableNodeTypes = [...availableNodeTypes, ...importedNpmNodeTypes];
3202
+ const instances = (config.instances || []).map((inst) => {
3203
+ let parent;
3204
+ if (inst.parentScope) {
3205
+ const dotIndex = inst.parentScope.indexOf(".");
3206
+ if (dotIndex > 0) {
3207
+ parent = {
3208
+ id: inst.parentScope.substring(0, dotIndex),
3209
+ scope: inst.parentScope.substring(dotIndex + 1)
3210
+ };
3211
+ }
3212
+ }
3213
+ const portConfigs = inst.portConfigs;
3214
+ return {
3215
+ type: "NodeInstance",
3216
+ id: inst.id,
3217
+ nodeType: inst.type,
3218
+ ...parent && { parent },
3219
+ config: {
3220
+ ...inst.label && { label: inst.label },
3221
+ ...portConfigs && portConfigs.length > 0 && { portConfigs },
3222
+ ...inst.pullExecution && { pullExecution: inst.pullExecution },
3223
+ ...inst.minimized && { minimized: inst.minimized },
3224
+ ...inst.color && { color: inst.color },
3225
+ ...inst.icon && { icon: inst.icon },
3226
+ ...inst.tags && inst.tags.length > 0 && { tags: inst.tags },
3227
+ ...inst.width && { width: inst.width },
3228
+ ...inst.height && { height: inst.height },
3229
+ ...inst.suppressWarnings?.length && { suppressWarnings: inst.suppressWarnings }
3230
+ },
3231
+ ...inst.sourceLocation && {
3232
+ sourceLocation: { file: filePath, ...inst.sourceLocation }
3233
+ },
3234
+ ...inst.attributes && { attributes: inst.attributes }
3235
+ };
3236
+ });
3237
+ const connections = (config.connections || []).map((conn) => ({
3238
+ type: "Connection",
3239
+ from: conn.from,
3240
+ to: conn.to,
3241
+ ...conn.sourceLocation && { sourceLocation: { file: filePath, ...conn.sourceLocation } },
3242
+ ...conn.coerce && { coerce: conn.coerce }
3243
+ }));
3244
+ if (config.autoConnect && connections.length === 0 && instances.length > 0) {
3245
+ const autoConnections = generateAutoConnections(
3246
+ instances,
3247
+ allAvailableNodeTypes,
3248
+ startPorts,
3249
+ exitPorts
3250
+ );
3251
+ connections.push(...autoConnections);
3252
+ }
3253
+ const scopes = config.scopes || {};
3254
+ const macros = [];
3255
+ if (config.maps && config.maps.length > 0) {
3256
+ for (const mapConfig of config.maps) {
3257
+ expandMapMacro(
3258
+ mapConfig,
3259
+ instances,
3260
+ connections,
3261
+ scopes,
3262
+ allAvailableNodeTypes,
3263
+ macros,
3264
+ errors,
3265
+ warnings
3266
+ );
3267
+ }
3268
+ }
3269
+ if (config.paths && config.paths.length > 0) {
3270
+ expandPathMacros(
3271
+ config.paths,
3272
+ instances,
3273
+ connections,
3274
+ allAvailableNodeTypes,
3275
+ startPorts,
3276
+ exitPorts,
3277
+ macros,
3278
+ errors,
3279
+ warnings
3280
+ );
3281
+ }
3282
+ if (config.fanOuts && config.fanOuts.length > 0) {
3283
+ expandFanOutMacros(config.fanOuts, instances, connections, startPorts, exitPorts, macros, errors);
3284
+ }
3285
+ if (config.fanIns && config.fanIns.length > 0) {
3286
+ expandFanInMacros(config.fanIns, instances, connections, startPorts, exitPorts, macros, errors);
3287
+ }
3288
+ if (config.coercions && config.coercions.length > 0) {
3289
+ expandCoerceMacros(config.coercions, instances, connections, startPorts, exitPorts, macros, errors);
3290
+ }
3291
+ if (instances.some((inst) => inst.config?.portConfigs?.some((pc) => pc.expression !== void 0))) {
3292
+ expandExpressionReferences({
3293
+ instances,
3294
+ connections,
3295
+ findNodeType: (name) => allAvailableNodeTypes.find((nt) => nt.name === name || nt.functionName === name),
3296
+ startPorts,
3297
+ moduleBindings: collectModuleBindings(
3298
+ sourceFile,
3299
+ new Set(allAvailableNodeTypes.map((nt) => nt.functionName))
3300
+ ),
3301
+ errors
3302
+ });
3303
+ }
3304
+ const realNameToType = /* @__PURE__ */ new Map();
3305
+ for (const nt of allAvailableNodeTypes) {
3306
+ if (!isImportStub(nt) && !importedNpmNodeTypes.includes(nt)) {
3307
+ realNameToType.set(nt.name, nt);
3308
+ }
3309
+ }
3310
+ const resolvedImportedTypes = importedNpmNodeTypes.map((imp) => {
3311
+ if (isImportStub(imp)) {
3312
+ const real = realNameToType.get(imp.name);
3313
+ if (real) {
3314
+ const merged = { ...real };
3315
+ const impSource = imp.importSource;
3316
+ if (impSource) merged.importSource = impSource;
3317
+ return merged;
3318
+ }
3319
+ }
3320
+ return imp;
3321
+ });
3322
+ const importedNames = new Set(resolvedImportedTypes.map((nt) => nt.name));
3323
+ const dedupedAvailableTypes = allAvailableNodeTypes.filter((nt) => !importedNames.has(nt.name));
3324
+ const workflowNodeTypes = [...dedupedAvailableTypes, ...resolvedImportedTypes];
3325
+ for (const inst of instances) {
3326
+ if (inst.nodeType.startsWith("__fw_") && COERCION_NODE_TYPES[inst.nodeType]) {
3327
+ if (!workflowNodeTypes.some((nt) => nt.functionName === inst.nodeType)) {
3328
+ workflowNodeTypes.push(COERCION_NODE_TYPES[inst.nodeType]);
3329
+ }
3330
+ }
3331
+ }
3332
+ workflows.push({
3333
+ type: "Workflow",
3334
+ sourceFile: filePath,
3335
+ name: config.name || functionName,
3336
+ functionName,
3337
+ nodeTypes: workflowNodeTypes,
3338
+ instances,
3339
+ connections,
3340
+ scopes,
3341
+ startPorts,
3342
+ exitPorts,
3343
+ imports: [],
3344
+ description: config.description,
3345
+ userSpecifiedAsync,
3346
+ availableFunctionNames: allFunctionNames,
3347
+ ...macros.length > 0 && { macros },
3348
+ ...(config.strictTypes !== void 0 || config.autoConnect || config.trigger || config.http || config.cancelOn || config.retries !== void 0 || config.timeout || config.throttle || config.deploy) && {
3349
+ options: {
3350
+ ...config.strictTypes !== void 0 && { strictTypes: config.strictTypes },
3351
+ ...config.autoConnect && { autoConnect: true },
3352
+ ...config.trigger && { trigger: config.trigger },
3353
+ ...config.http && config.http.length > 0 && { http: config.http },
3354
+ ...config.cancelOn && { cancelOn: config.cancelOn },
3355
+ ...config.retries !== void 0 && { retries: config.retries },
3356
+ ...config.timeout && { timeout: config.timeout },
3357
+ ...config.throttle && { throttle: config.throttle },
3358
+ // Surface each pack deploy namespace as a top-level options.<namespace>
3359
+ // convenience mirror (e.g. options.<pack> from deploy['<pack>']). Packs
3360
+ // type these fields via module augmentation of TWorkflowOptions; core
3361
+ // stays namespace-agnostic and keeps no vendor vocabulary.
3362
+ ...promoteDeployNamespaces(config.deploy),
3363
+ // Per-target deployment config
3364
+ ...config.deploy && { deploy: config.deploy }
3365
+ }
3366
+ }
3367
+ });
3368
+ });
3369
+ return workflows;
3370
+ }
3371
+
3372
+ // src/parser/import-resolution.ts
3373
+ function dependenciesUnchanged(deps) {
3374
+ for (const dep of deps) {
3375
+ try {
3376
+ if (fs2.statSync(dep.path).mtimeMs !== dep.mtime) return false;
3377
+ } catch {
3378
+ return false;
3379
+ }
3380
+ }
3381
+ return true;
3382
+ }
3383
+ function recordDependency(ctx, filePath, mtime) {
3384
+ for (const recorder of ctx.dependencyRecorders) {
3385
+ recorder.set(filePath, mtime);
3386
+ }
3387
+ }
3388
+ function extractImportedNodeTypes(ctx, sourceFile, currentFilePath, importResolver, sourceLoader, warnings) {
3389
+ const importedNodeTypes = [];
3390
+ const imports = sourceFile.getImportDeclarations();
3391
+ for (const importDecl of imports) {
3392
+ const moduleSpecifier = importDecl.getModuleSpecifierValue();
3393
+ if (!moduleSpecifier) {
3394
+ continue;
3395
+ }
3396
+ if (!moduleSpecifier.startsWith(".")) {
3397
+ const packageNodeTypes = resolveNpmPackageTypes(
3398
+ ctx,
3399
+ importDecl,
3400
+ moduleSpecifier,
3401
+ currentFilePath
3402
+ );
3403
+ importedNodeTypes.push(...packageNodeTypes);
3404
+ continue;
3405
+ }
3406
+ const currentDir = path3.dirname(currentFilePath);
3407
+ const importedFilePath = importResolver?.(moduleSpecifier, currentFilePath) ?? resolveModulePath(moduleSpecifier, currentDir, warnings);
3408
+ if (!importedFilePath) {
3409
+ const ext = path3.extname(moduleSpecifier);
3410
+ if (ext && !SOURCE_EXTENSIONS.has(ext)) {
3411
+ continue;
3412
+ }
3413
+ throw new Error(
3414
+ `Import error: File not found for "${moduleSpecifier}"
3415
+ Imported from: ${currentFilePath}
3416
+ Searched extensions: .ts, .tsx, .js, .jsx`
3417
+ );
3418
+ }
3419
+ if (ctx.importStack.has(importedFilePath)) {
3420
+ const cycle = Array.from(ctx.importStack).concat(importedFilePath);
3421
+ throw new Error(`Circular dependency detected:
3422
+ ${cycle.join("\n -> ")}`);
3423
+ }
3424
+ try {
3425
+ let nodeTypes;
3426
+ const overriddenSource = sourceLoader?.(importedFilePath);
3427
+ const importStats = overriddenSource === void 0 ? fs2.statSync(importedFilePath) : { mtimeMs: 0 };
3428
+ if (overriddenSource === void 0) {
3429
+ recordDependency(ctx, importedFilePath, importStats.mtimeMs);
3430
+ }
3431
+ const cached = overriddenSource === void 0 ? ctx.importCache.get(importedFilePath) : void 0;
3432
+ if (cached && cached.mtime === importStats.mtimeMs && dependenciesUnchanged(cached.deps)) {
3433
+ nodeTypes = cached.nodeTypes;
3434
+ for (const dep of cached.deps) recordDependency(ctx, dep.path, dep.mtime);
3435
+ } else {
3436
+ ctx.importStack.add(importedFilePath);
3437
+ const importDeps = /* @__PURE__ */ new Map();
3438
+ ctx.dependencyRecorders.push(importDeps);
3439
+ try {
3440
+ const importedRaw = overriddenSource ?? fs2.readFileSync(importedFilePath, "utf-8");
3441
+ const importedContent = hasInPlaceMarkers(importedRaw) ? stripGeneratedSections(importedRaw) : importedRaw;
3442
+ const importedFile = ctx.project.createSourceFile(importedFilePath, importedContent, {
3443
+ overwrite: true
3444
+ });
3445
+ const importWarnings = [];
3446
+ const localNodeTypes = extractNodeTypes(importedFile, importWarnings, ctx.tagRegistry);
3447
+ const importedFromFile = extractImportedNodeTypes(
3448
+ ctx,
3449
+ importedFile,
3450
+ importedFilePath,
3451
+ importResolver,
3452
+ sourceLoader,
3453
+ warnings
3454
+ );
3455
+ const workflows = extractWorkflows(
3456
+ importedFile,
3457
+ [...localNodeTypes, ...importedFromFile],
3458
+ importedFilePath,
3459
+ [],
3460
+ importWarnings,
3461
+ ctx.tagRegistry,
3462
+ (imp, filePath, importAnnotationWarnings) => resolveImportAnnotation(ctx, imp, filePath, importAnnotationWarnings)
3463
+ );
3464
+ const workflowAsNodeTypes = workflows.map((wf) => workflowToNodeType(wf));
3465
+ nodeTypes = [...localNodeTypes, ...importedFromFile, ...workflowAsNodeTypes];
3466
+ const inferredFromImport = inferAllUnannotatedFunctions(importedFile, nodeTypes);
3467
+ nodeTypes.push(...inferredFromImport);
3468
+ if (overriddenSource === void 0) {
3469
+ ctx.project.removeSourceFile(importedFile);
3470
+ }
3471
+ ctx.importCache.set(importedFilePath, {
3472
+ mtime: importStats.mtimeMs,
3473
+ nodeTypes,
3474
+ deps: [...importDeps].map(([path4, mtime]) => ({ path: path4, mtime }))
3475
+ });
3476
+ } finally {
3477
+ ctx.importStack.delete(importedFilePath);
3478
+ ctx.dependencyRecorders.pop();
3479
+ }
3480
+ }
3481
+ const importedNames = /* @__PURE__ */ new Set();
3482
+ importDecl.getNamedImports().forEach((namedImport) => {
3483
+ importedNames.add(namedImport.getName());
3484
+ });
3485
+ nodeTypes.forEach((nodeType) => {
3486
+ if (importedNames.has(nodeType.functionName)) {
3487
+ importedNodeTypes.push({
3488
+ ...nodeType,
3489
+ sourceLocation: {
3490
+ file: importedFilePath,
3491
+ line: nodeType.sourceLocation?.line || 0,
3492
+ column: nodeType.sourceLocation?.column || 0
3493
+ }
3494
+ });
3495
+ }
3496
+ });
3497
+ } catch (error) {
3498
+ if (error instanceof Error) {
3499
+ throw new Error(`Failed to process import from ${importedFilePath}:
3500
+ ${error.message}`, { cause: error });
3501
+ }
3502
+ throw error;
3503
+ }
3504
+ }
3505
+ return importedNodeTypes;
3506
+ }
3507
+ function resolveNpmPackageTypes(ctx, importDecl, moduleSpecifier, currentFilePath) {
3508
+ const namedImports = importDecl.getNamedImports();
3509
+ if (namedImports.length === 0) return [];
3510
+ const importedNames = /* @__PURE__ */ new Set();
3511
+ namedImports.forEach((ni) => importedNames.add(ni.getName()));
3512
+ const cacheKey = `npm:${moduleSpecifier}`;
3513
+ const npmCached = ctx.importCache.get(cacheKey);
3514
+ if (npmCached) {
3515
+ const currentDir2 = path3.dirname(currentFilePath);
3516
+ const resolvedDts = resolvePackageTypesPath(moduleSpecifier, currentDir2);
3517
+ if (resolvedDts) {
3518
+ try {
3519
+ const dtsStats = fs2.statSync(resolvedDts);
3520
+ if (npmCached.mtime === dtsStats.mtimeMs) {
3521
+ recordDependency(ctx, resolvedDts, dtsStats.mtimeMs);
3522
+ return npmCached.nodeTypes.filter((nt) => importedNames.has(nt.functionName));
3523
+ }
3524
+ } catch {
3525
+ }
3526
+ } else {
3527
+ return npmCached.nodeTypes.filter((nt) => importedNames.has(nt.functionName));
3528
+ }
3529
+ }
3530
+ const currentDir = path3.dirname(currentFilePath);
3531
+ const dtsPath = resolvePackageTypesPath(moduleSpecifier, currentDir);
3532
+ if (!dtsPath) return [];
3533
+ try {
3534
+ const dtsContent = fs2.readFileSync(dtsPath, "utf-8");
3535
+ recordDependency(ctx, dtsPath, fs2.statSync(dtsPath).mtimeMs);
3536
+ const dtsFile = ctx.project.createSourceFile(
3537
+ `__npm_dts__/${moduleSpecifier}.d.ts`,
3538
+ dtsContent,
3539
+ { overwrite: true }
3540
+ );
3541
+ const fns = extractFunctionLikes(dtsFile);
3542
+ const allNodeTypes = [];
3543
+ const seenNames = /* @__PURE__ */ new Set();
3544
+ for (const fn of fns) {
3545
+ const fnName = fn.getName();
3546
+ if (!fnName) continue;
3547
+ if (seenNames.has(fnName)) continue;
3548
+ seenNames.add(fnName);
3549
+ const nodeType = inferNodeTypeFromFunction(fn, fnName, dtsPath);
3550
+ nodeType.importSource = moduleSpecifier;
3551
+ nodeType.functionText = void 0;
3552
+ allNodeTypes.push(nodeType);
3553
+ }
3554
+ ctx.project.removeSourceFile(dtsFile);
3555
+ const dtsMtime = fs2.statSync(dtsPath).mtimeMs;
3556
+ ctx.importCache.set(cacheKey, { mtime: dtsMtime, nodeTypes: allNodeTypes, deps: [] });
3557
+ return allNodeTypes.filter((nt) => importedNames.has(nt.functionName));
3558
+ } catch {
3559
+ return [];
3560
+ }
3561
+ }
3562
+ function resolveImportAnnotation(ctx, imp, currentFilePath, warnings) {
3563
+ const currentDir = path3.dirname(currentFilePath);
3564
+ if (imp.importSource.startsWith(".")) {
3565
+ return resolveLocalImportAnnotation(ctx, imp, currentDir, warnings);
3566
+ } else {
3567
+ return resolveNpmImportAnnotation(ctx, imp, currentDir, warnings);
3568
+ }
3569
+ }
3570
+ function resolveLocalImportAnnotation(ctx, imp, currentDir, warnings) {
3571
+ const importedFilePath = resolveModulePath(imp.importSource, currentDir, warnings);
3572
+ if (!importedFilePath) {
3573
+ warnings.push(`@fwImport: Could not resolve "${imp.importSource}" from ${currentDir}`);
3574
+ return createImportStub(imp);
3575
+ }
3576
+ if (ctx.importStack.has(importedFilePath)) {
3577
+ const cycle = Array.from(ctx.importStack).concat(importedFilePath);
3578
+ warnings.push(`@fwImport: Circular dependency detected:
3579
+ ${cycle.join("\n -> ")}`);
3580
+ return createImportStub(imp);
3581
+ }
3582
+ ctx.importStack.add(importedFilePath);
3583
+ try {
3584
+ const importedContent = fs2.readFileSync(importedFilePath, "utf-8");
3585
+ recordDependency(ctx, importedFilePath, fs2.statSync(importedFilePath).mtimeMs);
3586
+ const importedFile = ctx.project.createSourceFile(importedFilePath, importedContent, {
3587
+ overwrite: true
3588
+ });
3589
+ const fns = extractFunctionLikes(importedFile);
3590
+ const fn = fns.find((f) => f.getName() === imp.functionName);
3591
+ if (!fn) {
3592
+ ctx.project.removeSourceFile(importedFile);
3593
+ return createImportStub(imp);
3594
+ }
3595
+ const nodeType = inferNodeTypeFromFunction(fn, imp.name, importedFilePath);
3596
+ nodeType.importSource = imp.importSource;
3597
+ nodeType.functionText = void 0;
3598
+ ctx.project.removeSourceFile(importedFile);
3599
+ return nodeType;
3600
+ } catch {
3601
+ return createImportStub(imp);
3602
+ } finally {
3603
+ ctx.importStack.delete(importedFilePath);
3604
+ }
3605
+ }
3606
+ function resolveNpmImportAnnotation(ctx, imp, currentDir, warnings) {
3607
+ const cacheKey = `npm:${imp.importSource}`;
3608
+ if (ctx.importCache.has(cacheKey)) {
3609
+ const cached = ctx.importCache.get(cacheKey);
3610
+ const resolvedDts = resolvePackageTypesPath(imp.importSource, currentDir);
3611
+ let cacheValid = false;
3612
+ if (resolvedDts) {
3613
+ try {
3614
+ const dtsStats = fs2.statSync(resolvedDts);
3615
+ cacheValid = cached.mtime === dtsStats.mtimeMs;
3616
+ } catch {
3617
+ }
3618
+ } else {
3619
+ cacheValid = true;
3620
+ }
3621
+ if (cacheValid) {
3622
+ const found = cached.nodeTypes.find((nt) => nt.functionName === imp.functionName);
3623
+ if (found) {
3624
+ return { ...found, name: imp.name, importSource: imp.importSource };
3625
+ }
3626
+ }
3627
+ }
3628
+ const dtsPath = resolvePackageTypesPath(imp.importSource, currentDir);
3629
+ if (!dtsPath) {
3630
+ warnings.push(
3631
+ `@fwImport: Package "${imp.importSource}" has no type declarations (.d.ts). Install @types/${imp.importSource} or add a local wrapper with @flowWeaver nodeType annotations.`
3632
+ );
3633
+ return createImportStub(imp);
3634
+ }
3635
+ try {
3636
+ const allNodeTypes = inferNodeTypesDeep(
3637
+ ctx.project,
3638
+ dtsPath,
3639
+ imp.importSource,
3640
+ /* @__PURE__ */ new Set(),
3641
+ /* @__PURE__ */ new Set(),
3642
+ 0
3643
+ );
3644
+ const dtsMtime2 = fs2.statSync(dtsPath).mtimeMs;
3645
+ recordDependency(ctx, dtsPath, dtsMtime2);
3646
+ ctx.importCache.set(cacheKey, { mtime: dtsMtime2, nodeTypes: allNodeTypes, deps: [] });
3647
+ const found = allNodeTypes.find((nt) => nt.functionName === imp.functionName);
3648
+ if (found) {
3649
+ return { ...found, name: imp.name, importSource: imp.importSource };
3650
+ }
3651
+ warnings.push(
3652
+ `@fwImport: Function "${imp.functionName}" not found in type declarations for "${imp.importSource}". Available exports: ${allNodeTypes.map((nt) => nt.functionName).join(", ") || "(none)"}.`
3653
+ );
3654
+ } catch (err) {
3655
+ warnings.push(
3656
+ `@fwImport: Failed to parse type declarations for "${imp.importSource}": ${err.message}. Node "${imp.name}" will use a generic stub.`
3657
+ );
3658
+ }
3659
+ return createImportStub(imp);
3660
+ }
3661
+ function inferNodeTypesDeep(project, dtsPath, importSource, visitedFiles, seenNames, depth) {
3662
+ const MAX_DEPTH = 8;
3663
+ const resolved = path3.resolve(dtsPath);
3664
+ if (visitedFiles.has(resolved) || depth > MAX_DEPTH) return [];
3665
+ visitedFiles.add(resolved);
3666
+ let dtsContent;
3667
+ try {
3668
+ dtsContent = fs2.readFileSync(resolved, "utf-8");
3669
+ } catch (err) {
3670
+ if (depth === 0) throw err;
3671
+ return [];
3672
+ }
3673
+ const sf = project.createSourceFile(
3674
+ `__npm_dts__/${resolved.replace(/[^A-Za-z0-9._-]/g, "_")}.d.ts`,
3675
+ dtsContent,
3676
+ { overwrite: true }
3677
+ );
3678
+ const out = [];
3679
+ try {
3680
+ for (const fn of extractFunctionLikes(sf)) {
3681
+ const fnName = fn.getName();
3682
+ if (!fnName) continue;
3683
+ if (seenNames.has(fnName)) continue;
3684
+ seenNames.add(fnName);
3685
+ const nodeType = inferNodeTypeFromFunction(fn, fnName, resolved);
3686
+ nodeType.importSource = importSource;
3687
+ nodeType.functionText = void 0;
3688
+ out.push(nodeType);
3689
+ }
3690
+ const baseDir = path3.dirname(resolved);
3691
+ for (const exp of sf.getExportDeclarations()) {
3692
+ const spec = exp.getModuleSpecifierValue();
3693
+ if (!spec || !spec.startsWith(".")) continue;
3694
+ const target = resolveReExportedDts(baseDir, spec);
3695
+ if (!target) continue;
3696
+ out.push(
3697
+ ...inferNodeTypesDeep(project, target, importSource, visitedFiles, seenNames, depth + 1)
3698
+ );
3699
+ }
3700
+ } finally {
3701
+ project.removeSourceFile(sf);
3702
+ }
3703
+ return out;
3704
+ }
3705
+
3706
+ // src/parser/external-node-types.ts
3707
+ function externalToAST(ext) {
3708
+ const inputs = {};
3709
+ const outputs = {};
3710
+ const isExpression = ext.expression === true;
3711
+ if (ext.ports) {
3712
+ for (const port of ext.ports) {
3713
+ const def = {
3714
+ dataType: port.type || "ANY",
3715
+ ...port.defaultLabel && { label: port.defaultLabel }
3716
+ };
3717
+ if (port.direction === "OUTPUT") {
3718
+ outputs[port.name] = def;
3719
+ } else {
3720
+ inputs[port.name] = def;
3721
+ }
3722
+ }
3723
+ }
3724
+ if (!inputs.execute) {
3725
+ inputs.execute = { dataType: "STEP", label: "Execute" };
3726
+ }
3727
+ if (!outputs.onSuccess) {
3728
+ outputs.onSuccess = { dataType: "STEP", label: "On Success", isControlFlow: true };
3729
+ }
3730
+ if (!outputs.onFailure) {
3731
+ outputs.onFailure = {
3732
+ dataType: "STEP",
3733
+ label: "On Failure",
3734
+ isControlFlow: true,
3735
+ failure: true
3736
+ };
3737
+ }
3738
+ return {
3739
+ type: "NodeType",
3740
+ name: ext.name,
3741
+ functionName: ext.functionName || ext.name,
3742
+ inputs,
3743
+ outputs,
3744
+ hasSuccessPort: "onSuccess" in outputs,
3745
+ hasFailurePort: "onFailure" in outputs,
3746
+ // Honor the supplied async flag so codegen emits `await` for an async
3747
+ // foreign node (e.g. pack-core `waitForApproval`). Defaults to sync
3748
+ // when the caller doesn't say, preserving prior behavior.
3749
+ isAsync: ext.isAsync === true || ext.durableEffect === true,
3750
+ executeWhen: EXECUTION_STRATEGIES.CONJUNCTION,
3751
+ variant: "FUNCTION",
3752
+ // Honor the expression flag so codegen calls the node WITHOUT the
3753
+ // leading `execute` arg (e.g. pack-core `resolveMonth(spec)`).
3754
+ ...isExpression && { expression: true },
3755
+ ...ext.durableGate && { durableGate: ext.durableGate },
3756
+ ...ext.durableEffect === true && { durableEffect: true },
3757
+ ...ext.durablePure === true && { durablePure: true },
3758
+ ...ext.resilience && { resilience: ext.resilience }
3759
+ };
3760
+ }
3761
+ function mergeExternalNodeTypes(nodeTypes, externalNodeTypes) {
3762
+ for (const ext of externalNodeTypes) {
3763
+ const existingIdx = nodeTypes.findIndex(
3764
+ (nt) => nt.name === ext.name || nt.functionName === ext.name
3765
+ );
3766
+ if (existingIdx === -1) {
3767
+ nodeTypes.push(externalToAST(ext));
3768
+ continue;
3769
+ }
3770
+ if (isImportStub(nodeTypes[existingIdx])) {
3771
+ const replacement = externalToAST(ext);
3772
+ const stubImportSource = nodeTypes[existingIdx].importSource;
3773
+ if (stubImportSource) {
3774
+ replacement.importSource = stubImportSource;
3775
+ }
3776
+ nodeTypes[existingIdx] = replacement;
3777
+ }
3778
+ }
3779
+ }
3780
+
3781
+ // src/parser/annotation-suggestion.ts
3782
+ function generateAnnotationSuggestion(project, content, cursorLine, virtualPath = "virtual.ts") {
3783
+ const existingFile = project.getSourceFile(virtualPath);
3784
+ if (existingFile) {
3785
+ project.removeSourceFile(existingFile);
3786
+ }
3787
+ const contentLines = content.split(/\r?\n/);
3788
+ let typedJsDocStart = /^\s*\/\*\*\s*$/.test(contentLines[cursorLine] ?? "");
3789
+ for (let i = cursorLine + 1; typedJsDocStart && i < contentLines.length; i++) {
3790
+ const line = contentLines[i].trim();
3791
+ if (!line.startsWith("*")) break;
3792
+ if (line.includes("*/")) typedJsDocStart = false;
3793
+ }
3794
+ const parseContent = typedJsDocStart ? contentLines.map((line, i) => i === cursorLine ? "" : line).join("\n") : content;
3795
+ const sourceFile = project.createSourceFile(virtualPath, parseContent, { overwrite: true });
3796
+ try {
3797
+ const allFunctions = extractFunctionLikes(sourceFile);
3798
+ if (allFunctions.length === 0) return null;
3799
+ let targetFn = null;
3800
+ let bestDistance = Infinity;
3801
+ for (const fn of allFunctions) {
3802
+ const fnLine = fn.getStartLineNumber(false) - 1;
3803
+ const distance = fnLine >= cursorLine ? fnLine - cursorLine : cursorLine - fnLine + 1e3;
3804
+ if (distance < bestDistance) {
3805
+ bestDistance = distance;
3806
+ targetFn = fn;
3807
+ }
3808
+ }
3809
+ if (!targetFn) return null;
3810
+ const fnName = targetFn.getName() || "anonymous";
3811
+ const fnStartLine = targetFn.getStartLineNumber(false) - 1;
3812
+ if (cursorLine < fnStartLine - 30) return null;
3813
+ const hasAnnotation = hasFlowWeaverAnnotation(targetFn);
3814
+ const hasAnyJsDoc = targetFn.getJsDocs().length > 0;
3815
+ if (hasAnyJsDoc && !hasAnnotation) return null;
3816
+ const inferred = inferNodeTypeFromFunction(targetFn, fnName, virtualPath);
3817
+ const paramDescriptions = /* @__PURE__ */ new Map();
3818
+ for (const doc of targetFn.getJsDocs()) {
3819
+ for (const tag of doc.getTags()) {
3820
+ if (tag.getTagName() === "param") {
3821
+ const comment = tag.getCommentText?.()?.trim() || "";
3822
+ const paramMatch = comment.match(/^(?:\{[^}]*\}\s+)?(\w+)(?:\s*-\s*|\s+)(.+)/);
3823
+ if (paramMatch) {
3824
+ paramDescriptions.set(paramMatch[1], paramMatch[2]);
3825
+ }
3826
+ }
3827
+ }
3828
+ }
3829
+ for (const [portName, portDef] of Object.entries(inferred.inputs)) {
3830
+ const desc = paramDescriptions.get(portName);
3831
+ if (desc) {
3832
+ portDef.label = desc;
3833
+ }
3834
+ }
3835
+ const existingPorts = extractExistingAnnotatedPorts(targetFn);
3836
+ const missingLines = [];
3837
+ for (const [portName, portDef] of Object.entries(inferred.inputs)) {
3838
+ if (isControlFlowPort(portName)) continue;
3839
+ if (existingPorts.inputs.has(portName)) continue;
3840
+ missingLines.push(` * ${generateJSDocPortTag(portName, portDef, "input")}`);
3841
+ }
3842
+ for (const [portName, portDef] of Object.entries(inferred.outputs)) {
3843
+ if (isControlFlowPort(portName)) continue;
3844
+ if (existingPorts.outputs.has(portName)) continue;
3845
+ missingLines.push(` * ${generateJSDocPortTag(portName, portDef, "output")}`);
3846
+ }
3847
+ if (hasAnnotation) {
3848
+ const isWorkflow = isWorkflowBlock(targetFn);
3849
+ if (isWorkflow) {
3850
+ const connectionLines = generateWorkflowStructureSuggestion(targetFn, sourceFile);
3851
+ missingLines.push(...connectionLines);
3852
+ }
3853
+ if (missingLines.length === 0) return null;
3854
+ const lines2 = content.split(/\r?\n/);
3855
+ let jsDocEndLine = -1;
3856
+ for (let i = fnStartLine - 1; i >= 0; i--) {
3857
+ if (lines2[i].includes("*/")) {
3858
+ jsDocEndLine = i;
3859
+ break;
3860
+ }
3861
+ }
3862
+ if (jsDocEndLine < 0) return null;
3863
+ const text2 = missingLines.join("\n") + "\n";
3864
+ return {
3865
+ text: text2,
3866
+ insertLine: jsDocEndLine,
3867
+ replaceLinesCount: 0
3868
+ };
3869
+ }
3870
+ const lines = content.split(/\r?\n/);
3871
+ const cursorLineText = lines[cursorLine] || "";
3872
+ if (/^\s*\/\*\*\s*$/.test(cursorLineText)) {
3873
+ const continuationLines = [
3874
+ ` * @flowWeaver nodeType ${fnName}`,
3875
+ ...inferred.expression ? [" * @expression"] : [],
3876
+ ...missingLines,
3877
+ " */"
3878
+ ];
3879
+ const text2 = continuationLines.join("\n") + "\n";
3880
+ return {
3881
+ text: text2,
3882
+ insertLine: cursorLine + 1,
3883
+ replaceLinesCount: 0
3884
+ };
3885
+ }
3886
+ const allLines = [
3887
+ "/**",
3888
+ ` * @flowWeaver nodeType ${fnName}`,
3889
+ ...inferred.expression ? [" * @expression"] : [],
3890
+ ...missingLines,
3891
+ " */"
3892
+ ];
3893
+ const text = allLines.join("\n") + "\n";
3894
+ return {
3895
+ text,
3896
+ insertLine: fnStartLine,
3897
+ replaceLinesCount: 0
3898
+ };
3899
+ } finally {
3900
+ const sf = project.getSourceFile(virtualPath);
3901
+ if (sf) project.removeSourceFile(sf);
3902
+ }
3903
+ }
3904
+ function isWorkflowBlock(fn) {
3905
+ for (const doc of fn.getJsDocs()) {
3906
+ for (const tag of doc.getTags()) {
3907
+ if (tag.getTagName() !== "flowWeaver") continue;
3908
+ const comment = tag.getCommentText?.()?.trim() || "";
3909
+ const firstWord = comment.split(/\s/)[0];
3910
+ if (firstWord !== "nodeType") {
3911
+ return true;
3912
+ }
3913
+ }
3914
+ }
3915
+ return false;
3916
+ }
3917
+ function generateWorkflowStructureSuggestion(fn, sourceFile) {
3918
+ const nodeDecls = /* @__PURE__ */ new Map();
3919
+ const existingConnections = /* @__PURE__ */ new Set();
3920
+ for (const doc of fn.getJsDocs()) {
3921
+ for (const tag of doc.getTags()) {
3922
+ const tagName = tag.getTagName();
3923
+ const comment = tag.getCommentText?.()?.trim() || "";
3924
+ if (tagName === "node") {
3925
+ const nodeMatch = comment.match(/^(\w+)\s+(\w+)/);
3926
+ if (nodeMatch) {
3927
+ nodeDecls.set(nodeMatch[1], nodeMatch[2]);
3928
+ }
3929
+ } else if (tagName === "connect") {
3930
+ const connMatch = comment.match(/^(\w+)\.(\w+)\s*->\s*(\w+)\.(\w+)/);
3931
+ if (connMatch) {
3932
+ existingConnections.add(`${connMatch[1]}.${connMatch[2]}->${connMatch[3]}.${connMatch[4]}`);
3933
+ }
3934
+ }
3935
+ }
3936
+ }
3937
+ if (nodeDecls.size < 2) return [];
3938
+ const allFunctions = extractFunctionLikes(sourceFile);
3939
+ const resolvedTypes = /* @__PURE__ */ new Map();
3940
+ for (const [nodeId, typeName] of nodeDecls) {
3941
+ const matchedFn = allFunctions.find((f) => f.getName() === typeName);
3942
+ if (matchedFn) {
3943
+ resolvedTypes.set(nodeId, inferNodeTypeFromFunction(matchedFn, typeName, sourceFile.getFilePath()));
3944
+ }
3945
+ }
3946
+ const suggestions = [];
3947
+ const nodeIds = [...nodeDecls.keys()];
3948
+ for (let i = 0; i < nodeIds.length; i++) {
3949
+ for (let j = 0; j < nodeIds.length; j++) {
3950
+ if (i === j) continue;
3951
+ const srcId = nodeIds[i];
3952
+ const tgtId = nodeIds[j];
3953
+ const srcType = resolvedTypes.get(srcId);
3954
+ const tgtType = resolvedTypes.get(tgtId);
3955
+ if (!srcType || !tgtType) continue;
3956
+ for (const [outputName, outputDef] of Object.entries(srcType.outputs)) {
3957
+ if (isControlFlowPort(outputName)) continue;
3958
+ if (outputDef.dataType === "STEP") continue;
3959
+ if (outputName in tgtType.inputs && !isControlFlowPort(outputName)) {
3960
+ const connKey = `${srcId}.${outputName}->${tgtId}.${outputName}`;
3961
+ if (!existingConnections.has(connKey)) {
3962
+ suggestions.push(` * @connect ${srcId}.${outputName} -> ${tgtId}.${outputName}`);
3963
+ existingConnections.add(connKey);
3964
+ }
3965
+ }
3966
+ }
3967
+ }
3968
+ }
3969
+ return suggestions;
3970
+ }
3971
+ function extractExistingAnnotatedPorts(fn) {
3972
+ const inputs = /* @__PURE__ */ new Set();
3973
+ const outputs = /* @__PURE__ */ new Set();
3974
+ for (const doc of fn.getJsDocs()) {
3975
+ for (const tag of doc.getTags()) {
3976
+ const tagName = tag.getTagName();
3977
+ const comment = tag.getCommentText?.()?.trim() || "";
3978
+ const nameMatch = comment.match(/^\[?(\w+)/);
3979
+ if (!nameMatch) continue;
3980
+ const portName = nameMatch[1];
3981
+ if (tagName === "input" || tagName === "step") {
3982
+ inputs.add(portName);
3983
+ } else if (tagName === "output") {
3984
+ outputs.add(portName);
3985
+ }
3986
+ }
3987
+ }
3988
+ return { inputs, outputs };
3989
+ }
3990
+
3991
+ // src/parser/pack-handlers.ts
3992
+ async function registerPackHandlers(tagRegistry, projectDir) {
3993
+ const { discoverTagHandlers, discoverValidationRuleSets } = await import("./registry-K2U5KUTY.js");
3994
+ const { pathToFileURL } = await import("node:url");
3995
+ const handlers = await discoverTagHandlers(projectDir);
3996
+ for (const discovered of handlers) {
3997
+ const handlerAlreadyRegistered = discovered.tags.every((t) => tagRegistry.has(t));
3998
+ try {
3999
+ const mod = await import(pathToFileURL(discovered.absoluteFile).href);
4000
+ if (!handlerAlreadyRegistered) {
4001
+ const handlerFn = discovered.exportName ? mod[discovered.exportName] : mod.default;
4002
+ if (typeof handlerFn === "function") {
4003
+ tagRegistry.register(
4004
+ discovered.tags,
4005
+ discovered.namespace,
4006
+ discovered.scope,
4007
+ handlerFn
4008
+ );
4009
+ }
4010
+ }
4011
+ if (discovered.serializerExport) {
4012
+ const serializerFn = mod[discovered.serializerExport];
4013
+ if (typeof serializerFn === "function") {
4014
+ tagRegistry.registerSerializer(discovered.namespace, serializerFn);
4015
+ }
4016
+ }
4017
+ } catch {
4018
+ }
4019
+ }
4020
+ const { validationRuleRegistry } = await import("./validation-registry-IQZX3UE3.js");
4021
+ const ruleSets = await discoverValidationRuleSets(projectDir);
4022
+ for (const ruleSet of ruleSets) {
4023
+ try {
4024
+ const mod = await import(pathToFileURL(ruleSet.absoluteFile).href);
4025
+ const detectFn = mod[ruleSet.detectExport ?? "detect"];
4026
+ const getRulesFn = mod[ruleSet.rulesExport ?? "getRules"];
4027
+ if (typeof detectFn === "function" && typeof getRulesFn === "function") {
4028
+ validationRuleRegistry.register({
4029
+ name: ruleSet.name,
4030
+ namespace: ruleSet.namespace,
4031
+ detect: detectFn,
4032
+ getRules: getRulesFn
4033
+ });
4034
+ }
4035
+ } catch {
4036
+ }
4037
+ }
4038
+ }
4039
+
4040
+ // src/parser/annotation-parser.ts
4041
+ var AnnotationParser = class {
4042
+ project;
4043
+ importCache = new LRUCache(200);
4044
+ importStack = /* @__PURE__ */ new Set();
4045
+ parseCache = new LRUCache(100);
4046
+ /**
4047
+ * Dependency recorders for the parses in progress: the outer entry belongs to
4048
+ * the workflow file, and each imported file being processed pushes its own so
4049
+ * its importCache entry can list what it read. A file read while any recorder
4050
+ * is active is added to all of them.
4051
+ */
4052
+ dependencyRecorders = [];
4053
+ /** Tag handler registry. Defaults to the global singleton (pre-populated by extensions). */
4054
+ tagRegistry = tagHandlerRegistry;
4055
+ /** Tracks which projectDirs have already had their pack handlers loaded. */
4056
+ loadedPackDirs = /* @__PURE__ */ new Set();
4057
+ constructor(project = getSharedProject()) {
4058
+ this.project = project;
4059
+ }
4060
+ /**
4061
+ * Discover and register tag handlers from installed marketplace packs.
4062
+ * Results are cached per projectDir so repeated parse calls skip the scan.
4063
+ */
4064
+ async loadPackHandlers(projectDir) {
4065
+ if (this.loadedPackDirs.has(projectDir)) return;
4066
+ this.loadedPackDirs.add(projectDir);
4067
+ await registerPackHandlers(this.tagRegistry, projectDir);
4068
+ }
4069
+ computeHash(content) {
4070
+ return createHash("sha256").update(content).digest("hex").slice(0, 16);
4071
+ }
4072
+ /** The import state this parser shares with the import resolution functions. */
4073
+ importContext() {
4074
+ return {
4075
+ project: this.project,
4076
+ tagRegistry: this.tagRegistry,
4077
+ importCache: this.importCache,
4078
+ importStack: this.importStack,
4079
+ dependencyRecorders: this.dependencyRecorders
4080
+ };
4081
+ }
4082
+ parse(filePath, externalNodeTypes) {
4083
+ const stats = fs3.statSync(filePath);
4084
+ const hasExternalTypes = externalNodeTypes && externalNodeTypes.length > 0;
4085
+ if (!hasExternalTypes) {
4086
+ const cached = this.parseCache.get(filePath);
4087
+ const reusable = cached !== void 0 && dependenciesUnchanged(cached.deps);
4088
+ if (cached && reusable && cached.mtime === stats.mtimeMs) {
4089
+ return cached.result;
4090
+ }
4091
+ const rawContent2 = fs3.readFileSync(filePath, "utf-8");
4092
+ const content2 = hasInPlaceMarkers(rawContent2) ? stripGeneratedSections(rawContent2) : rawContent2;
4093
+ const hash2 = this.computeHash(content2);
4094
+ if (cached && reusable && cached.contentHash === hash2) {
4095
+ cached.mtime = stats.mtimeMs;
4096
+ return cached.result;
4097
+ }
4098
+ return this.fullParse(filePath, content2, hash2, stats.mtimeMs);
4099
+ }
4100
+ const rawContent = fs3.readFileSync(filePath, "utf-8");
4101
+ const content = hasInPlaceMarkers(rawContent) ? stripGeneratedSections(rawContent) : rawContent;
4102
+ const hash = this.computeHash(content);
4103
+ return this.fullParse(filePath, content, hash, stats.mtimeMs, externalNodeTypes);
4104
+ }
4105
+ /**
4106
+ * Parse an in-memory source override at its real filesystem path. Relative
4107
+ * imports resolve exactly as they do for parse(), but the override is never
4108
+ * written to disk or stored in the parse cache.
4109
+ */
4110
+ parseSourceAtPath(filePath, content, externalNodeTypes, importResolver, sourceLoader) {
4111
+ return this.fullParse(
4112
+ filePath,
4113
+ content,
4114
+ this.computeHash(content),
4115
+ 0,
4116
+ externalNodeTypes,
4117
+ false,
4118
+ importResolver,
4119
+ sourceLoader
4120
+ );
4121
+ }
4122
+ fullParse(filePath, content, hash, mtimeMs, externalNodeTypes, cacheResult = true, importResolver, sourceLoader) {
4123
+ this.importStack.clear();
4124
+ const deps = /* @__PURE__ */ new Map();
4125
+ this.dependencyRecorders = [deps];
4126
+ const ctx = this.importContext();
4127
+ const errors = [];
4128
+ const warnings = [];
4129
+ if (sourceLoader !== void 0) {
4130
+ preloadSourceOverrides(
4131
+ this.project,
4132
+ filePath,
4133
+ content,
4134
+ importResolver,
4135
+ sourceLoader,
4136
+ /* @__PURE__ */ new Set([filePath])
4137
+ );
4138
+ }
4139
+ const sourceFile = this.project.createSourceFile(filePath, content, { overwrite: true });
4140
+ this.importStack.add(filePath);
4141
+ const importedNodeTypes = sourceLoader === void 0 ? [] : extractImportedNodeTypes(ctx, sourceFile, filePath, importResolver, sourceLoader, warnings);
4142
+ const localNodeTypes = extractNodeTypes(sourceFile, warnings, this.tagRegistry);
4143
+ if (sourceLoader === void 0) {
4144
+ importedNodeTypes.push(...extractImportedNodeTypes(
4145
+ ctx,
4146
+ sourceFile,
4147
+ filePath,
4148
+ importResolver,
4149
+ sourceLoader,
4150
+ warnings
4151
+ ));
4152
+ }
4153
+ const workflowSignatures = extractWorkflowSignatures(sourceFile, filePath, warnings, this.tagRegistry);
4154
+ const sameFileWorkflowNodeTypes = workflowSignatures.map((wf) => workflowToNodeType(wf));
4155
+ const nodeTypes = [...localNodeTypes, ...importedNodeTypes, ...sameFileWorkflowNodeTypes];
4156
+ if (externalNodeTypes?.length) {
4157
+ mergeExternalNodeTypes(nodeTypes, externalNodeTypes);
4158
+ }
4159
+ const inferredNodeTypes = inferNodeTypesFromUnannotated(sourceFile, nodeTypes, localNodeTypes, warnings);
4160
+ nodeTypes.push(...inferredNodeTypes);
4161
+ const workflows = extractWorkflows(
4162
+ sourceFile,
4163
+ nodeTypes,
4164
+ filePath,
4165
+ errors,
4166
+ warnings,
4167
+ this.tagRegistry,
4168
+ (imp, currentFilePath, importWarnings) => resolveImportAnnotation(ctx, imp, currentFilePath, importWarnings)
4169
+ );
4170
+ const dedupedWarnings = [...new Set(warnings)];
4171
+ const result = { workflows, nodeTypes, errors, warnings: dedupedWarnings };
4172
+ this.project.removeSourceFile(sourceFile);
4173
+ this.dependencyRecorders = [];
4174
+ if (cacheResult && !externalNodeTypes?.length) {
4175
+ this.parseCache.set(filePath, {
4176
+ mtime: mtimeMs,
4177
+ contentHash: hash,
4178
+ result,
4179
+ deps: [...deps].map(([path4, mtime]) => ({ path: path4, mtime }))
4180
+ });
4181
+ }
4182
+ return result;
4183
+ }
4184
+ /**
4185
+ * Parse workflow from a string instead of a file path.
4186
+ * Useful for testing and in-memory operations.
4187
+ *
4188
+ * Note: Imports from other workflow files are NOT supported in this mode
4189
+ * since there's no filesystem context. Use parse() for files with imports.
4190
+ *
4191
+ * @param code - TypeScript source code containing workflow definitions
4192
+ * @param virtualPath - Virtual file path for error messages (default: 'virtual.ts')
4193
+ * @returns ParseResult with workflows and nodeTypes
4194
+ */
4195
+ parseFromString(code, virtualPath = "virtual.ts") {
4196
+ this.importStack.clear();
4197
+ const existingFile = this.project.getSourceFile(virtualPath);
4198
+ if (existingFile) {
4199
+ this.project.removeSourceFile(existingFile);
4200
+ }
4201
+ const sourceFile = this.project.createSourceFile(virtualPath, code, { overwrite: true });
4202
+ const errors = [];
4203
+ const warnings = [];
4204
+ const localNodeTypes = extractNodeTypes(sourceFile, warnings, this.tagRegistry);
4205
+ const workflowSignatures = extractWorkflowSignatures(sourceFile, virtualPath, warnings, this.tagRegistry);
4206
+ const sameFileWorkflowNodeTypes = workflowSignatures.map((wf) => workflowToNodeType(wf));
4207
+ const nodeTypes = [...localNodeTypes, ...sameFileWorkflowNodeTypes];
4208
+ const inferredNodeTypes = inferNodeTypesFromUnannotated(sourceFile, nodeTypes, localNodeTypes, warnings);
4209
+ nodeTypes.push(...inferredNodeTypes);
4210
+ const ctx = this.importContext();
4211
+ const workflows = extractWorkflows(
4212
+ sourceFile,
4213
+ nodeTypes,
4214
+ virtualPath,
4215
+ errors,
4216
+ warnings,
4217
+ this.tagRegistry,
4218
+ (imp, currentFilePath, importWarnings) => resolveImportAnnotation(ctx, imp, currentFilePath, importWarnings)
4219
+ );
4220
+ this.project.removeSourceFile(sourceFile);
4221
+ const dedupedWarnings = [...new Set(warnings)];
4222
+ return {
4223
+ workflows,
4224
+ nodeTypes,
4225
+ errors,
4226
+ warnings: dedupedWarnings
4227
+ };
4228
+ }
4229
+ clearCache() {
4230
+ this.importCache.clear();
4231
+ this.parseCache.clear();
4232
+ }
4233
+ /** Clear only the parse result cache, keeping the import/node-type cache intact. */
4234
+ clearParseCache() {
4235
+ this.parseCache.clear();
4236
+ }
4237
+ /**
4238
+ * Suggest the `@flowWeaver` JSDoc for the function at or below `cursorLine`
4239
+ * (0-based) in `content`. Returns the text to insert and where, or null when
4240
+ * there is nothing to suggest.
4241
+ */
4242
+ generateAnnotationSuggestion(content, cursorLine, virtualPath = "virtual.ts") {
4243
+ return generateAnnotationSuggestion(this.project, content, cursorLine, virtualPath);
4244
+ }
4245
+ };
4246
+ var parser = new AnnotationParser();
4247
+
4248
+ export {
4249
+ MARKERS,
4250
+ hasInPlaceMarkers,
4251
+ stripGeneratedSections,
4252
+ findClosestMatches,
4253
+ resolveNpmNodeTypes,
4254
+ AnnotationParser,
4255
+ parser
4256
+ };