@uipath/flow-tool 1.201.0 → 1.202.0-preview.136

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 (234) hide show
  1. package/dist/{authoring-7r6g06c7.js → authoring-wpa6d0vf.js} +74 -48
  2. package/dist/binding-service-dh91hw9e.js +141 -0
  3. package/dist/{browser-strategy-rkcvc6tn.js → browser-strategy-6atc7v8s.js} +3 -3
  4. package/dist/connector-service-d9ph9kx1.js +948 -0
  5. package/dist/{conversion-H2VEEYLB-ng48mbf7.js → conversion-QANACVCM-zs0hhfjv.js} +39 -33
  6. package/dist/{de-5KVP66U6-f7knj511.js → de-5KVP66U6-1bnf4zt5.js} +52 -52
  7. package/dist/de-6U7ECGHH-xwsw33fk.js +35 -0
  8. package/dist/{de-5HU6GFWV-4EZK6G7N-yrh21f52.js → de-7XQXX2DK-IDWR6CAR-n4z245kt.js} +857 -845
  9. package/dist/{de-5HU6GFWV-zheyw6d2.js → de-7XQXX2DK-tqdy5n2b.js} +857 -845
  10. package/dist/{de-HKTOVV4H-d5yw5j21.js → de-HKTOVV4H-pe9w0xn8.js} +46 -46
  11. package/dist/{de-XLT4QPIP-0rtw349w.js → de-XLT4QPIP-kj81dxjc.js} +9 -9
  12. package/dist/debug-conversation-trigger-452frzyz.js +41 -0
  13. package/dist/debug-http-client-wd6xb8v4.js +31 -0
  14. package/dist/debug-service-fvyexnb1.js +58 -0
  15. package/dist/edge-service-e77bndbe.js +162 -0
  16. package/dist/{elk.bundled-pydbzeez.js → elk.bundled-vpsbxz0p.js} +3 -3
  17. package/dist/{en-MABQK6C4-REWE2WG2-8dp4cqdg.js → en-5ZGC5VQ3-EWX7ILY7-rmtj70fk.js} +898 -898
  18. package/dist/{en-MABQK6C4-nkzq2j8t.js → en-5ZGC5VQ3-h581y30k.js} +897 -897
  19. package/dist/en-EPWMLP2N-2wvge238.js +28 -0
  20. package/dist/{en-UNT7BE26-rhh65jry.js → en-LQHKFSEY-vvbe8ve9.js} +13 -11
  21. package/dist/{en-P4AS26D7-szrzfxz1.js → en-P4AS26D7-zptp77bm.js} +45 -45
  22. package/dist/{en-4KXU7N7B-66fntxa2.js → en-X3S6IZ5J-nhkg6pwn.js} +54 -60
  23. package/dist/{es-MX-H2EAXLYI-qwnqt48x.js → es-MX-H2EAXLYI-j42kfkxy.js} +46 -46
  24. package/dist/es-MX-NHTIP5YM-ar6zfx95.js +35 -0
  25. package/dist/{es-MX-OKNDG2NH-c1k1s1tg.js → es-MX-OKNDG2NH-tcac6j4g.js} +9 -9
  26. package/dist/{es-MX-POESXYP2-UW6VP5QI-cd3a79g9.js → es-MX-U2VN3SZW-KYAJ2ONK-kdram1g1.js} +857 -845
  27. package/dist/{es-MX-POESXYP2-9538722k.js → es-MX-U2VN3SZW-anynsmd8.js} +857 -845
  28. package/dist/{es-MX-XAVLOQW3-9b3cp9n8.js → es-MX-XAVLOQW3-q00km2y7.js} +52 -52
  29. package/dist/{es-NQICVYSQ-aa9z3nhs.js → es-NQICVYSQ-3dtqgget.js} +9 -9
  30. package/dist/{es-O4PAV2CR-jwfaawwk.js → es-O4PAV2CR-0g23ve3v.js} +46 -46
  31. package/dist/es-PQ3RA33Q-y4kxhjfr.js +35 -0
  32. package/dist/{es-VFPNVMP5-thm0z9sr.js → es-VFPNVMP5-bx2c337j.js} +52 -52
  33. package/dist/{es-LUTYN7U7-IY5QWOUF-k2aefzc0.js → es-ZGCPPOME-24PJEGPV-rn86z9kn.js} +857 -845
  34. package/dist/{es-LUTYN7U7-ye5zn4sn.js → es-ZGCPPOME-8gazspjj.js} +857 -845
  35. package/dist/flow-api-wv8p8xbd.js +36 -0
  36. package/dist/flow-debug-service-tfbefas6.js +741 -0
  37. package/dist/flow-eval-node-target-c6wea7rz.js +44 -0
  38. package/dist/flow-eval-run-service-01kdky72.js +961 -0
  39. package/dist/flow-eval-service-ft8e16jz.js +1338 -0
  40. package/dist/flow-init-service-mva4crty.js +35 -0
  41. package/dist/flow-io-r318sjrw.js +36 -0
  42. package/dist/flow-migrate-service-rwcdx60q.js +119 -0
  43. package/dist/flow-pack-service-p4hxyj9e.js +280 -0
  44. package/dist/flow-validate-service-j25pxpwz.js +57 -0
  45. package/dist/{fr-5YRGHXF5-q6b63yg0.js → fr-5YRGHXF5-kz1ywpv6.js} +46 -46
  46. package/dist/{fr-E5MDO4EG-exvrs7ge.js → fr-E5MDO4EG-c3mkty2t.js} +52 -52
  47. package/dist/{fr-PFHIL7YZ-cxnshwa8.js → fr-PFHIL7YZ-2n589p47.js} +9 -9
  48. package/dist/fr-R4L3OAWI-30khpsmn.js +35 -0
  49. package/dist/{fr-LJIK56LW-STG6QR3T-cextvv8q.js → fr-T3G5GZCT-TU4IKBEG-k6xz1s1f.js} +857 -845
  50. package/dist/{fr-LJIK56LW-xf3xf2kh.js → fr-T3G5GZCT-y3f7xb1q.js} +857 -845
  51. package/dist/governance-fetcher-j9cx4f1d.js +391 -0
  52. package/dist/headless-h1myzz32.js +177196 -0
  53. package/dist/hitl-service-kvt5wms4.js +256 -0
  54. package/dist/index-1kgxzh8x.js +143 -0
  55. package/dist/index-4zrwgb3c.js +111 -0
  56. package/dist/index-ev4mdg5y.js +4801 -0
  57. package/dist/{index-er6vy3jk.js → index-eybzsdcc.js} +295 -317
  58. package/dist/{index-hsadteg4.js → index-h8cph72k.js} +4 -4
  59. package/dist/{index-p50kx6jv.js → index-k5tbd184.js} +276 -276
  60. package/dist/index-n33np76r.js +630 -0
  61. package/dist/{index-9f8q2ege.js → index-p3vk57z7.js} +27 -27
  62. package/dist/{index-dhcd9b82.js → index-w0z4s69j.js} +166 -81
  63. package/dist/index.js +29 -32
  64. package/dist/{index.umd.min-drpc57vn.js → index.umd.min-fqefd9kn.js} +3 -3
  65. package/dist/init.js +24 -25
  66. package/dist/input-reader-6pwhtp8v.js +11 -0
  67. package/dist/{ja-FGEGLBJ3-w9byjhze.js → ja-BI5K3JDZ-77zat4z2.js} +857 -845
  68. package/dist/{ja-FGEGLBJ3-MG3BSWXD-vq19zt2p.js → ja-BI5K3JDZ-GTIHISTZ-s6n3r2ab.js} +857 -845
  69. package/dist/{ja-DPO5PPLO-s2a7j3nj.js → ja-DPO5PPLO-mysfmznx.js} +52 -52
  70. package/dist/{ja-P4OSE367-8ywxep9a.js → ja-P4OSE367-srr3qypg.js} +9 -9
  71. package/dist/{ja-SDAPAVCR-943p5gx7.js → ja-SDAPAVCR-kg39dfap.js} +46 -46
  72. package/dist/ja-ZHKCBE5W-x73w6x3e.js +35 -0
  73. package/dist/{js-yaml-cggj6w7q.js → js-yaml-87cdx6bm.js} +27 -19
  74. package/dist/known-types-a20evmmg.js +20 -0
  75. package/dist/ko-6W7OGLLB-mnmqc584.js +35 -0
  76. package/dist/{ko-ITOPNIYI-qz39kamf.js → ko-ITOPNIYI-hmxd2asd.js} +52 -52
  77. package/dist/{ko-TUAK3G3A-s25w0ckg.js → ko-JOBF5V7N-4bv0mjje.js} +857 -845
  78. package/dist/{ko-TUAK3G3A-TBEBKOTM-ns78t2rv.js → ko-JOBF5V7N-O7T4HKIE-ape840y0.js} +857 -845
  79. package/dist/{ko-NAGOZLC3-wb3y9yhh.js → ko-NAGOZLC3-gaxxsnd2.js} +46 -46
  80. package/dist/{ko-PYOS2KJP-5sbj5bp8.js → ko-PYOS2KJP-e7dshyxy.js} +9 -9
  81. package/dist/localization-h8a53z6p.js +47 -0
  82. package/dist/{node-gd4469ea.js → node-cnrcrrb0.js} +7973 -7166
  83. package/dist/node-service-8g5x5d2y.js +70 -0
  84. package/dist/{node-strategy-8gzp67xs.js → node-strategy-gc4sg6a2.js} +132 -16
  85. package/dist/node-sync-service-e2reh33c.js +42 -0
  86. package/dist/{packager-tool-9qecd4wb.js → packager-tool-0gctz400.js} +5 -2
  87. package/dist/{packager-tool-1cb0d5e0.js → packager-tool-0v3s8r01.js} +2 -2
  88. package/dist/{packager-tool-wckvcay0.js → packager-tool-1yh8g550.js} +9 -7
  89. package/dist/packager-tool-27avrkyk.js +15 -0
  90. package/dist/packager-tool-2wefykg9.js +106 -0
  91. package/dist/packager-tool-4fhgws0x.js +757 -0
  92. package/dist/{packager-tool-7yjpwj92.js → packager-tool-4hx14snw.js} +49 -48
  93. package/dist/{packager-tool-3wygxefb.js → packager-tool-58q3tvh7.js} +10 -10
  94. package/dist/{packager-tool-cvwr40ax.js → packager-tool-5qaxht3k.js} +1425 -550
  95. package/dist/packager-tool-5z1eg3ea.js +33289 -0
  96. package/dist/{packager-tool-17cn3xb7.js → packager-tool-6m078z5s.js} +13388 -19366
  97. package/dist/packager-tool-7b6tpg7y.js +77 -0
  98. package/dist/packager-tool-7exrv6w7.js +23 -0
  99. package/dist/packager-tool-8dszjcg5.js +4892 -0
  100. package/dist/packager-tool-8j92afwp.js +58 -0
  101. package/dist/packager-tool-94w17vf8.js +85 -0
  102. package/dist/{packager-tool-vdd02vns.js → packager-tool-9bec251q.js} +543 -1493
  103. package/dist/packager-tool-a1hbfmws.js +399 -0
  104. package/dist/{packager-tool-tq9q9m77.js → packager-tool-a42jnpy5.js} +3 -9
  105. package/dist/packager-tool-abbtfk2v.js +54 -0
  106. package/dist/packager-tool-cdwpc9fh.js +4945 -0
  107. package/dist/packager-tool-e0p2zsyc.js +97 -0
  108. package/dist/packager-tool-eebq62fq.js +540 -0
  109. package/dist/{packager-tool-m6x5sczh.js → packager-tool-em5r6g6j.js} +14 -21
  110. package/dist/packager-tool-eypvc2kv.js +23 -0
  111. package/dist/packager-tool-f0kd5kq4.js +2327 -0
  112. package/dist/packager-tool-fjaa8d3v.js +289 -0
  113. package/dist/packager-tool-g0eha8ge.js +121 -0
  114. package/dist/packager-tool-g9y14b10.js +54 -0
  115. package/dist/packager-tool-gbgfwx8f.js +2 -0
  116. package/dist/packager-tool-jc34wvrw.js +64 -0
  117. package/dist/packager-tool-k99nf3pq.js +25 -0
  118. package/dist/{packager-tool-hr0xg6q8.js → packager-tool-kn91khp6.js} +17 -13
  119. package/dist/{packager-tool-jysvpt8p.js → packager-tool-m3wkcxf5.js} +2 -2
  120. package/dist/{packager-tool-78a3szsp.js → packager-tool-m5qfverj.js} +1720 -2014
  121. package/dist/packager-tool-mwvbq6ef.js +79 -0
  122. package/dist/packager-tool-nq4rcqqg.js +87 -0
  123. package/dist/packager-tool-nxx8naxv.js +4234 -0
  124. package/dist/{packager-tool-3y0k15sv.js → packager-tool-p9stswjj.js} +2858 -19342
  125. package/dist/packager-tool-r0xpcqwg.js +188 -0
  126. package/dist/packager-tool-raq2wbwp.js +18 -0
  127. package/dist/{packager-tool-y3dezh8k.js → packager-tool-rs6jm14d.js} +6 -4
  128. package/dist/packager-tool-s9ff3kk4.js +6 -0
  129. package/dist/{packager-tool-pbsghbmj.js → packager-tool-sykgshez.js} +2 -2
  130. package/dist/packager-tool-tf3d2y8z.js +31 -0
  131. package/dist/packager-tool-tn5e7wnb.js +384 -0
  132. package/dist/packager-tool-v2rkcehq.js +457 -0
  133. package/dist/packager-tool-v86fdwvs.js +262 -0
  134. package/dist/packager-tool-v9psxdy5.js +8185 -0
  135. package/dist/packager-tool-v9rrz038.js +602 -0
  136. package/dist/packager-tool-vpqyvh4c.js +304 -0
  137. package/dist/packager-tool-wcha0e5r.js +443 -0
  138. package/dist/{packager-tool-1gt6js73.js → packager-tool-xhzfwa5p.js} +6 -4
  139. package/dist/{packager-tool-5arsyj36.js → packager-tool-yc4kw997.js} +4 -2
  140. package/dist/{packager-tool-pkq70dec.js → packager-tool-ywqc9rtf.js} +31 -3
  141. package/dist/{packager-tool-0567pxpm.js → packager-tool-z9bfhmm5.js} +10 -10
  142. package/dist/{packager-tool-gmrwvnyh.js → packager-tool-zfrp8ecz.js} +8 -58
  143. package/dist/{packager-tool-3vdpx9ng.js → packager-tool-zke08y39.js} +1121 -1846
  144. package/dist/packager-tool.js +17 -17
  145. package/dist/{pt-7TR74ZMB-1g8my56g.js → pt-7TR74ZMB-bmphh4x2.js} +46 -46
  146. package/dist/{pt-BR-7XGDXRDJ-TR5D7JYL-533wvy7p.js → pt-BR-7DYX2YPT-LZYH4YFD-bx43vx3z.js} +857 -845
  147. package/dist/{pt-BR-7XGDXRDJ-espnkgrj.js → pt-BR-7DYX2YPT-fqxqzqtf.js} +857 -845
  148. package/dist/{pt-BR-BXURWX4W-dqr4dnf9.js → pt-BR-BXURWX4W-bwfcwhk1.js} +52 -52
  149. package/dist/{pt-BR-DXXSYJDO-bn84ewp7.js → pt-BR-DXXSYJDO-a2tp13v7.js} +46 -46
  150. package/dist/pt-BR-UQCYHKMJ-q78n7q70.js +35 -0
  151. package/dist/{pt-BR-Z3TUDJHM-n7ngej6s.js → pt-BR-Z3TUDJHM-8v73x9s7.js} +9 -9
  152. package/dist/pt-D6A6MVB2-yvxca8vz.js +35 -0
  153. package/dist/{pt-TMVOOITK-myha14p9.js → pt-HTXGGX6Y-97t21dty.js} +857 -845
  154. package/dist/{pt-TMVOOITK-H2ADYHSD-ezpggv33.js → pt-HTXGGX6Y-ZHQSDFKI-vehfxadc.js} +857 -845
  155. package/dist/{pt-KSBWHAVQ-hd52bpsz.js → pt-KSBWHAVQ-mhvhgr2p.js} +9 -9
  156. package/dist/{pt-YI4VE4YQ-v7gjeg82.js → pt-YI4VE4YQ-wdkn2dcf.js} +52 -52
  157. package/dist/ro-4TMBHS5M-jz0anpt6.js +35 -0
  158. package/dist/{ro-BJFER5OI-334n28rj.js → ro-BJFER5OI-83tq8vxh.js} +46 -46
  159. package/dist/{ro-2VALF3S5-NXBJUEZN-nqw1zs33.js → ro-KTNQ3MNU-XIE6YPQN-gen8p82z.js} +857 -845
  160. package/dist/{ro-2VALF3S5-cdz5afkr.js → ro-KTNQ3MNU-y08n1x5g.js} +857 -845
  161. package/dist/{ro-RKXZUG7Z-cm3xn3fj.js → ro-RKXZUG7Z-nndrrsq7.js} +52 -52
  162. package/dist/{ro-VZUZTAMR-tccygznf.js → ro-VZUZTAMR-f4q0g3em.js} +9 -9
  163. package/dist/{ru-GSCT4ARZ-qj8dm4dp.js → ru-GSCT4ARZ-1sa9wbr8.js} +1 -1
  164. package/dist/{ru-GSCT4ARZ-FTVCGQTL-5nh4jf2e.js → ru-GSCT4ARZ-FTVCGQTL-gee86v14.js} +1 -1
  165. package/dist/{ru-T73OPRTC-mp5gn7gs.js → ru-T73OPRTC-4knxw497.js} +1 -1
  166. package/dist/{ru-WBLQ5B2U-awt245ky.js → ru-WBLQ5B2U-8r3c7v6d.js} +1 -1
  167. package/dist/ru-WBLQ5B2U-kdey8qa4.js +10 -0
  168. package/dist/{ru-WBLQ5B2U-57ezmxzz.js → ru-WBLQ5B2U-wemdzdqd.js} +1 -1
  169. package/dist/{serialization-GAW7UFOK-9hkdmmd2.js → serialization-J5QK3HPY-bgewpt6f.js} +158 -152
  170. package/dist/services/expression-validator.d.ts +28 -0
  171. package/dist/services/flow-eval-schema/types.d.ts +17 -0
  172. package/dist/services/flow-validate-service.d.ts +26 -0
  173. package/dist/services/node-validators/js-expression-syntax-validator.d.ts +6 -3
  174. package/dist/services/tidy-service.d.ts +26 -0
  175. package/dist/services/vars-reference-rule.d.ts +156 -0
  176. package/dist/shared-utils-8xdq6f04.js +20 -0
  177. package/dist/tidy-service-ashgyfwj.js +34 -0
  178. package/dist/tool.js +30 -33
  179. package/dist/{tr-AA6O2WSR-ga1xnymp.js → tr-AA6O2WSR-86ba4bdf.js} +52 -52
  180. package/dist/tr-GSQQ6SOT-hv1gyeaa.js +35 -0
  181. package/dist/{tr-RQTZ2DMS-bpgd4kma.js → tr-RQTZ2DMS-w3cwv8s4.js} +46 -46
  182. package/dist/{tr-W4AVRSQ4-bt3qqqdy.js → tr-W4AVRSQ4-hjr81xzk.js} +9 -9
  183. package/dist/{tr-RIFCEXFH-BZS7S7QK-q465b62g.js → tr-XHSSPNK7-GW5KVXR3-2w3f1ss6.js} +857 -845
  184. package/dist/{tr-RIFCEXFH-hgkb4g8y.js → tr-XHSSPNK7-cmqyc4wd.js} +857 -845
  185. package/dist/utils/handle-expansion.d.ts +16 -0
  186. package/dist/validation.js +47 -27
  187. package/dist/variable-service-er7ph4br.js +152 -0
  188. package/dist/wait-for-flow-job-45p1a444.js +134 -0
  189. package/dist/{zh-CN-IP3FMXWM-H3JI2XUM-ta4yac7h.js → zh-CN-2EHQT23P-T5XRQCVS-ac17dpc1.js} +857 -845
  190. package/dist/{zh-CN-IP3FMXWM-1cfarhcp.js → zh-CN-2EHQT23P-mr63c4xz.js} +857 -845
  191. package/dist/{zh-CN-6YRAN57T-j7jp34ws.js → zh-CN-6YRAN57T-rd7x2tqs.js} +9 -9
  192. package/dist/zh-CN-EDFRBU32-vvj7tmaq.js +35 -0
  193. package/dist/{zh-CN-R2KLHXQV-wttmznep.js → zh-CN-R2KLHXQV-agqr45ds.js} +52 -52
  194. package/dist/{zh-CN-ZC6LT4IN-vty9mvv8.js → zh-CN-ZC6LT4IN-kbzvvzz5.js} +46 -46
  195. package/dist/zh-TW-HAICM6DE-rh7k3cq7.js +35 -0
  196. package/dist/{zh-TW-AGIDXIPF-R4XZRDJZ-cgxxz5k4.js → zh-TW-MGZCE5BT-P6FLIUAR-zmq07vhs.js} +857 -845
  197. package/dist/{zh-TW-AGIDXIPF-n6r6w7vy.js → zh-TW-MGZCE5BT-c4ekmrz9.js} +857 -845
  198. package/dist/{zh-TW-R7Y5KVMU-q81f4z2p.js → zh-TW-R7Y5KVMU-m61y07e3.js} +46 -46
  199. package/dist/{zh-TW-RJGCQANM-gqn0aca0.js → zh-TW-RJGCQANM-w0x3qc1p.js} +52 -52
  200. package/dist/{zh-TW-SO2245GN-m5kh88bg.js → zh-TW-SO2245GN-n2bn1gg4.js} +9 -9
  201. package/package.json +2 -2
  202. package/dist/de-5KVP66U6-t37qr521.js +0 -161
  203. package/dist/de-WMKOGI7B-6dc1zdnp.js +0 -143
  204. package/dist/en-4KXU7N7B-24v330b5.js +0 -118
  205. package/dist/en-X4DLPKLJ-1h9gj5c1.js +0 -110
  206. package/dist/es-BVPGJUWA-0k59eqfv.js +0 -143
  207. package/dist/es-MX-U6YL5KQX-k4qvpgd4.js +0 -143
  208. package/dist/es-MX-XAVLOQW3-47a405kf.js +0 -161
  209. package/dist/es-VFPNVMP5-6sftsdxe.js +0 -161
  210. package/dist/fr-E5MDO4EG-f3x1jeqw.js +0 -161
  211. package/dist/fr-EKTTDR7Z-m2t68j0m.js +0 -143
  212. package/dist/ja-DPO5PPLO-fmbg7zt2.js +0 -161
  213. package/dist/ja-Y2YBTXNN-5sszk2zv.js +0 -143
  214. package/dist/ko-ITOPNIYI-aqy82jk8.js +0 -161
  215. package/dist/ko-S33XAV26-rfsv9myd.js +0 -143
  216. package/dist/packager-tool-0sz8se22.js +0 -10671
  217. package/dist/packager-tool-8mqydhz8.js +0 -9850
  218. package/dist/packager-tool-p9j43p8h.js +0 -115
  219. package/dist/packager-tool-v74yk918.js +0 -107
  220. package/dist/packager-tool-xj0agqpk.js +0 -11
  221. package/dist/pt-BR-BXURWX4W-xzyndmrx.js +0 -161
  222. package/dist/pt-BR-JO45SCNI-mt93s33c.js +0 -143
  223. package/dist/pt-W3NA4LIZ-fwd1q4j0.js +0 -143
  224. package/dist/pt-YI4VE4YQ-521681zf.js +0 -161
  225. package/dist/ro-RKXZUG7Z-pdztdafr.js +0 -161
  226. package/dist/ro-WLKX6HF5-b9tj8q67.js +0 -143
  227. package/dist/ru-WBLQ5B2U-8xd4gpv2.js +0 -10
  228. package/dist/ru-WBLQ5B2U-mswqs9wc.js +0 -10
  229. package/dist/tr-3U2W2XCA-43ptfc0m.js +0 -143
  230. package/dist/tr-AA6O2WSR-bj9n80k8.js +0 -161
  231. package/dist/zh-CN-IPZYQR3P-egjmvyjf.js +0 -143
  232. package/dist/zh-CN-R2KLHXQV-x6gnk2n0.js +0 -161
  233. package/dist/zh-TW-RJGCQANM-tt8j5wv2.js +0 -161
  234. package/dist/zh-TW-YPVSQVGT-b378ztph.js +0 -143
@@ -1,187 +1,377 @@
1
1
  import {
2
- ManifestClient,
3
- buildErrorHandle,
4
- getConnectorInfo,
5
- getNode,
6
- isConnectorNode,
7
- isKnownSdkNodeType,
8
- loadRegistry,
9
- readFlowWorkflow,
10
- validateIntSvcNode,
11
- writeFlowWorkflow
12
- } from "./packager-tool-3y0k15sv.js";
2
+ UI_ONLY_NODE_TYPES
3
+ } from "./packager-tool-4fhgws0x.js";
4
+ import {
5
+ checkForwardMigration
6
+ } from "./packager-tool-mwvbq6ef.js";
7
+ import {
8
+ crossNodeBindingValidator,
9
+ isConnectorTriggerType,
10
+ isConnectorWaitForEventType,
11
+ isEventDrivenConnectorType
12
+ } from "./packager-tool-2wefykg9.js";
13
+ import {
14
+ ERROR_SOURCE_PORT,
15
+ deriveOutcomeHandleIds,
16
+ expandHandleIds,
17
+ isHandleVisible,
18
+ isTemplatedHandleId,
19
+ parseVisibleInputKey,
20
+ portMatchesTemplate
21
+ } from "./packager-tool-nq4rcqqg.js";
22
+ import {
23
+ isRecord
24
+ } from "./packager-tool-8j92afwp.js";
25
+ import {
26
+ collectNodeBindingResourceKeys,
27
+ isProcessNode,
28
+ resolveProcessTarget
29
+ } from "./packager-tool-v2rkcehq.js";
30
+ import {
31
+ loadRegistry
32
+ } from "./packager-tool-cdwpc9fh.js";
33
+ import {
34
+ validateIntSvcNode
35
+ } from "./packager-tool-v9psxdy5.js";
36
+ import {
37
+ getLoginStatusAsync
38
+ } from "./packager-tool-f0kd5kq4.js";
13
39
  import {
14
40
  findNearestParentUipxFile,
15
- getLoginStatusAsync,
16
41
  readSolutionManifest
17
- } from "./packager-tool-0sz8se22.js";
42
+ } from "./packager-tool-eebq62fq.js";
43
+ import {
44
+ resolveProjectFlowFile
45
+ } from "./packager-tool-94w17vf8.js";
46
+ import {
47
+ canonicalAgentInputPath,
48
+ collectAgentInputLeaves,
49
+ createFlowRefResolver,
50
+ resolveWorkflowRefs
51
+ } from "./packager-tool-6m078z5s.js";
18
52
  import {
19
53
  OutputFormatter,
20
54
  RESULTS,
21
55
  catchError,
56
+ extractErrorMessageSync,
22
57
  logger
23
- } from "./packager-tool-cvwr40ax.js";
58
+ } from "./packager-tool-5qaxht3k.js";
24
59
  import {
25
60
  getFileSystem
26
- } from "./packager-tool-1cb0d5e0.js";
61
+ } from "./packager-tool-0v3s8r01.js";
27
62
  import {
28
- addBinding,
29
- addNode,
30
- buildInlineAgentContract,
31
- createBinding,
32
- createFlowRefResolver,
33
- generateNodeIdAndName,
34
- getMigrationChain,
35
- isInlineAgentNodeType,
36
- migrateWorkflowToFloor,
37
- minimumSupportedVersion,
38
- operateRuntimeOptions,
39
- readInlineAgentSource,
40
- registerFlowMigrationsI18n,
41
- resolveWorkflowRefs,
42
- runtimeMigrations,
43
- runtimeVersion
44
- } from "./packager-tool-17cn3xb7.js";
63
+ ManifestClient,
64
+ buildErrorHandle
65
+ } from "./packager-tool-p9stswjj.js";
45
66
  import {
46
67
  AGENT_NODE_TYPES,
47
- EntryPointType,
48
- ProjectType,
49
68
  cliRules,
50
69
  conditionExpressionRule,
51
70
  decodeLiteral,
52
- generateBindingsJson,
53
- generateEntryPointsJson,
54
- generateOperateJson,
55
- getBindingResources,
56
- getEntryPoints,
57
71
  getJsExpressionBody,
58
72
  instance,
59
73
  isBlockingSeverity,
60
- isConversationalOrVoiceAgentNodeType,
61
74
  isExpressionValue,
62
75
  isStartEventNode,
63
76
  isVoiceAgentNodeType,
64
- mergeBindingResources,
65
77
  parseWorkflowJson,
66
- registerFlowSchemaI18n,
67
- runRules
68
- } from "./packager-tool-78a3szsp.js";
78
+ runRules,
79
+ toSerializedNodes
80
+ } from "./packager-tool-m5qfverj.js";
81
+ import {
82
+ registerFlowSchemaI18n
83
+ } from "./packager-tool-e0p2zsyc.js";
84
+ import {
85
+ __require
86
+ } from "./packager-tool-1yh8g550.js";
69
87
 
70
- // src/services/connector-node-types.ts
71
- function isConnectorTriggerType(nodeType) {
72
- return nodeType.startsWith("uipath.connector.trigger");
88
+ // src/services/connector-binding-validator.ts
89
+ var STATIC_CONNECTOR_KEYWORDS = [
90
+ "slack",
91
+ "gmail",
92
+ "outlook",
93
+ "office365",
94
+ "exchange",
95
+ "jira",
96
+ "confluence",
97
+ "salesforce",
98
+ "sfdc",
99
+ "hubspot",
100
+ "servicenow",
101
+ "zendesk",
102
+ "intercom",
103
+ "notion",
104
+ "asana",
105
+ "trello",
106
+ "monday",
107
+ "github",
108
+ "gitlab",
109
+ "bitbucket",
110
+ "discord",
111
+ "teams",
112
+ "sharepoint",
113
+ "onedrive",
114
+ "dropbox",
115
+ "box",
116
+ "googledrive",
117
+ "docusign",
118
+ "adobesign",
119
+ "mailchimp",
120
+ "sendgrid",
121
+ "twilio",
122
+ "stripe",
123
+ "shopify",
124
+ "quickbooks",
125
+ "xero",
126
+ "workday",
127
+ "successfactors",
128
+ "bamboohr",
129
+ "sap",
130
+ "netsuite",
131
+ "oracle",
132
+ "marketo",
133
+ "pardot",
134
+ "segment",
135
+ "snowflake",
136
+ "bigquery",
137
+ "redshift",
138
+ "databricks",
139
+ "tableau",
140
+ "powerbi"
141
+ ];
142
+ var ACTION_VERBS = [
143
+ "send",
144
+ "post",
145
+ "create",
146
+ "update",
147
+ "delete",
148
+ "get",
149
+ "fetch",
150
+ "list",
151
+ "read",
152
+ "write",
153
+ "upload",
154
+ "download",
155
+ "find",
156
+ "add",
157
+ "remove",
158
+ "query",
159
+ "search",
160
+ "notify",
161
+ "publish",
162
+ "subscribe",
163
+ "trigger",
164
+ "watch",
165
+ "share",
166
+ "invite",
167
+ "schedule",
168
+ "assign",
169
+ "close",
170
+ "open",
171
+ "reply",
172
+ "forward",
173
+ "archive"
174
+ ];
175
+ var MANAGED_HTTP_NODE_TYPE = "core.action.http.v2";
176
+ async function loadConnectorCatalog() {
177
+ const keywords = new Set(STATIC_CONNECTOR_KEYWORDS);
178
+ const activityTokenBags = [];
179
+ const [err, registry] = await catchError(loadRegistry());
180
+ if (err) {
181
+ logger.debug(`Connector-binding validator: could not load IS catalog cache (${err.message}); falling back to static keyword list.`);
182
+ return { keywords, activityTokenBags };
183
+ }
184
+ if (!registry) {
185
+ return { keywords, activityTokenBags };
186
+ }
187
+ for (const connector of registry.discovered.connectors) {
188
+ addConnectorKeywords(connector, keywords);
189
+ for (const activity of connector.activities) {
190
+ const tokens = tokenize(activity.displayName);
191
+ if (tokens.size > 0) {
192
+ activityTokenBags.push({
193
+ connectorKey: connector.key,
194
+ connectorName: connector.name,
195
+ tokens
196
+ });
197
+ }
198
+ }
199
+ }
200
+ return { keywords, activityTokenBags };
73
201
  }
74
- function isConnectorWaitForEventType(nodeType) {
75
- return nodeType.startsWith("uipath.connector.event");
202
+ function addConnectorKeywords(connector, out) {
203
+ const keyParts = connector.key.toLowerCase().split("-").filter((p) => p && p !== "uipath");
204
+ for (const part of keyParts)
205
+ out.add(part);
206
+ for (const t of tokenize(connector.name))
207
+ out.add(t);
76
208
  }
77
- function isEventDrivenConnectorType(nodeType) {
78
- return isConnectorTriggerType(nodeType) || isConnectorWaitForEventType(nodeType);
209
+ function tokenize(label) {
210
+ if (!label)
211
+ return new Set;
212
+ const tokens = label.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length > 1);
213
+ return new Set(tokens);
79
214
  }
80
-
81
- // src/services/node-validators/connector-validator.ts
82
- var connectorNodeValidator = {
83
- id: "uipath-connector",
84
- appliesTo: (node) => node.type?.startsWith("uipath.connector") ?? false,
85
- validate: (node) => {
86
- const rawDetail = node.inputs?.detail;
87
- if (!rawDetail || typeof rawDetail !== "object" || Array.isArray(rawDetail)) {
88
- return [];
89
- }
90
- const detail = rawDetail;
91
- if (Object.keys(detail).length === 0)
92
- return [];
93
- const isEventDriven = isEventDrivenConnectorType(node.type);
94
- const context = {
95
- nodeId: node.id,
96
- nodeKind: isEventDriven ? "trigger" : "activity",
97
- connectionId: detail.connectionId,
98
- folderKey: detail.connectionFolderKey,
99
- objectName: detail.objectName ?? detail.connector,
100
- httpMethod: detail.method,
101
- endpoint: detail.endpoint,
102
- eventMode: detail.eventMode,
103
- eventType: detail.eventType,
104
- bodyParameters: detail.bodyParameters,
105
- queryParameters: detail.queryParameters,
106
- pathParameters: detail.pathParameters,
107
- eventParameters: detail.eventParameters,
108
- configuration: detail.configuration
109
- };
110
- const issues = validateIntSvcNode(context).map((issue) => ({
111
- path: `nodes[${node.id}].inputs.detail`,
112
- message: issue.title,
113
- severity: issue.type === "Error" ? "error" : "warning"
114
- }));
115
- issues.push(...validateCeqlFilterShape(node.id, detail));
116
- return issues;
215
+ function readNodeLabel(node) {
216
+ const fromDisplay = node.display?.label;
217
+ if (typeof fromDisplay === "string" && fromDisplay.length > 0) {
218
+ return fromDisplay;
117
219
  }
118
- };
119
- function validateCeqlFilterShape(nodeId, detail) {
120
- const issues = [];
121
- const queryParameters = readObjectField(detail, "queryParameters");
122
- if (queryParameters && Object.hasOwn(queryParameters, "$where")) {
123
- issues.push({
124
- path: `nodes[${nodeId}].inputs.detail.queryParameters["$where"]`,
125
- severity: "error",
126
- message: 'Connector node uses OData-style `"$where"` (with leading `$`) ' + "in queryParameters. CEQL uses bare `where` — rename the key " + 'from `"$where"` to `"where"`. The leading `$` is the OData ' + "system-query-option prefix and is not recognized by " + "uipath.connector.* nodes. See uipath-maestro-flow skill — " + 'plugins/connector/impl.md, "Hand-authored CEQL strings" ' + "(MST-9265)."
127
- });
220
+ const fromName = node.name;
221
+ if (typeof fromName === "string" && fromName.length > 0) {
222
+ return fromName;
128
223
  }
129
- const queryWhere = queryParameters?.where;
130
- const queryWhereAuthored = isNonEmptyString(queryWhere);
131
- const queryWhereIsWholeValueExpression = typeof queryWhere === "string" && queryWhere.startsWith("=js:");
132
- const savedTrees = readObjectField(detail, "savedFilterTrees") ?? readEssentialSavedFilterTrees(detail);
133
- const savedWhereAuthored = savedTrees !== undefined && isNonEmptyObject(savedTrees.where);
134
- if (queryWhereAuthored && !queryWhereIsWholeValueExpression && !savedWhereAuthored) {
135
- issues.push({
136
- path: `nodes[${nodeId}].inputs.detail.savedFilterTrees.where`,
137
- severity: "error",
138
- message: "Connector node has `queryParameters.where` set but no " + "matching `savedFilterTrees.where` AST — neither at " + "`inputs.detail.savedFilterTrees.where` nor as " + "`essentialConfiguration.savedFilterTrees.where` inside " + "`inputs.detail.configuration`. CEQL filters must be authored " + "as both the raw filter expression (`queryParameters.where`) " + "AND a parallel canonical AST (`filters[].id` / `.operator` / " + "`.value.value`). The Studio Web canvas needs the AST to " + "render the filter UI; the runtime needs the expression. " + "Re-run `uip maestro flow node configure --detail.filter` to " + "author both. See uipath-maestro-flow skill — " + 'plugins/connector/impl.md, "Hand-authored CEQL strings" ' + "(MST-9265)."
139
- });
224
+ return;
225
+ }
226
+ function hasConnectorBinding(node) {
227
+ const detail = node.inputs?.detail;
228
+ if (!detail || typeof detail !== "object" || Array.isArray(detail)) {
229
+ return false;
140
230
  }
141
- if (savedWhereAuthored && !queryWhereAuthored) {
142
- issues.push({
143
- path: `nodes[${nodeId}].inputs.detail.queryParameters.where`,
144
- severity: "error",
145
- message: "Connector node has `savedFilterTrees.where` AST but no " + "matching `queryParameters.where` expression. CEQL filters " + "must be authored on both keys in parallel — the runtime " + "evaluates `queryParameters.where`, not the AST. See " + 'uipath-maestro-flow skill — plugins/connector/impl.md, "Hand-authored ' + 'CEQL strings" (MST-9265).'
146
- });
231
+ const d = detail;
232
+ const authentication = d.authentication;
233
+ if (authentication === "connector") {
234
+ const connectionId = d.connectionId;
235
+ const targetConnector = d.targetConnector;
236
+ return typeof connectionId === "string" && connectionId.length > 0 && connectionId !== "ImplicitConnection" && typeof targetConnector === "string" && targetConnector.length > 0;
147
237
  }
148
- return issues;
149
- }
150
- function readEssentialSavedFilterTrees(detail) {
151
- const configuration = detail.configuration;
152
- if (typeof configuration !== "string")
153
- return;
154
- const [, parsed] = catchError(() => JSON.parse(configuration.replace(/^=jsonString:/, "")));
155
- if (!parsed)
156
- return;
157
- const essentialConfiguration = readObjectField(parsed, "essentialConfiguration");
158
- if (!essentialConfiguration)
159
- return;
160
- return readObjectField(essentialConfiguration, "savedFilterTrees");
161
- }
162
- function readObjectField(parent, key) {
163
- const value = parent[key];
164
- if (!value || typeof value !== "object" || Array.isArray(value)) {
165
- return;
238
+ if (authentication === "manual") {
239
+ const url = d.url;
240
+ return typeof url === "string" && url.length > 0;
166
241
  }
167
- return value;
168
- }
169
- function isNonEmptyString(value) {
170
- return typeof value === "string" && value.trim().length > 0;
171
- }
172
- function isNonEmptyObject(value) {
173
- return !!value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length > 0;
242
+ return false;
174
243
  }
175
-
176
- // src/services/node-validators/activity-type-id-validator.ts
177
- var activityTypeIdValidator = {
178
- id: "activity-type-id",
179
- appliesTo: (node) => {
180
- const t = node.type;
181
- if (!t)
182
- return false;
183
- return t === "core.action.http.v2" || t.startsWith("uipath.connector.");
184
- },
244
+ function classifyLabel(label, catalog) {
245
+ const tokens = tokenize(label);
246
+ if (tokens.size === 0)
247
+ return null;
248
+ for (const bag of catalog.activityTokenBags) {
249
+ let overlap = 0;
250
+ for (const t of bag.tokens) {
251
+ if (tokens.has(t))
252
+ overlap += 1;
253
+ }
254
+ if (overlap >= 2) {
255
+ const keyword = pickConnectorKeyword(tokens, catalog.keywords);
256
+ return {
257
+ connectorKeyword: keyword ?? bag.connectorKey,
258
+ matchedActivity: {
259
+ connectorKey: bag.connectorKey,
260
+ connectorName: bag.connectorName
261
+ }
262
+ };
263
+ }
264
+ }
265
+ const matchedKeyword = pickConnectorKeyword(tokens, catalog.keywords);
266
+ if (!matchedKeyword)
267
+ return null;
268
+ const hasVerb = [...tokens].some((t) => ACTION_VERBS.includes(t));
269
+ if (!hasVerb)
270
+ return null;
271
+ return { connectorKeyword: matchedKeyword };
272
+ }
273
+ function pickConnectorKeyword(tokens, keywords) {
274
+ for (const t of tokens) {
275
+ if (keywords.has(t))
276
+ return t;
277
+ }
278
+ return;
279
+ }
280
+ function buildDiagnosticMessage(label, classification, strict) {
281
+ const connectorHint = classification.matchedActivity ? `looks like a "${classification.matchedActivity.connectorName}" connector activity` : `mentions the "${classification.connectorKeyword}" connector keyword`;
282
+ const strictNote = strict ? " (--strict-bindings promoted this to an error.)" : " Pass `--strict-bindings` to fail validation on this.";
283
+ const connectorDetail = `{"authentication":"connector",` + `"targetConnector":"${classification.connectorKeyword}",` + `"connectionId":"<uuid>","folderKey":"<uuid>","method":"GET","url":"<path>"}`;
284
+ const manualDetail = `{"authentication":"manual","method":"GET","url":"https://…"}`;
285
+ return `Node "${label}" ${connectorHint} but uses the generic Managed HTTP type \`${MANAGED_HTTP_NODE_TYPE}\` ` + "with no connection binding. The runtime will issue a raw HTTP call to an undefined endpoint. " + `Either bind a real Integration Service connection with \`uip maestro flow node configure <file> <node-id> --detail '${connectorDetail}'\`, ` + `or configure manual-mode HTTP with \`--detail '${manualDetail}'\`. ` + "If this node is intentionally a raw HTTP call, rename it so the label doesn't " + `imply a connector binding.${strictNote}`;
286
+ }
287
+ function validateConnectorBindings(workflow, catalog, options = {}) {
288
+ const issues = [];
289
+ const severity = options.strict ? "error" : "warning";
290
+ const checkNode = (node, scope) => {
291
+ if (node.type !== MANAGED_HTTP_NODE_TYPE)
292
+ return;
293
+ if (hasConnectorBinding(node))
294
+ return;
295
+ const label = readNodeLabel(node);
296
+ if (!label)
297
+ return;
298
+ const classification = classifyLabel(label, catalog);
299
+ if (!classification)
300
+ return;
301
+ issues.push({
302
+ path: `${scope}nodes[${node.id}].inputs.detail`,
303
+ severity,
304
+ message: buildDiagnosticMessage(label, classification, options.strict === true)
305
+ });
306
+ };
307
+ for (const node of workflow.nodes) {
308
+ checkNode(node, "");
309
+ }
310
+ for (const [subflowId, sub] of Object.entries(workflow.subflows ?? {})) {
311
+ for (const node of sub.nodes ?? []) {
312
+ checkNode(node, `subflows[${subflowId}].`);
313
+ }
314
+ }
315
+ return issues;
316
+ }
317
+
318
+ // src/services/expression-validator.ts
319
+ var catalogRegistered = false;
320
+ async function ensureCatalogRegistered() {
321
+ if (catalogRegistered || !instance.isInitialized)
322
+ return;
323
+ try {
324
+ const { registerFlowExpressionModelI18n } = await import("./localization-h8a53z6p.js");
325
+ registerFlowExpressionModelI18n(instance);
326
+ } catch (error) {
327
+ logger.warn(`Expression type checking localization unavailable, falling back to English: ${extractErrorMessageSync(error)}`);
328
+ }
329
+ catalogRegistered = true;
330
+ }
331
+ var headlessModule;
332
+ function loadHeadless() {
333
+ headlessModule ??= import("./headless-h1myzz32.js").then((mod) => {
334
+ logger.info(`Expression type checking: @uipath/flow-expression-model (TypeScript ${mod.HEADLESS_TYPESCRIPT_VERSION})`);
335
+ return mod;
336
+ }).catch((error) => {
337
+ logger.warn(`Expression type checking unavailable, skipping: ${extractErrorMessageSync(error)}`);
338
+ return null;
339
+ });
340
+ return headlessModule;
341
+ }
342
+ function findingPath(finding) {
343
+ if (!finding.nodeId)
344
+ return finding.fieldPath ?? "(workflow)";
345
+ if (!finding.fieldPath)
346
+ return `nodes[${finding.nodeId}]`;
347
+ return `nodes[${finding.nodeId}].${finding.fieldPath}`;
348
+ }
349
+ async function validateExpressions(graph, pathPrefix, strict = false) {
350
+ await ensureCatalogRegistered();
351
+ const headless = await loadHeadless();
352
+ if (!headless)
353
+ return [];
354
+ const [error, findings] = await catchError(headless.checkWorkflowExpressionsHeadless(graph));
355
+ if (error || !findings) {
356
+ logger.warn(`Expression type checking failed, skipping: ${extractErrorMessageSync(error)}`);
357
+ return [];
358
+ }
359
+ return findings.map((finding) => ({
360
+ path: `${pathPrefix}${findingPath(finding)}`,
361
+ message: `[${finding.code}] ${finding.message}`,
362
+ severity: strict ? "error" : "warning"
363
+ }));
364
+ }
365
+
366
+ // src/services/node-validators/activity-type-id-validator.ts
367
+ var activityTypeIdValidator = {
368
+ id: "activity-type-id",
369
+ appliesTo: (node) => {
370
+ const t = node.type;
371
+ if (!t)
372
+ return false;
373
+ return t === "core.action.http.v2" || t.startsWith("uipath.connector.");
374
+ },
185
375
  validate: (node) => {
186
376
  const rawDetail = node.inputs?.detail;
187
377
  if (!rawDetail || typeof rawDetail !== "object" || Array.isArray(rawDetail)) {
@@ -5827,97 +6017,153 @@ var ceqlQueryValidator = {
5827
6017
  }
5828
6018
  };
5829
6019
 
5830
- // src/services/node-validators/cross-node-binding-validator.ts
5831
- var IDENTIFIER_ROOT_RE = /(?<![.\w$])([A-Za-z_$][\w$]*)\.(?!\.)/g;
5832
- function findCrossNodeBindingReferences(value, nodeIds) {
5833
- if (nodeIds.size === 0)
5834
- return [];
5835
- const trimmed = value.trimStart();
5836
- if (!trimmed.startsWith("=js:"))
5837
- return [];
5838
- const body = trimmed.slice(4);
5839
- const referenced = new Set;
5840
- const fixedBody = body.replace(IDENTIFIER_ROOT_RE, (match, identifier) => {
5841
- if (!nodeIds.has(identifier))
5842
- return match;
5843
- referenced.add(identifier);
5844
- return `$vars.${match}`;
5845
- });
5846
- if (referenced.size === 0)
5847
- return [];
5848
- const fixedValue = `=js:${fixedBody}`;
5849
- return [...referenced].map((nodeId) => ({ nodeId, fixedValue }));
6020
+ // src/services/node-validators/connector-validator.ts
6021
+ var connectorNodeValidator = {
6022
+ id: "uipath-connector",
6023
+ appliesTo: (node) => node.type?.startsWith("uipath.connector") ?? false,
6024
+ validate: (node) => {
6025
+ const rawDetail = node.inputs?.detail;
6026
+ const emptyDetailWarning = {
6027
+ path: `nodes[${node.id}].inputs.detail`,
6028
+ severity: "warning",
6029
+ message: "Connector is not configured, no detail found. " + "Run `uip maestro flow node configure <file> <node-id> " + `--detail '{"connectionId":"<id>","folderKey":"<key>",...}'\` ` + "to bind an Integration Service connection."
6030
+ };
6031
+ if (!rawDetail || typeof rawDetail !== "object" || Array.isArray(rawDetail)) {
6032
+ return [emptyDetailWarning];
6033
+ }
6034
+ const detail = rawDetail;
6035
+ if (Object.keys(detail).length === 0)
6036
+ return [emptyDetailWarning];
6037
+ const isEventDriven = isEventDrivenConnectorType(node.type);
6038
+ const context = {
6039
+ nodeId: node.id,
6040
+ nodeKind: isEventDriven ? "trigger" : "activity",
6041
+ connectionId: detail.connectionId,
6042
+ folderKey: detail.connectionFolderKey,
6043
+ objectName: detail.objectName ?? detail.connector,
6044
+ httpMethod: detail.method,
6045
+ endpoint: detail.endpoint,
6046
+ eventMode: detail.eventMode,
6047
+ eventType: detail.eventType,
6048
+ bodyParameters: detail.bodyParameters,
6049
+ queryParameters: detail.queryParameters,
6050
+ pathParameters: detail.pathParameters,
6051
+ eventParameters: detail.eventParameters,
6052
+ configuration: detail.configuration
6053
+ };
6054
+ const issues = validateIntSvcNode(context).map((issue) => ({
6055
+ path: `nodes[${node.id}].inputs.detail`,
6056
+ message: issue.title,
6057
+ severity: issue.type === "Error" ? "error" : "warning"
6058
+ }));
6059
+ issues.push(...validateCeqlFilterShape(node.id, detail));
6060
+ if (!isEventDriven) {
6061
+ issues.push(...validateEndpointMatchesActivityPath(node.id, detail));
6062
+ }
6063
+ return issues;
6064
+ }
6065
+ };
6066
+ function staticSegments(path, substitutedValues) {
6067
+ const cut = path.search(/[?#]/);
6068
+ return (cut === -1 ? path : path.slice(0, cut)).split("/").filter((seg) => seg.length > 0).filter((seg) => !(seg.startsWith("{") && seg.endsWith("}"))).filter((seg) => !substitutedValues.has(seg));
5850
6069
  }
5851
- function crossNodeBindingMessage(originalValue, ref2) {
5852
- return `Expression "${originalValue}" references node "${ref2.nodeId}" without the "$vars." prefix — ` + `cross-node outputs resolve to undefined at runtime (the bare identifier reads as an ` + `undeclared local, not the runtime variable). Use "${ref2.fixedValue}" instead. ` + "See uipath-maestro-flow skill — node-output-wiring.md (FPD-538).";
6070
+ function endpointNamesActivity(endpointSegments, activitySegments) {
6071
+ const extra = endpointSegments.length - activitySegments.length;
6072
+ if (extra < 0 || extra > 1)
6073
+ return false;
6074
+ return activitySegments.every((seg, i2) => seg === endpointSegments[i2]);
5853
6075
  }
5854
- function scanContainerForCrossNodeBindings(obj, path, nodeIds, severity, issues) {
5855
- if (typeof obj === "string") {
5856
- for (const ref2 of findCrossNodeBindingReferences(obj, nodeIds)) {
5857
- issues.push({
5858
- path,
5859
- severity,
5860
- message: crossNodeBindingMessage(obj, ref2)
5861
- });
5862
- }
6076
+ function readEssentialConfiguration(detail) {
6077
+ const configuration = detail.configuration;
6078
+ if (typeof configuration !== "string")
5863
6079
  return;
5864
- }
5865
- if (Array.isArray(obj)) {
5866
- for (let i2 = 0;i2 < obj.length; i2++) {
5867
- scanContainerForCrossNodeBindings(obj[i2], `${path}[${i2}]`, nodeIds, severity, issues);
5868
- }
6080
+ const [, parsed] = catchError(() => JSON.parse(configuration.replace(/^=jsonString:/, "")));
6081
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
5869
6082
  return;
5870
6083
  }
5871
- if (obj && typeof obj === "object") {
5872
- for (const [key, value] of Object.entries(obj)) {
5873
- scanContainerForCrossNodeBindings(value, `${path}.${key}`, nodeIds, severity, issues);
6084
+ return readObjectField(parsed, "essentialConfiguration");
6085
+ }
6086
+ function readEssentialPath(detail) {
6087
+ const path = readEssentialConfiguration(detail)?.path;
6088
+ return typeof path === "string" && path.length > 0 ? path : undefined;
6089
+ }
6090
+ function validateEndpointMatchesActivityPath(nodeId, detail) {
6091
+ const endpoint = detail.endpoint;
6092
+ if (typeof endpoint !== "string" || endpoint.length === 0)
6093
+ return [];
6094
+ const activityPath = readEssentialPath(detail);
6095
+ if (!activityPath)
6096
+ return [];
6097
+ const substituted = new Set;
6098
+ const pathParameters = detail.pathParameters;
6099
+ if (pathParameters && typeof pathParameters === "object") {
6100
+ for (const v of Object.values(pathParameters)) {
6101
+ if (typeof v === "string" || typeof v === "number") {
6102
+ substituted.add(String(v));
6103
+ }
5874
6104
  }
5875
6105
  }
5876
- }
5877
- var PARAMETER_CONTAINER_KEYS = [
5878
- "bodyParameters",
5879
- "queryParameters",
5880
- "pathParameters"
5881
- ];
5882
- function scanDetailForCrossNodeBindings(detail, nodeIds, severity = "warning") {
5883
- if (!detail || nodeIds.size === 0)
6106
+ if (endpointNamesActivity(staticSegments(endpoint, substituted), staticSegments(activityPath, substituted))) {
5884
6107
  return [];
5885
- const issues = [];
5886
- for (const containerKey of PARAMETER_CONTAINER_KEYS) {
5887
- const container = detail[containerKey];
5888
- if (!container || typeof container !== "object" || Array.isArray(container)) {
5889
- continue;
6108
+ }
6109
+ return [
6110
+ {
6111
+ path: `nodes[${nodeId}].inputs.detail.endpoint`,
6112
+ severity: "warning",
6113
+ message: `endpoint "${endpoint}" does not name the activity this node is configured for — its path is "${activityPath}" ` + "(essentialConfiguration.path). The runtime calls the endpoint verbatim, so the request reaches a different operation and fails at debug " + "with the provider's words for a missing or unknown field (e.g. Slack [102003] no_text when the v1 endpoint receives the v2 body). " + `Re-run node configure with --detail.endpoint "${activityPath}" (keep {param} segments; values go in pathParameters).`
5890
6114
  }
5891
- scanContainerForCrossNodeBindings(container, `detail.${containerKey}`, nodeIds, severity, issues);
6115
+ ];
6116
+ }
6117
+ function validateCeqlFilterShape(nodeId, detail) {
6118
+ const issues = [];
6119
+ const queryParameters = readObjectField(detail, "queryParameters");
6120
+ if (queryParameters && Object.hasOwn(queryParameters, "$where")) {
6121
+ issues.push({
6122
+ path: `nodes[${nodeId}].inputs.detail.queryParameters["$where"]`,
6123
+ severity: "error",
6124
+ message: 'Connector node uses OData-style `"$where"` (with leading `$`) ' + "in queryParameters. CEQL uses bare `where` — rename the key " + 'from `"$where"` to `"where"`. The leading `$` is the OData ' + "system-query-option prefix and is not recognized by " + "uipath.connector.* nodes. See uipath-maestro-flow skill — " + 'plugins/connector/impl.md, "Hand-authored CEQL strings" ' + "(MST-9265)."
6125
+ });
6126
+ }
6127
+ const queryWhere = queryParameters?.where;
6128
+ const queryWhereAuthored = isNonEmptyString(queryWhere);
6129
+ const queryWhereIsWholeValueExpression = typeof queryWhere === "string" && queryWhere.startsWith("=js:");
6130
+ const savedTrees = readObjectField(detail, "savedFilterTrees") ?? readEssentialSavedFilterTrees(detail);
6131
+ const savedWhereAuthored = savedTrees !== undefined && isNonEmptyObject(savedTrees.where);
6132
+ if (queryWhereAuthored && !queryWhereIsWholeValueExpression && !savedWhereAuthored) {
6133
+ issues.push({
6134
+ path: `nodes[${nodeId}].inputs.detail.savedFilterTrees.where`,
6135
+ severity: "error",
6136
+ message: "Connector node has `queryParameters.where` set but no " + "matching `savedFilterTrees.where` AST — neither at " + "`inputs.detail.savedFilterTrees.where` nor as " + "`essentialConfiguration.savedFilterTrees.where` inside " + "`inputs.detail.configuration`. CEQL filters must be authored " + "as both the raw filter expression (`queryParameters.where`) " + "AND a parallel canonical AST (`filters[].id` / `.operator` / " + "`.value.value`). The Studio Web canvas needs the AST to " + "render the filter UI; the runtime needs the expression. " + "Re-run `uip maestro flow node configure --detail.filter` to " + "author both. See uipath-maestro-flow skill — " + 'plugins/connector/impl.md, "Hand-authored CEQL strings" ' + "(MST-9265)."
6137
+ });
6138
+ }
6139
+ if (savedWhereAuthored && !queryWhereAuthored) {
6140
+ issues.push({
6141
+ path: `nodes[${nodeId}].inputs.detail.queryParameters.where`,
6142
+ severity: "error",
6143
+ message: "Connector node has `savedFilterTrees.where` AST but no " + "matching `queryParameters.where` expression. CEQL filters " + "must be authored on both keys in parallel — the runtime " + "evaluates `queryParameters.where`, not the AST. See " + 'uipath-maestro-flow skill — plugins/connector/impl.md, "Hand-authored ' + 'CEQL strings" (MST-9265).'
6144
+ });
5892
6145
  }
5893
6146
  return issues;
5894
6147
  }
5895
- var crossNodeBindingValidator = {
5896
- id: "cross-node-binding",
5897
- appliesTo: (node) => {
5898
- const t = node.type;
5899
- if (!t)
5900
- return false;
5901
- if (isEventDrivenConnectorType(t))
5902
- return false;
5903
- return t.startsWith("uipath.connector.") || t === "core.action.http" || t === "core.action.http.v2";
5904
- },
5905
- validate: (node, context) => {
5906
- const nodeIds = context.nodeIds ?? new Set;
5907
- if (nodeIds.size === 0)
5908
- return [];
5909
- const rawDetail = node.inputs?.detail;
5910
- if (!rawDetail || typeof rawDetail !== "object" || Array.isArray(rawDetail)) {
5911
- return [];
5912
- }
5913
- const severity = context.strictBindings ? "error" : "warning";
5914
- const issues = scanDetailForCrossNodeBindings(rawDetail, nodeIds, severity);
5915
- return issues.map((issue) => ({
5916
- ...issue,
5917
- path: `nodes[${node.id}].inputs.${issue.path}`
5918
- }));
6148
+ function readEssentialSavedFilterTrees(detail) {
6149
+ const essentialConfiguration = readEssentialConfiguration(detail);
6150
+ if (!essentialConfiguration)
6151
+ return;
6152
+ return readObjectField(essentialConfiguration, "savedFilterTrees");
6153
+ }
6154
+ function readObjectField(parent, key) {
6155
+ const value = parent[key];
6156
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
6157
+ return;
5919
6158
  }
5920
- };
6159
+ return value;
6160
+ }
6161
+ function isNonEmptyString(value) {
6162
+ return typeof value === "string" && value.trim().length > 0;
6163
+ }
6164
+ function isNonEmptyObject(value) {
6165
+ return !!value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length > 0;
6166
+ }
5921
6167
 
5922
6168
  // src/services/node-validators/expression-prefix-validator.ts
5923
6169
  var expressionPrefixValidator = {
@@ -6098,7 +6344,8 @@ var jsExpressionSyntaxValidator = {
6098
6344
  for (const containerKey of [
6099
6345
  "bodyParameters",
6100
6346
  "queryParameters",
6101
- "pathParameters"
6347
+ "pathParameters",
6348
+ "filterVariables"
6102
6349
  ]) {
6103
6350
  const container = detail[containerKey];
6104
6351
  if (!container || typeof container !== "object" || Array.isArray(container)) {
@@ -6147,1632 +6394,561 @@ function scanForInvalidJsExpressions(obj, path, severity, issues) {
6147
6394
  }
6148
6395
  return;
6149
6396
  }
6150
- if (obj && typeof obj === "object") {
6151
- for (const [key, value] of Object.entries(obj)) {
6152
- scanForInvalidJsExpressions(value, `${path}.${key}`, severity, issues);
6153
- }
6154
- }
6155
- }
6156
- function reportInvalidExpression(expression, path, severity, issues) {
6157
- if (expression.trim() === "")
6158
- return;
6159
- const error = syntaxErrorFrom(() => parse3(`(${expression}
6160
- )`, {
6161
- ecmaVersion: 2020,
6162
- sourceType: "script"
6163
- }));
6164
- if (!error)
6165
- return;
6166
- issues.push({
6167
- path,
6168
- severity,
6169
- message: `Expression at this field is not valid JavaScript: ${error.message}. Fix the syntax — validate cannot otherwise catch JavaScript expression errors; they surface only at flow debug.`
6170
- });
6171
- }
6172
- function syntaxErrorFrom(parseSource) {
6173
- try {
6174
- parseSource();
6175
- return;
6176
- } catch (err) {
6177
- return err instanceof Error ? err : new Error(String(err));
6178
- }
6179
- }
6180
-
6181
- // src/services/node-validators/model-source-validator.ts
6182
- var modelSourceValidator = {
6183
- id: "model-source",
6184
- appliesTo: () => true,
6185
- validate: (node, context) => {
6186
- const definition = context.definitions.find((d) => d.nodeType === node.type);
6187
- if (!definition)
6188
- return [];
6189
- const requiresModelSource = readModelSourceFlag(definition);
6190
- if (!requiresModelSource)
6191
- return [];
6192
- const legacySource = readLegacyModelSource(node);
6193
- if (legacySource !== undefined) {
6194
- return [
6195
- {
6196
- path: `nodes[${node.id}].model.source`,
6197
- severity: "error",
6198
- message: `Node type "${node.type}" carries the deprecated ` + `"model.source" UUID on the node instance. ` + `flow-core 0.2.50+ requires the canvas-generated ` + `UUID at "inputs.source"; remove "model.source" ` + `from the node and place the value under ` + `"inputs": { "source": "<uuid>" } instead. ` + `See uipath-maestro-flow skill — ` + `inline-agent/impl.md (MST-9265).`
6199
- }
6200
- ];
6201
- }
6202
- const inputsSource = node.inputs?.source;
6203
- if (typeof inputsSource === "string" && inputsSource.length > 0) {
6204
- return [];
6205
- }
6206
- return [
6207
- {
6208
- path: `nodes[${node.id}].inputs.source`,
6209
- severity: "error",
6210
- message: `Node type "${node.type}" requires a stable UUID at ` + `"inputs.source" — the agent's ProjectId for inline ` + `agent nodes, or the resource id from the parent inline ` + `agent's "resources[]" for agent-tool resource nodes. ` + `Set "inputs": { "source": "<uuid>" } on the node ` + `(use the ProjectId returned by ` + `"uip agent init --inline-in-flow" for inline agents). ` + `See uipath-maestro-flow skill — inline-agent/impl.md ` + `(MST-9265).`
6211
- }
6212
- ];
6213
- }
6214
- };
6215
- function readModelSourceFlag(definition) {
6216
- const model = definition.model;
6217
- if (!model || typeof model !== "object" || Array.isArray(model)) {
6218
- return false;
6219
- }
6220
- const source = model.source;
6221
- return source === true;
6222
- }
6223
- function readLegacyModelSource(node) {
6224
- const model = node.model;
6225
- if (!model || typeof model !== "object" || Array.isArray(model)) {
6226
- return;
6227
- }
6228
- const source = model.source;
6229
- if (typeof source === "string" && source.length > 0) {
6230
- return source;
6231
- }
6232
- return;
6233
- }
6234
-
6235
- // src/services/node-validators/index.ts
6236
- var defaultNodeValidators = [
6237
- activityTypeIdValidator,
6238
- ceqlQueryValidator,
6239
- connectorNodeValidator,
6240
- crossNodeBindingValidator,
6241
- expressionPrefixValidator,
6242
- jsExpressionSyntaxValidator,
6243
- ixpNodeValidator,
6244
- modelSourceValidator
6245
- ];
6246
-
6247
- // src/utils/error-edge-handling.ts
6248
- var ERROR_SOURCE_PORT = "error";
6249
- function collectErrorEdgeSourceNodeIds(edges) {
6250
- return new Set(edges.filter((edge) => edge.sourcePort === ERROR_SOURCE_PORT).map((edge) => edge.sourceNodeId));
6251
- }
6252
- function enableErrorHandlingForErrorEdges(nodes, edges) {
6253
- const sourceNodeIds = collectErrorEdgeSourceNodeIds(edges);
6254
- let updated = 0;
6255
- for (const node of nodes) {
6256
- if (!sourceNodeIds.has(node.id))
6257
- continue;
6258
- if (node.inputs?.errorHandlingEnabled === true)
6259
- continue;
6260
- node.inputs = {
6261
- ...node.inputs ?? {},
6262
- errorHandlingEnabled: true
6263
- };
6264
- updated += 1;
6265
- }
6266
- return updated;
6267
- }
6268
-
6269
- // src/utils/handle-expansion.ts
6270
- var VISIBLE_INPUT_EXPRESSION = /^\{inputs\.([A-Za-z0-9_]+)\}$/;
6271
- function parseVisibleInputKey(visible) {
6272
- if (typeof visible !== "string")
6273
- return null;
6274
- const match = VISIBLE_INPUT_EXPRESSION.exec(visible);
6275
- return match ? match[1] : null;
6276
- }
6277
- function isHandleVisible(handle, node) {
6278
- const { visible } = handle;
6279
- if (visible === undefined || visible === true)
6280
- return true;
6281
- if (visible === false)
6282
- return false;
6283
- const inputKey = parseVisibleInputKey(visible);
6284
- if (inputKey === null) {
6285
- return true;
6286
- }
6287
- return node.inputs?.[inputKey] === true;
6288
- }
6289
- function expandHandleIds(handle, node) {
6290
- if (!handle.repeat) {
6291
- return [handle.id];
6292
- }
6293
- const repeatPath = handle.repeat.split(".");
6294
- let collection = node;
6295
- for (const segment of repeatPath) {
6296
- if (collection && typeof collection === "object") {
6297
- collection = collection[segment];
6298
- } else {
6299
- collection = undefined;
6300
- break;
6301
- }
6302
- }
6303
- if (!Array.isArray(collection)) {
6304
- return [handle.id];
6305
- }
6306
- return collection.filter((item) => item != null && typeof item === "object").map((item) => handle.id.replace(/\{item\.(\w+)\}/g, (_match, key) => String(item[key] ?? "")));
6307
- }
6308
- function isTemplatedHandleId(id) {
6309
- return id.includes("{");
6310
- }
6311
- var escapeRegexMetachars = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6312
- function portMatchesTemplate(requestedPort, templateId) {
6313
- if (!isTemplatedHandleId(templateId)) {
6314
- return requestedPort === templateId;
6315
- }
6316
- const parts = templateId.split(/\{[^}]*\}/);
6317
- const escapedParts = parts.map(escapeRegexMetachars);
6318
- const pattern = new RegExp(`^${escapedParts.join(".+")}$`);
6319
- return pattern.test(requestedPort);
6320
- }
6321
-
6322
- // src/services/connector-binding-validator.ts
6323
- var STATIC_CONNECTOR_KEYWORDS = [
6324
- "slack",
6325
- "gmail",
6326
- "outlook",
6327
- "office365",
6328
- "exchange",
6329
- "jira",
6330
- "confluence",
6331
- "salesforce",
6332
- "sfdc",
6333
- "hubspot",
6334
- "servicenow",
6335
- "zendesk",
6336
- "intercom",
6337
- "notion",
6338
- "asana",
6339
- "trello",
6340
- "monday",
6341
- "github",
6342
- "gitlab",
6343
- "bitbucket",
6344
- "discord",
6345
- "teams",
6346
- "sharepoint",
6347
- "onedrive",
6348
- "dropbox",
6349
- "box",
6350
- "googledrive",
6351
- "docusign",
6352
- "adobesign",
6353
- "mailchimp",
6354
- "sendgrid",
6355
- "twilio",
6356
- "stripe",
6357
- "shopify",
6358
- "quickbooks",
6359
- "xero",
6360
- "workday",
6361
- "successfactors",
6362
- "bamboohr",
6363
- "sap",
6364
- "netsuite",
6365
- "oracle",
6366
- "marketo",
6367
- "pardot",
6368
- "segment",
6369
- "snowflake",
6370
- "bigquery",
6371
- "redshift",
6372
- "databricks",
6373
- "tableau",
6374
- "powerbi"
6375
- ];
6376
- var ACTION_VERBS = [
6377
- "send",
6378
- "post",
6379
- "create",
6380
- "update",
6381
- "delete",
6382
- "get",
6383
- "fetch",
6384
- "list",
6385
- "read",
6386
- "write",
6387
- "upload",
6388
- "download",
6389
- "find",
6390
- "add",
6391
- "remove",
6392
- "query",
6393
- "search",
6394
- "notify",
6395
- "publish",
6396
- "subscribe",
6397
- "trigger",
6398
- "watch",
6399
- "share",
6400
- "invite",
6401
- "schedule",
6402
- "assign",
6403
- "close",
6404
- "open",
6405
- "reply",
6406
- "forward",
6407
- "archive"
6408
- ];
6409
- var MANAGED_HTTP_NODE_TYPE = "core.action.http.v2";
6410
- async function loadConnectorCatalog() {
6411
- const keywords2 = new Set(STATIC_CONNECTOR_KEYWORDS);
6412
- const activityTokenBags = [];
6413
- const [err, registry] = await catchError(loadRegistry());
6414
- if (err) {
6415
- logger.debug(`Connector-binding validator: could not load IS catalog cache (${err.message}); falling back to static keyword list.`);
6416
- return { keywords: keywords2, activityTokenBags };
6417
- }
6418
- if (!registry) {
6419
- return { keywords: keywords2, activityTokenBags };
6420
- }
6421
- for (const connector of registry.discovered.connectors) {
6422
- addConnectorKeywords(connector, keywords2);
6423
- for (const activity of connector.activities) {
6424
- const tokens = tokenize(activity.displayName);
6425
- if (tokens.size > 0) {
6426
- activityTokenBags.push({
6427
- connectorKey: connector.key,
6428
- connectorName: connector.name,
6429
- tokens
6430
- });
6431
- }
6432
- }
6433
- }
6434
- return { keywords: keywords2, activityTokenBags };
6435
- }
6436
- function addConnectorKeywords(connector, out) {
6437
- const keyParts = connector.key.toLowerCase().split("-").filter((p) => p && p !== "uipath");
6438
- for (const part of keyParts)
6439
- out.add(part);
6440
- for (const t of tokenize(connector.name))
6441
- out.add(t);
6442
- }
6443
- function tokenize(label) {
6444
- if (!label)
6445
- return new Set;
6446
- const tokens = label.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length > 1);
6447
- return new Set(tokens);
6448
- }
6449
- function readNodeLabel(node) {
6450
- const fromDisplay = node.display?.label;
6451
- if (typeof fromDisplay === "string" && fromDisplay.length > 0) {
6452
- return fromDisplay;
6453
- }
6454
- const fromName = node.name;
6455
- if (typeof fromName === "string" && fromName.length > 0) {
6456
- return fromName;
6457
- }
6458
- return;
6459
- }
6460
- function hasConnectorBinding(node) {
6461
- const detail = node.inputs?.detail;
6462
- if (!detail || typeof detail !== "object" || Array.isArray(detail)) {
6463
- return false;
6464
- }
6465
- const d = detail;
6466
- const authentication = d.authentication;
6467
- if (authentication === "connector") {
6468
- const connectionId = d.connectionId;
6469
- const targetConnector = d.targetConnector;
6470
- return typeof connectionId === "string" && connectionId.length > 0 && connectionId !== "ImplicitConnection" && typeof targetConnector === "string" && targetConnector.length > 0;
6471
- }
6472
- if (authentication === "manual") {
6473
- const url = d.url;
6474
- return typeof url === "string" && url.length > 0;
6475
- }
6476
- return false;
6477
- }
6478
- function classifyLabel(label, catalog) {
6479
- const tokens = tokenize(label);
6480
- if (tokens.size === 0)
6481
- return null;
6482
- for (const bag of catalog.activityTokenBags) {
6483
- let overlap = 0;
6484
- for (const t of bag.tokens) {
6485
- if (tokens.has(t))
6486
- overlap += 1;
6487
- }
6488
- if (overlap >= 2) {
6489
- const keyword = pickConnectorKeyword(tokens, catalog.keywords);
6490
- return {
6491
- connectorKeyword: keyword ?? bag.connectorKey,
6492
- matchedActivity: {
6493
- connectorKey: bag.connectorKey,
6494
- connectorName: bag.connectorName
6495
- }
6496
- };
6497
- }
6498
- }
6499
- const matchedKeyword = pickConnectorKeyword(tokens, catalog.keywords);
6500
- if (!matchedKeyword)
6501
- return null;
6502
- const hasVerb = [...tokens].some((t) => ACTION_VERBS.includes(t));
6503
- if (!hasVerb)
6504
- return null;
6505
- return { connectorKeyword: matchedKeyword };
6506
- }
6507
- function pickConnectorKeyword(tokens, keywords2) {
6508
- for (const t of tokens) {
6509
- if (keywords2.has(t))
6510
- return t;
6511
- }
6512
- return;
6513
- }
6514
- function buildDiagnosticMessage(label, classification, strict) {
6515
- const connectorHint = classification.matchedActivity ? `looks like a "${classification.matchedActivity.connectorName}" connector activity` : `mentions the "${classification.connectorKeyword}" connector keyword`;
6516
- const strictNote = strict ? " (--strict-bindings promoted this to an error.)" : " Pass `--strict-bindings` to fail validation on this.";
6517
- const connectorDetail = `{"authentication":"connector",` + `"targetConnector":"${classification.connectorKeyword}",` + `"connectionId":"<uuid>","folderKey":"<uuid>","method":"GET","url":"<path>"}`;
6518
- const manualDetail = `{"authentication":"manual","method":"GET","url":"https://…"}`;
6519
- return `Node "${label}" ${connectorHint} but uses the generic Managed HTTP type \`${MANAGED_HTTP_NODE_TYPE}\` ` + "with no connection binding. The runtime will issue a raw HTTP call to an undefined endpoint. " + `Either bind a real Integration Service connection with \`uip maestro flow node configure <file> <node-id> --detail '${connectorDetail}'\`, ` + `or configure manual-mode HTTP with \`--detail '${manualDetail}'\`. ` + "If this node is intentionally a raw HTTP call, rename it so the label doesn't " + `imply a connector binding.${strictNote}`;
6520
- }
6521
- function validateConnectorBindings(workflow, catalog, options = {}) {
6522
- const issues = [];
6523
- const severity = options.strict ? "error" : "warning";
6524
- const checkNode = (node, scope) => {
6525
- if (node.type !== MANAGED_HTTP_NODE_TYPE)
6526
- return;
6527
- if (hasConnectorBinding(node))
6528
- return;
6529
- const label = readNodeLabel(node);
6530
- if (!label)
6531
- return;
6532
- const classification = classifyLabel(label, catalog);
6533
- if (!classification)
6534
- return;
6535
- issues.push({
6536
- path: `${scope}nodes[${node.id}].inputs.detail`,
6537
- severity,
6538
- message: buildDiagnosticMessage(label, classification, options.strict === true)
6539
- });
6540
- };
6541
- for (const node of workflow.nodes) {
6542
- checkNode(node, "");
6543
- }
6544
- for (const [subflowId, sub] of Object.entries(workflow.subflows ?? {})) {
6545
- for (const node of sub.nodes ?? []) {
6546
- checkNode(node, `subflows[${subflowId}].`);
6547
- }
6548
- }
6549
- return issues;
6550
- }
6551
-
6552
- // src/services/flow-eval-schema/prompts.ts
6553
- var DEFAULT_EVALUATOR_PROMPT = `As an expert evaluator, analyze the semantic similarity of these JSON contents to determine a score from 0-100. Focus on comparing the meaning and contextual equivalence of corresponding fields, accounting for alternative valid expressions, synonyms, and reasonable variations in language while maintaining high standards for accuracy and completeness. Provide your score with a justification, explaining briefly and concisely why you gave that score.
6554
- ----
6555
- ExpectedOutput:
6556
- {{ExpectedOutput}}
6557
- ----
6558
- ActualOutput:
6559
- {{ActualOutput}}
6560
- `;
6561
- var DEFAULT_TRAJECTORY_EVALUATOR_PROMPT = `As an expert evaluator, determine how well the agent did on a scale of 0-100. Focus on if the simulation was successful and if the agent behaved according to the expected output accounting for alternative valid expressions, and reasonable variations in language while maintaining high standards for accuracy and completeness. Provide your score with a justification, explaining briefly and concisely why you gave that score.
6562
- ----
6563
- UserOrSyntheticInputGivenToAgent:
6564
- {{UserOrSyntheticInput}}
6565
- ----
6566
- SimulationInstructions:
6567
- {{SimulationInstructions}}
6568
- ----
6569
- ExpectedAgentBehavior:
6570
- {{ExpectedAgentBehavior}}
6571
- ----
6572
- AgentRunHistory:
6573
- {{AgentRunHistory}}
6574
- `;
6575
-
6576
- // src/services/flow-eval-schema/evaluator-fields.ts
6577
- var targetOutputKeyConfigField = {
6578
- key: "targetOutputKey",
6579
- label: "Target Output Key",
6580
- type: "targetOutputKey",
6581
- required: false,
6582
- description: "The key in the output to evaluate"
6583
- };
6584
- var caseSensitiveConfigField = {
6585
- key: "caseSensitive",
6586
- label: "Case Sensitive",
6587
- type: "boolean",
6588
- required: false,
6589
- default: false,
6590
- description: "If true, the comparison is case-sensitive"
6591
- };
6592
- var negatedConfigField = {
6593
- key: "negated",
6594
- label: "Negated",
6595
- type: "boolean",
6596
- required: false,
6597
- default: false,
6598
- description: "If true, the evaluation passes when the match is not found"
6599
- };
6600
- var expectedOutputCriteriaField = {
6601
- key: "expectedOutput",
6602
- label: "Expected Output",
6603
- type: "object",
6604
- required: false,
6605
- description: "The expected output value for this evaluator"
6606
- };
6607
- var llmBaseConfigFields = [
6608
- {
6609
- key: "model",
6610
- label: "Model",
6611
- type: "llmModel",
6612
- required: true,
6613
- description: "The LLM model to use for judging"
6614
- },
6615
- {
6616
- key: "prompt",
6617
- label: "Evaluation Prompt",
6618
- type: "string",
6619
- required: true,
6620
- default: DEFAULT_EVALUATOR_PROMPT,
6621
- description: "Custom prompt template for the LLM judge"
6622
- },
6623
- {
6624
- key: "temperature",
6625
- label: "Temperature",
6626
- type: "number",
6627
- required: true,
6628
- default: 0,
6629
- min: 0,
6630
- max: 2,
6631
- step: 0.1,
6632
- description: "Temperature for LLM generation"
6633
- },
6634
- {
6635
- key: "maxTokens",
6636
- label: "Max Tokens",
6637
- type: "number",
6638
- required: true,
6639
- default: 8192,
6640
- min: 0,
6641
- max: 16384,
6642
- step: 256,
6643
- description: "Maximum tokens for LLM response"
6644
- }
6645
- ];
6646
- var llmTrajectoryBaseConfigFields = llmBaseConfigFields.map((field) => field.key === "prompt" ? { ...field, default: DEFAULT_TRAJECTORY_EVALUATOR_PROMPT } : field);
6647
-
6648
- // src/services/flow-eval-schema/deterministic-evaluators.ts
6649
- var DETERMINISTIC_EVALUATOR_TYPES = {
6650
- "uipath-contains": {
6651
- name: "Contains Text",
6652
- description: "Check if output contains specific text",
6653
- category: "deterministic",
6654
- shortDescription: "Passes when output contains given text",
6655
- configFields: [
6656
- targetOutputKeyConfigField,
6657
- caseSensitiveConfigField,
6658
- {
6659
- ...negatedConfigField,
6660
- label: "Negated (should NOT contain)"
6661
- }
6662
- ],
6663
- criteriaFields: [
6664
- {
6665
- key: "searchText",
6666
- label: "Search Text",
6667
- type: "string",
6668
- required: false,
6669
- minLength: 1,
6670
- description: "The text to search for in the output"
6671
- }
6672
- ],
6673
- examples: {
6674
- criteria: { searchText: "loan approved" }
6675
- }
6676
- },
6677
- "uipath-exact-match": {
6678
- name: "Exact Match",
6679
- description: "Check if output exactly matches expected value",
6680
- category: "deterministic",
6681
- shortDescription: "Passes when output is an exact match",
6682
- configFields: [
6683
- targetOutputKeyConfigField,
6684
- caseSensitiveConfigField,
6685
- negatedConfigField
6686
- ],
6687
- criteriaFields: [expectedOutputCriteriaField],
6688
- examples: {
6689
- criteria: { expectedOutput: { value: "Application approved" } }
6690
- }
6691
- },
6692
- "uipath-json-similarity": {
6693
- name: "JSON Similarity",
6694
- description: "Compare JSON output similarity",
6695
- category: "deterministic",
6696
- shortDescription: "Passes when JSON structures are similar",
6697
- configFields: [targetOutputKeyConfigField],
6698
- criteriaFields: [expectedOutputCriteriaField],
6699
- examples: {
6700
- criteria: { expectedOutput: { status: "ok" } }
6701
- }
6702
- }
6703
- };
6704
-
6705
- // src/services/flow-eval-schema/llm-judge-evaluators.ts
6706
- var LLM_JUDGE_EVALUATOR_TYPES = {
6707
- "uipath-llm-judge-output-semantic-similarity": {
6708
- name: "LLM Judge Output",
6709
- description: "Use LLM to judge semantic similarity of outputs",
6710
- category: "llm-judge",
6711
- shortDescription: "AI judges if output semantically matches expected",
6712
- configFields: [...llmBaseConfigFields, targetOutputKeyConfigField],
6713
- criteriaFields: [expectedOutputCriteriaField],
6714
- examples: {
6715
- config: { model: "gpt-4o", temperature: 0 },
6716
- criteria: {
6717
- expectedOutput: {
6718
- text: "The loan has been approved for the requested amount."
6719
- }
6720
- }
6721
- }
6722
- },
6723
- "uipath-llm-judge-output-strict-json-similarity": {
6724
- name: "LLM Judge Strict JSON",
6725
- description: "Use LLM to judge strict JSON similarity",
6726
- category: "llm-judge",
6727
- shortDescription: "AI judges strict JSON structural match",
6728
- configFields: [...llmBaseConfigFields, targetOutputKeyConfigField],
6729
- criteriaFields: [expectedOutputCriteriaField],
6730
- examples: {
6731
- config: { model: "gpt-4o", temperature: 0 },
6732
- criteria: { expectedOutput: { result: "success" } }
6733
- }
6734
- },
6735
- "uipath-llm-judge-trajectory-similarity": {
6736
- name: "LLM Judge Trajectory",
6737
- description: "Use LLM to judge agent trajectory and behavior",
6738
- category: "llm-judge",
6739
- shortDescription: "AI judges if agent followed expected behavior",
6740
- configFields: llmTrajectoryBaseConfigFields,
6741
- criteriaFields: [
6742
- {
6743
- key: "expectedAgentBehavior",
6744
- label: "Expected Agent Behavior",
6745
- type: "string",
6746
- required: false,
6747
- description: "Description of expected agent behavior and actions"
6748
- }
6749
- ],
6750
- examples: {
6751
- config: { model: "gpt-4o" },
6752
- criteria: {
6753
- expectedAgentBehavior: "Agent checks eligibility, then calls approval API"
6754
- }
6755
- }
6756
- },
6757
- "uipath-llm-judge-trajectory-simulation": {
6758
- name: "LLM Judge Simulation",
6759
- description: "Use LLM to judge simulation trajectory",
6760
- category: "llm-judge",
6761
- shortDescription: "AI judges simulated agent execution path",
6762
- configFields: llmTrajectoryBaseConfigFields,
6763
- criteriaFields: [
6764
- {
6765
- key: "expectedAgentBehavior",
6766
- label: "Expected Agent Behavior",
6767
- type: "string",
6768
- required: false,
6769
- description: "Description of expected agent behavior during simulation"
6770
- }
6771
- ],
6772
- examples: {
6773
- config: { model: "gpt-4o" },
6774
- criteria: {
6775
- expectedAgentBehavior: "Agent simulates the user journey through checkout flow"
6776
- }
6777
- }
6778
- }
6779
- };
6780
-
6781
- // src/services/flow-eval-schema/tool-call-evaluators.ts
6782
- var TOOL_CALL_EVALUATOR_TYPES = {
6783
- "uipath-tool-call-args": {
6784
- name: "Tool Call Arguments",
6785
- description: "Verify tool call arguments match expected values",
6786
- category: "tool-call",
6787
- shortDescription: "Checks that tools were called with correct arguments",
6788
- configFields: [
6789
- {
6790
- key: "strict",
6791
- label: "Strict Mode",
6792
- type: "boolean",
6793
- required: false,
6794
- default: false,
6795
- description: "If true, requires exact match of all tool call arguments"
6796
- },
6797
- {
6798
- key: "subset",
6799
- label: "Subset Mode",
6800
- type: "boolean",
6801
- required: false,
6802
- default: false,
6803
- description: "If true, allows actual tool calls to be a subset of expected"
6804
- }
6805
- ],
6806
- criteriaFields: [
6807
- {
6808
- key: "toolCalls",
6809
- label: "Tool Calls",
6810
- type: "toolCallArgs",
6811
- required: false,
6812
- description: "Expected tool calls with names and arguments"
6813
- }
6814
- ]
6815
- },
6816
- "uipath-tool-call-count": {
6817
- name: "Tool Call Count",
6818
- description: "Verify tool call counts match expected values",
6819
- category: "tool-call",
6820
- shortDescription: "Checks number of times each tool was called",
6821
- configFields: [
6822
- {
6823
- key: "strict",
6824
- label: "Strict Mode",
6825
- type: "boolean",
6826
- required: false,
6827
- default: false,
6828
- description: "If true, requires exact count match"
6829
- }
6830
- ],
6831
- criteriaFields: [
6832
- {
6833
- key: "toolCallsCount",
6834
- label: "Tool Calls Count",
6835
- type: "toolCallCount",
6836
- required: false,
6837
- description: "Expected tool call counts with comparison operators"
6838
- }
6839
- ]
6840
- },
6841
- "uipath-tool-call-order": {
6842
- name: "Tool Call Order",
6843
- description: "Verify tool calls occur in expected order",
6844
- category: "tool-call",
6845
- shortDescription: "Checks that tools were called in the right sequence",
6846
- configFields: [
6847
- {
6848
- key: "strict",
6849
- label: "Strict Mode",
6850
- type: "boolean",
6851
- required: false,
6852
- default: false,
6853
- description: "If true, requires exact order match"
6854
- }
6855
- ],
6856
- criteriaFields: [
6857
- {
6858
- key: "toolCallsOrder",
6859
- label: "Tool Calls Order",
6860
- type: "toolCallOrder",
6861
- required: false,
6862
- description: "Tool names in expected execution order"
6863
- }
6864
- ]
6865
- },
6866
- "uipath-tool-call-output": {
6867
- name: "Tool Call Output",
6868
- description: "Verify tool call outputs match expected values",
6869
- category: "tool-call",
6870
- shortDescription: "Checks that tool outputs match expected values",
6871
- configFields: [
6872
- {
6873
- key: "strict",
6874
- label: "Strict Mode",
6875
- type: "boolean",
6876
- required: false,
6877
- default: false,
6878
- description: "If true, requires exact output match"
6879
- }
6880
- ],
6881
- criteriaFields: [
6882
- {
6883
- key: "toolOutputs",
6884
- label: "Tool Outputs",
6885
- type: "toolCallOutput",
6886
- required: false,
6887
- description: "Expected tool outputs with names and output values"
6888
- }
6889
- ]
6890
- }
6891
- };
6892
-
6893
- // src/services/flow-eval-schema/registry.ts
6894
- var EVALUATOR_TYPE_REGISTRY = {
6895
- ...DETERMINISTIC_EVALUATOR_TYPES,
6896
- ...LLM_JUDGE_EVALUATOR_TYPES,
6897
- ...TOOL_CALL_EVALUATOR_TYPES
6898
- };
6899
- var EVALUATOR_TYPE_ALIASES = {
6900
- "exact-match": "uipath-exact-match",
6901
- "json-similarity": "uipath-json-similarity",
6902
- contains: "uipath-contains",
6903
- "llm-judge-output": "uipath-llm-judge-output-semantic-similarity",
6904
- "llm-judge-strict-json": "uipath-llm-judge-output-strict-json-similarity",
6905
- "llm-judge-trajectory": "uipath-llm-judge-trajectory-similarity",
6906
- "llm-judge-trajectory-simulation": "uipath-llm-judge-trajectory-simulation"
6907
- };
6908
-
6909
- // src/services/flow-eval-schema/helpers.ts
6910
- function evaluatorTypeAliases() {
6911
- return Object.keys(EVALUATOR_TYPE_ALIASES);
6912
- }
6913
- function isEvaluatorTypeId(value) {
6914
- return value in EVALUATOR_TYPE_REGISTRY;
6915
- }
6916
- function getEvaluatorTypeDefinition(typeId) {
6917
- if (!isEvaluatorTypeId(typeId)) {
6918
- return null;
6919
- }
6920
- return EVALUATOR_TYPE_REGISTRY[typeId];
6921
- }
6922
- function resolveEvaluatorType(type) {
6923
- const resolved = EVALUATOR_TYPE_ALIASES[type] ?? type;
6924
- if (!isEvaluatorTypeId(resolved)) {
6925
- throw new Error(`Unknown evaluator type "${type}". Valid types: ${evaluatorTypeAliases().join(", ")}`);
6926
- }
6927
- return resolved;
6928
- }
6929
- function getDefaultConfigForEvaluatorType(typeId) {
6930
- return collectFieldDefaults(EVALUATOR_TYPE_REGISTRY[typeId].configFields);
6931
- }
6932
- function collectFieldDefaults(fields) {
6933
- const defaults = {};
6934
- for (const field of fields) {
6935
- if (field.default !== undefined) {
6936
- defaults[field.key] = field.default;
6937
- }
6938
- }
6939
- return defaults;
6940
- }
6941
- function evaluatorTypeHasConfigField(typeId, fieldKey) {
6942
- return getEvaluatorTypeDefinition(typeId)?.configFields.some((field) => field.key === fieldKey) ?? false;
6943
- }
6944
- function evaluatorCanUseSharedExpectedOutput(typeId) {
6945
- return getEvaluatorTypeDefinition(typeId)?.criteriaFields.some((field) => field.key === "expectedOutput" && field.type === "object") ?? false;
6946
- }
6947
- // src/services/flow-eval-utils.ts
6948
- function isRecord(value) {
6949
- return typeof value === "object" && value !== null && !Array.isArray(value);
6950
- }
6951
- var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
6952
- function isUUID(value) {
6953
- return UUID_RE.test(value);
6954
- }
6955
- function stripJsonExt(name) {
6956
- return name.endsWith(".json") ? name.slice(0, -".json".length) : name;
6957
- }
6958
- function slugify(text) {
6959
- const slug = text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
6960
- return slug || "untitled";
6961
- }
6962
- function getEvaluatorRef(evaluator) {
6963
- return stripJsonExt(evaluator.fileName ?? `${evaluator.id}.json`);
6964
- }
6965
- function buildEvaluatorConfig(typeId, options) {
6966
- const evaluatorConfig = {
6967
- name: options.name,
6968
- ...getDefaultConfigForEvaluatorType(typeId)
6969
- };
6970
- if (evaluatorTypeHasConfigField(typeId, "targetOutputKey")) {
6971
- evaluatorConfig.targetOutputKey = options.targetOutputKey ?? "*";
6972
- }
6973
- if (options.model !== undefined) {
6974
- evaluatorConfig.model = options.model;
6975
- }
6976
- if (options.prompt !== undefined) {
6977
- evaluatorConfig.prompt = options.prompt;
6978
- }
6979
- return evaluatorConfig;
6980
- }
6981
- function buildDefaultCriteria(evaluators, expectedOutput, searchText) {
6982
- const criterias = {};
6983
- for (const evaluator of evaluators) {
6984
- const key = evaluator.id;
6985
- if (expectedOutput !== undefined && evaluatorCanUseSharedExpectedOutput(evaluator.evaluatorTypeId)) {
6986
- criterias[key] = { expectedOutput };
6987
- } else if (searchText !== undefined && evaluator.evaluatorTypeId === "uipath-contains") {
6988
- criterias[key] = { searchText };
6989
- } else {
6990
- const defaultCriteria = evaluator.evaluatorConfig.defaultEvaluationCriteria;
6991
- criterias[key] = isRecord(defaultCriteria) ? defaultCriteria : null;
6992
- }
6993
- }
6994
- return criterias;
6995
- }
6996
-
6997
- // src/services/flow-migration-check.ts
6998
- if (!instance.isInitialized) {
6999
- instance.init({
7000
- lng: "en",
7001
- fallbackLng: "en",
7002
- defaultNS: "validation",
7003
- resources: {},
7004
- interpolation: { escapeValue: false }
7005
- });
7006
- }
7007
- registerFlowMigrationsI18n(instance);
7008
- function captureMigrationIssues() {
7009
- const paths = [];
7010
- const tracker = {
7011
- trackError: (_error, _severity, details) => {
7012
- if (!("issues" in details))
7013
- return;
7014
- const issues = details.issues;
7015
- if (!Array.isArray(issues))
7016
- return;
7017
- for (const issue of issues) {
7018
- if (!issue || typeof issue !== "object")
7019
- continue;
7020
- if (!("path" in issue))
7021
- continue;
7022
- const path = issue.path;
7023
- if (Array.isArray(path) && path.length > 0) {
7024
- paths.push(path.map(String).join("."));
7025
- }
7026
- }
7027
- }
7028
- };
7029
- return { tracker, fieldPaths: () => [...new Set(paths)] };
7030
- }
7031
- function formatMigrationFailureMessage(step, rawMessage, fieldPaths) {
7032
- const parts = [`Workflow migration failed at ${step}: ${rawMessage}.`];
7033
- if (fieldPaths.length > 0) {
7034
- const shown = fieldPaths.slice(0, 10);
7035
- const extra = fieldPaths.length > shown.length ? `, +${fieldPaths.length - shown.length} more` : "";
7036
- parts.push(`Offending field(s): ${shown.join(", ")}${extra}.`);
7037
- }
7038
- parts.push("Fix the flagged field(s) or re-scaffold the affected node, then re-run.");
7039
- return parts.join(" ");
7040
- }
7041
- function checkForwardMigration(rawWorkflow) {
7042
- try {
7043
- getMigrationChain(runtimeMigrations, String(rawWorkflow.version ?? ""), runtimeVersion);
7044
- } catch {
7045
- return { ok: true };
7046
- }
7047
- const { tracker, fieldPaths } = captureMigrationIssues();
7048
- const result = migrateWorkflowToFloor(runtimeMigrations, rawWorkflow, runtimeVersion, minimumSupportedVersion, tracker);
7049
- if (!result.error)
7050
- return { ok: true };
7051
- const paths = fieldPaths();
7052
- return {
7053
- ok: false,
7054
- step: result.error.step,
7055
- rawMessage: result.error.message,
7056
- message: formatMigrationFailureMessage(result.error.step, result.error.message, paths),
7057
- fieldPaths: paths
7058
- };
7059
- }
7060
-
7061
- // src/services/flow-eval-file-store.ts
7062
- async function ensureDirectory(fs, path) {
7063
- if (await fs.exists(path)) {
7064
- return;
7065
- }
7066
- const parent = fs.path.dirname(path);
7067
- if (parent && parent !== path && !await fs.exists(parent)) {
7068
- await ensureDirectory(fs, parent);
7069
- }
7070
- const [error] = await catchError(fs.mkdir(path));
7071
- if (error && !await fs.exists(path)) {
7072
- throw error;
7073
- }
7074
- }
7075
-
7076
- class FlowEvalFileStore {
7077
- fs;
7078
- constructor(fs) {
7079
- this.fs = fs;
7080
- }
7081
- async readJsonFiles(dir) {
7082
- const [readDirError, files] = await catchError(this.fs.readdir(dir));
7083
- if (readDirError) {
7084
- return [];
7085
- }
7086
- const items = [];
7087
- for (const file of files) {
7088
- if (!file.endsWith(".json")) {
7089
- continue;
7090
- }
7091
- const filePath = this.fs.path.join(dir, file);
7092
- const [readError, raw] = await catchError(this.fs.readFile(filePath, "utf-8"));
7093
- if (readError) {
7094
- throw new Error(`Failed to read JSON file "${filePath}": ${readError.message}`);
7095
- }
7096
- if (raw === null) {
7097
- continue;
7098
- }
7099
- const [parseError, data2] = catchError(() => JSON.parse(String(raw)));
7100
- if (parseError) {
7101
- throw new Error(`Invalid JSON in "${filePath}": ${parseError.message}`);
7102
- }
7103
- data2.fileName = file;
7104
- items.push(data2);
7105
- }
7106
- return items;
7107
- }
7108
- async writeJsonFile(path, value) {
7109
- await ensureDirectory(this.fs, this.fs.path.dirname(path));
7110
- await this.fs.writeFile(path, `${JSON.stringify(value, null, 2)}
7111
- `);
7112
- }
7113
- async remove(path) {
7114
- await this.fs.rm(path);
7115
- }
7116
- }
7117
-
7118
- // src/services/packaging-utils.ts
7119
- function fileNodesToPackagingNodes(nodes) {
7120
- return nodes.map((node) => ({
7121
- id: node.id,
7122
- type: node.type,
7123
- typeVersion: node.typeVersion ?? "1.0",
7124
- display: node.display,
7125
- inputs: node.inputs,
7126
- outputs: node.outputs,
7127
- ...node.model ? { model: node.model } : {}
7128
- }));
7129
- }
7130
- function isRecord2(value) {
7131
- return typeof value === "object" && value !== null && !Array.isArray(value);
7132
- }
7133
- function toResourceList(value) {
7134
- if (!Array.isArray(value))
7135
- return;
7136
- const resources = value.filter(isRecord2);
7137
- return resources.length === value.length ? resources : undefined;
7138
- }
7139
- function normalizePackagingBindingsJson(value) {
7140
- if (!isRecord2(value))
7141
- return;
7142
- const resources = toResourceList(value.resources);
7143
- if (!resources)
7144
- return;
7145
- return {
7146
- ...value,
7147
- version: typeof value.version === "string" ? value.version : "2.0",
7148
- resources
7149
- };
7150
- }
7151
- function emptyPackagingBindingsJson() {
7152
- return { version: "2.0", resources: [] };
7153
- }
7154
- function mergePackagingBindingsJson(bindingsJsons) {
7155
- const first = bindingsJsons.find((bindingsJson) => bindingsJson !== undefined);
7156
- return {
7157
- ...first ?? emptyPackagingBindingsJson(),
7158
- resources: mergeBindingResources(bindingsJsons.flatMap((bindingsJson) => bindingsJson?.resources ?? []))
7159
- };
7160
- }
7161
- var inlineAgentPackagerLogger = {
7162
- debug: (message) => logger.debug(message),
7163
- info: (message) => logger.info(message),
7164
- warn: (message) => logger.warn(message),
7165
- error: (message) => logger.error(message),
7166
- progress: (message) => logger.info(message),
7167
- log: (message, level) => {
7168
- if (level === "Error" /* Error */)
7169
- logger.error(message);
7170
- else if (level === "Warning" /* Warn */)
7171
- logger.warn(message);
7172
- else if (level === "Debug" /* Debug */)
7173
- logger.debug(message);
7174
- else
7175
- logger.info(message);
7176
- },
7177
- logMessage: (message) => inlineAgentPackagerLogger.log(message.message, message.logLevel)
7178
- };
7179
- async function createInlineAgentContract(fs, agentDir) {
7180
- const outputPath = fs.path.join(fs.env.tmpdir(), `.inline-agent-contract-${crypto.randomUUID()}`);
7181
- await fs.mkdir(outputPath);
7182
- try {
7183
- const built = await buildInlineAgentContract({
7184
- fileSystem: fs,
7185
- logger: inlineAgentPackagerLogger,
7186
- projectPath: agentDir,
7187
- outputPath
7188
- });
7189
- const bindingsJson = normalizePackagingBindingsJson(built.bindingsJson);
7190
- if (!bindingsJson) {
7191
- throw new Error("Agent packager returned an invalid binding contract");
7192
- }
7193
- return { agentJson: built.agentJson, bindingsJson };
7194
- } finally {
7195
- const [cleanupError] = await catchError(fs.rm(outputPath, { recursive: true }));
7196
- if (cleanupError) {
7197
- logger.debug(`Could not remove inline-agent contract directory ${outputPath}: ${cleanupError.message}`);
7198
- }
7199
- }
7200
- }
7201
- async function inlineAgentExists(fs, projectDir, source) {
7202
- const agentJsonPath = fs.path.join(projectDir, source, "agent.json");
7203
- return fs.exists(agentJsonPath);
7204
- }
7205
- async function packageInlineAgents(fs, projectDir, nodes) {
7206
- const result = [];
7207
- for (const node of nodes) {
7208
- if (!isInlineAgentNodeType(node.type))
7209
- continue;
7210
- const source = readInlineAgentSource(node);
7211
- if (!source)
7212
- continue;
7213
- if (/[/\\.]/.test(source))
7214
- continue;
7215
- if (!await inlineAgentExists(fs, projectDir, source))
7216
- continue;
7217
- const contract = await createInlineAgentContract(fs, fs.path.join(projectDir, source));
7218
- const inputSchema = contract.agentJson.inputSchema ?? {
7219
- type: "object",
7220
- properties: {}
7221
- };
7222
- const outputSchema = contract.agentJson.outputSchema ?? {
7223
- type: "object",
7224
- properties: {}
7225
- };
7226
- result.push({
7227
- source,
7228
- entryPoint: {
7229
- filePath: `content/${source}/agent.json`,
7230
- uniqueId: contract.agentJson.projectId ?? source,
7231
- type: EntryPointType.Agent,
7232
- input: inputSchema,
7233
- output: outputSchema,
7234
- displayName: contract.agentJson.name ?? "Agent"
7235
- },
7236
- agentJson: contract.agentJson,
7237
- bindingsJson: contract.bindingsJson
7238
- });
7239
- logger.info(`Packaged inline agent "${source}" for entry-points`);
7240
- }
7241
- return result;
7242
- }
7243
- async function stageInlineAgentPackageFiles(fs, sourceProjectPath, stagingProjectDir, inlineAgents, formatLogMessage) {
7244
- for (const agent of inlineAgents) {
7245
- const srcDir = fs.path.join(sourceProjectPath, agent.source);
7246
- const destDir = fs.path.join(stagingProjectDir, agent.source);
7247
- if (fs.path.resolve(srcDir) !== fs.path.resolve(destDir) && await fs.exists(srcDir)) {
7248
- await fs.copyDirectory(srcDir, destDir);
7249
- }
7250
- const agentBuilderDir = fs.path.join(destDir, ".agent-builder");
7251
- await ensureDirectory(fs, agentBuilderDir);
7252
- await fs.writeFile(fs.path.join(agentBuilderDir, "agent.json"), JSON.stringify({
7253
- ...agent.agentJson,
7254
- resources: agent.agentJson.resources ?? [],
7255
- features: agent.agentJson.features ?? []
7256
- }, null, 2));
7257
- await fs.writeFile(fs.path.join(agentBuilderDir, "bindings.json"), `${JSON.stringify(agent.bindingsJson ?? emptyPackagingBindingsJson(), null, 2)}
7258
- `);
7259
- logger.info(formatLogMessage(agent.source));
7260
- }
7261
- }
7262
- function buildInlineAgentDescriptors(nodes) {
7263
- const out = [];
7264
- for (const node of nodes) {
7265
- if (!isInlineAgentNodeType(node.type))
7266
- continue;
7267
- const source = readInlineAgentSource(node);
7268
- if (!source)
7269
- continue;
7270
- const label = node.display?.label ?? "Agent";
7271
- out.push({
7272
- name: label,
7273
- agentProjectId: source,
7274
- isConversational: isConversationalOrVoiceAgentNodeType(node.type),
7275
- entryPointPath: `${source}/agent.json`
7276
- });
7277
- }
7278
- return out;
7279
- }
7280
- async function writePackagingArtifacts(fs, projectDir, projectId, packagingNodes, bindings, variables, bpmnFileName, startEventId, flowFileName, definitions = [], options = {}) {
7281
- const { entryPoints } = await writePackagingArtifactsDetailed(fs, projectDir, projectId, packagingNodes, bindings, variables, bpmnFileName, startEventId, flowFileName, definitions, options);
7282
- return entryPoints;
7283
- }
7284
- async function writePackagingArtifactsDetailed(fs, projectDir, projectId, packagingNodes, bindings, variables, bpmnFileName, startEventId, flowFileName, definitions = [], options = {}) {
7285
- const flowEntryPoints = getEntryPoints(bpmnFileName, packagingNodes, variables, definitions, ProjectType.Flow);
7286
- const entryPoints = [
7287
- ...flowEntryPoints,
7288
- ...options.additionalEntryPoints ?? []
7289
- ];
7290
- await fs.writeFile(fs.path.join(projectDir, "entry-points.json"), `${JSON.stringify(generateEntryPointsJson(entryPoints), null, 2)}
7291
- `);
7292
- const bindingResources = getBindingResources(packagingNodes, bindings, definitions);
7293
- const bindingsJson = normalizePackagingBindingsJson(generateBindingsJson(bindingResources)) ?? emptyPackagingBindingsJson();
7294
- const stagedBindingsJson = mergePackagingBindingsJson([
7295
- bindingsJson,
7296
- ...options.additionalBindingsJsons ?? []
7297
- ]);
7298
- await fs.writeFile(fs.path.join(projectDir, "bindings_v2.json"), `${JSON.stringify(stagedBindingsJson, null, 2)}
7299
- `);
7300
- const mainEntryPoint = `/${bpmnFileName}#${startEventId}`;
7301
- const operateJson = generateOperateJson(projectId, mainEntryPoint, operateRuntimeOptions(packagingNodes));
7302
- await fs.writeFile(fs.path.join(projectDir, "operate.json"), `${JSON.stringify(operateJson, null, 2)}
7303
- `);
7304
- const packageDescriptorJson = options.packageDescriptorJson ?? {
7305
- $schema: "https://cloud.uipath.com/draft/2024-12/package-descriptor",
7306
- files: {
7307
- "operate.json": "operate.json",
7308
- "entry-points.json": "entry-points.json",
7309
- "bindings.json": "bindings_v2.json",
7310
- [bpmnFileName]: bpmnFileName,
7311
- ...flowFileName ? { [flowFileName]: flowFileName } : {}
6397
+ if (obj && typeof obj === "object") {
6398
+ for (const [key, value] of Object.entries(obj)) {
6399
+ scanForInvalidJsExpressions(value, `${path}.${key}`, severity, issues);
7312
6400
  }
7313
- };
7314
- await fs.writeFile(fs.path.join(projectDir, "package-descriptor.json"), `${JSON.stringify(packageDescriptorJson, null, 2)}
7315
- `);
7316
- return { entryPoints, bindingsJson: stagedBindingsJson };
6401
+ }
7317
6402
  }
7318
- function backfillNodeModelsFromDefinitions(nodes, definitions) {
7319
- if (definitions.length === 0)
7320
- return nodes;
7321
- const definitionByType = new Map;
7322
- for (const def of definitions) {
7323
- if (def?.nodeType)
7324
- definitionByType.set(def.nodeType, def);
7325
- }
7326
- return nodes.map((n) => {
7327
- if (n.model)
7328
- return n;
7329
- const def = definitionByType.get(n.type);
7330
- if (!def?.model)
7331
- return n;
7332
- return { ...n, model: def.model };
6403
+ function reportInvalidExpression(expression, path, severity, issues) {
6404
+ if (expression.trim() === "")
6405
+ return;
6406
+ const error = syntaxErrorFrom(() => parse3(`(${expression}
6407
+ )`, {
6408
+ ecmaVersion: 2020,
6409
+ sourceType: "script"
6410
+ }));
6411
+ if (!error)
6412
+ return;
6413
+ issues.push({
6414
+ path,
6415
+ severity,
6416
+ message: `Expression at this field is not valid JavaScript: ${error.message}. Fix the syntax — validate cannot otherwise catch JavaScript expression errors; they surface only at flow debug.`
7333
6417
  });
7334
6418
  }
7335
- async function regenerateBindingsFile(fs, flowFilePath) {
7336
- const absolutePath = fs.path.resolve(flowFilePath);
7337
- const projectDir = fs.path.dirname(absolutePath);
7338
- const content = await fs.readFile(absolutePath, "utf-8");
7339
- if (!content) {
7340
- throw new Error(`Could not read .flow file at ${absolutePath}`);
7341
- }
7342
- const [parseErr, flowData] = catchError(() => JSON.parse(content));
7343
- if (parseErr) {
7344
- throw new Error(`Failed to parse .flow file at ${absolutePath}: ${parseErr.message}`);
7345
- }
7346
- const packagingNodes = backfillNodeModelsFromDefinitions(fileNodesToPackagingNodes(flowData.nodes ?? []), flowData.definitions ?? []);
7347
- const bindingResources = getBindingResources(packagingNodes, flowData.bindings ?? [], flowData.definitions ?? []);
7348
- await fs.writeFile(fs.path.join(projectDir, "bindings_v2.json"), `${JSON.stringify(generateBindingsJson(bindingResources), null, 2)}
7349
- `);
7350
- }
7351
-
7352
- // src/services/node-service.ts
7353
- class NodeTypeNotFoundError extends Error {
7354
- code = "NodeTypeNotFound";
7355
- instructions;
7356
- constructor(message, instructions) {
7357
- super(message);
7358
- this.name = "NodeTypeNotFoundError";
7359
- this.instructions = instructions;
7360
- }
7361
- }
7362
-
7363
- class NodeTypeNotEnabledError extends Error {
7364
- code = "NodeTypeNotEnabled";
7365
- instructions;
7366
- constructor(message, instructions) {
7367
- super(message);
7368
- this.name = "NodeTypeNotEnabledError";
7369
- this.instructions = instructions;
6419
+ function syntaxErrorFrom(parseSource) {
6420
+ try {
6421
+ parseSource();
6422
+ return;
6423
+ } catch (err) {
6424
+ return err instanceof Error ? err : new Error(String(err));
7370
6425
  }
7371
6426
  }
7372
6427
 
7373
- class SourceRequiredError extends Error {
7374
- code = "SourceRequired";
7375
- instructions;
7376
- constructor(message, instructions) {
7377
- super(message);
7378
- this.name = "SourceRequiredError";
7379
- this.instructions = instructions;
6428
+ // src/services/node-validators/model-source-validator.ts
6429
+ var modelSourceValidator = {
6430
+ id: "model-source",
6431
+ appliesTo: () => true,
6432
+ validate: (node, context) => {
6433
+ const definition = context.definitions.find((d) => d.nodeType === node.type);
6434
+ if (!definition)
6435
+ return [];
6436
+ const requiresModelSource = readModelSourceFlag(definition);
6437
+ if (!requiresModelSource)
6438
+ return [];
6439
+ const legacySource = readLegacyModelSource(node);
6440
+ if (legacySource !== undefined) {
6441
+ return [
6442
+ {
6443
+ path: `nodes[${node.id}].model.source`,
6444
+ severity: "error",
6445
+ message: `Node type "${node.type}" carries the deprecated ` + `"model.source" UUID on the node instance. ` + `flow-core 0.2.50+ requires the canvas-generated ` + `UUID at "inputs.source"; remove "model.source" ` + `from the node and place the value under ` + `"inputs": { "source": "<uuid>" } instead. ` + `See uipath-maestro-flow skill — ` + `inline-agent/impl.md (MST-9265).`
6446
+ }
6447
+ ];
6448
+ }
6449
+ const inputsSource = node.inputs?.source;
6450
+ if (typeof inputsSource === "string" && inputsSource.length > 0) {
6451
+ return [];
6452
+ }
6453
+ return [
6454
+ {
6455
+ path: `nodes[${node.id}].inputs.source`,
6456
+ severity: "error",
6457
+ message: `Node type "${node.type}" requires a stable UUID at ` + `"inputs.source" — the agent's ProjectId for inline ` + `agent nodes, or the resource id from the parent inline ` + `agent's "resources[]" for agent-tool resource nodes. ` + `Set "inputs": { "source": "<uuid>" } on the node ` + `(use the ProjectId returned by ` + `"uip agent init --inline-in-flow" for inline agents). ` + `See uipath-maestro-flow skill — inline-agent/impl.md ` + `(MST-9265).`
6458
+ }
6459
+ ];
7380
6460
  }
7381
- }
7382
- var listNodesInFlow = async (filePath) => {
7383
- const { workflow } = await readFlowWorkflow(filePath);
7384
- const nodes = workflow.nodes.map((n) => ({
7385
- id: n.id,
7386
- type: n.type,
7387
- label: n.display.label ?? "",
7388
- position: n.ui.position
7389
- }));
7390
- return { nodes, count: nodes.length };
7391
6461
  };
7392
- var PROCESS_NODE_PREFIXES = [
7393
- "uipath.core.rpa-workflow.",
7394
- "uipath.agent.resource.tool.process.",
7395
- "uipath.core.agent.",
7396
- "uipath.core.api-workflow."
7397
- ];
7398
- function isProcessNode(manifest) {
7399
- return PROCESS_NODE_PREFIXES.some((prefix) => manifest.nodeType?.startsWith(prefix));
7400
- }
7401
- function extractProcessGuid(nodeType) {
7402
- const match = nodeType.match(/^(?:uipath\.core\.rpa-workflow|uipath\.agent\.resource\.tool\.process|uipath\.core\.agent|uipath\.core\.api-workflow)\.([0-9a-f-]+)$/i);
7403
- if (!match) {
7404
- throw new Error(`Invalid process node type: "${nodeType}". ` + "Expected a known prefix followed by a process GUID.");
7405
- }
7406
- return match[1];
7407
- }
7408
- function resolveProcessTarget(node, definitions) {
7409
- if (!isProcessNode({ nodeType: node.type }))
7410
- return;
7411
- let subType = "Process";
7412
- if (definitions) {
7413
- const sameType = definitions.filter((d) => d.nodeType === node.type);
7414
- const def = sameType.find((d) => node.typeVersion !== undefined && d.version === node.typeVersion) ?? sameType[0];
7415
- const model = def?.model;
7416
- const defBindings = model?.bindings;
7417
- if (defBindings?.resourceSubType)
7418
- subType = defBindings.resourceSubType;
7419
- if (defBindings?.resourceKey) {
7420
- return { key: defBindings.resourceKey, subType };
7421
- }
7422
- }
7423
- return { key: extractProcessGuid(node.type), subType };
7424
- }
7425
- function resolveProcessTargetKey(node, definitions) {
7426
- return resolveProcessTarget(node, definitions)?.key;
7427
- }
7428
- function createProcessBindings(manifest) {
7429
- const processGuid = extractProcessGuid(manifest.nodeType);
7430
- const model = manifest.model;
7431
- const rawValues = model?.bindings?.values;
7432
- let processName;
7433
- let folderPath;
7434
- if (Array.isArray(rawValues)) {
7435
- processName = rawValues.find((v) => v.propertyAttribute === "name")?.default ?? "";
7436
- folderPath = rawValues.find((v) => v.propertyAttribute === "folderPath")?.default;
7437
- } else {
7438
- processName = rawValues?.name ?? "";
7439
- folderPath = rawValues?.folderPath;
7440
- }
7441
- if (folderPath == null) {
7442
- throw new Error("Manifest is missing model.bindings.values.folderPath. " + "Cannot create process bindings without a folder path.");
7443
- }
7444
- const subType = model?.bindings?.resourceSubType ?? "Process";
7445
- const resourceKey = model?.bindings?.resourceKey ?? processGuid;
7446
- const nameBinding = createBinding({
7447
- name: "name",
7448
- value: processName,
7449
- resource: "process",
7450
- resourceKey,
7451
- propertyAttribute: "name",
7452
- resourceSubType: subType
7453
- });
7454
- const folderBinding = createBinding({
7455
- name: "folderPath",
7456
- value: folderPath,
7457
- resource: "process",
7458
- resourceKey,
7459
- propertyAttribute: "folderPath",
7460
- resourceSubType: subType
7461
- });
7462
- if (folderPath === "" && folderBinding.default === undefined) {
7463
- folderBinding.default = "";
6462
+ function readModelSourceFlag(definition) {
6463
+ const model = definition.model;
6464
+ if (!model || typeof model !== "object" || Array.isArray(model)) {
6465
+ return false;
7464
6466
  }
7465
- return { nameBinding, folderBinding };
6467
+ const source = model.source;
6468
+ return source === true;
7466
6469
  }
7467
- function resolveProcessBindingsInContext(node, nameBinding, folderBinding) {
6470
+ function readLegacyModelSource(node) {
7468
6471
  const model = node.model;
7469
- if (!model?.context)
6472
+ if (!model || typeof model !== "object" || Array.isArray(model)) {
7470
6473
  return;
7471
- for (const entry of model.context) {
7472
- if (entry.name === "name" && typeof entry.value === "string") {
7473
- entry.default = nameBinding.default;
7474
- entry.value = `=bindings.${nameBinding.id}`;
7475
- } else if (entry.name === "folderPath" && typeof entry.value === "string") {
7476
- entry.default = folderBinding.default;
7477
- entry.value = `=bindings.${folderBinding.id}`;
7478
- }
7479
6474
  }
6475
+ const source = model.source;
6476
+ if (typeof source === "string" && source.length > 0) {
6477
+ return source;
6478
+ }
6479
+ return;
7480
6480
  }
7481
- var UNRESOLVED_BINDING_PATTERN = /^<bindings\.\w+>$/;
7482
- function ensureProcessBindings(workflow) {
7483
- const nodes = workflow.nodes;
7484
- const definitions = workflow.definitions ?? [];
7485
- let bindingsCreated = 0;
7486
- for (const node of nodes) {
7487
- if (!isProcessNode({ nodeType: node.type }))
7488
- continue;
7489
- const nodeModel = node.model;
7490
- const defModel = definitions.find((d) => d.nodeType === node.type)?.model;
7491
- const hasUnresolved = [nodeModel, defModel].some((m) => m?.context?.some((entry) => typeof entry.value === "string" && UNRESOLVED_BINDING_PATTERN.test(entry.value)));
7492
- if (!hasUnresolved)
7493
- continue;
7494
- const definition = definitions.find((d) => d.nodeType === node.type);
7495
- if (!definition)
6481
+
6482
+ // src/services/node-validators/index.ts
6483
+ var defaultNodeValidators = [
6484
+ activityTypeIdValidator,
6485
+ ceqlQueryValidator,
6486
+ connectorNodeValidator,
6487
+ crossNodeBindingValidator,
6488
+ expressionPrefixValidator,
6489
+ jsExpressionSyntaxValidator,
6490
+ ixpNodeValidator,
6491
+ modelSourceValidator
6492
+ ];
6493
+
6494
+ // src/services/vars-reference-rule.ts
6495
+ var VARS_REF_RE = /\$vars((?:\s*\??\.\s*[A-Za-z_$][\w$]*|\s*\[\s*(?:'[^']*'|"[^"]*")\s*\])+)/g;
6496
+ var VARS_STEP_RE = /(\??\.)\s*([A-Za-z_$][\w$]*)|\[\s*(?:'([^']*)'|"([^"]*)")\s*\]/g;
6497
+ var JS_EXPRESSION_PREFIX = "=js:";
6498
+ var ARRAY_MEMBERS = new Set([
6499
+ "length",
6500
+ "at",
6501
+ "concat",
6502
+ "copyWithin",
6503
+ "entries",
6504
+ "every",
6505
+ "fill",
6506
+ "filter",
6507
+ "find",
6508
+ "findIndex",
6509
+ "findLast",
6510
+ "findLastIndex",
6511
+ "flat",
6512
+ "flatMap",
6513
+ "forEach",
6514
+ "includes",
6515
+ "indexOf",
6516
+ "join",
6517
+ "keys",
6518
+ "lastIndexOf",
6519
+ "map",
6520
+ "pop",
6521
+ "push",
6522
+ "reduce",
6523
+ "reduceRight",
6524
+ "reverse",
6525
+ "shift",
6526
+ "slice",
6527
+ "some",
6528
+ "sort",
6529
+ "splice",
6530
+ "toLocaleString",
6531
+ "toReversed",
6532
+ "toSorted",
6533
+ "toSpliced",
6534
+ "toString",
6535
+ "unshift",
6536
+ "values",
6537
+ "with"
6538
+ ]);
6539
+ var LOOP_NODE_TYPE = "core.logic.loop";
6540
+ var LOOP_BACK_TARGET_PORT = "loopBack";
6541
+ var SCRIPT_NODE_TYPE = "core.action.script";
6542
+ var JS_EXPRESSION_TYPE = "jsExpression";
6543
+ function undefinedSafe(ref2, k) {
6544
+ return ref2.guarded.has(k + 1);
6545
+ }
6546
+ function stripJsComments(source) {
6547
+ let out = "";
6548
+ let i2 = 0;
6549
+ const n = source.length;
6550
+ while (i2 < n) {
6551
+ const c = source[i2];
6552
+ const next = source[i2 + 1];
6553
+ if (c === "/" && next === "/") {
6554
+ while (i2 < n && source[i2] !== `
6555
+ `)
6556
+ i2++;
7496
6557
  continue;
7497
- const [err, bindings] = catchError(() => createProcessBindings(definition));
7498
- if (err) {
7499
- logger.warn(`Skipping binding resolution for node "${node.id}": ${err.message}`);
6558
+ }
6559
+ if (c === "/" && next === "*") {
6560
+ const end = source.indexOf("*/", i2 + 2);
6561
+ i2 = end === -1 ? n : end + 2;
6562
+ out += " ";
7500
6563
  continue;
7501
6564
  }
7502
- const { nameBinding, folderBinding } = bindings;
7503
- const beforeCount = workflow.bindings?.length ?? 0;
7504
- addBinding(workflow, nameBinding);
7505
- addBinding(workflow, folderBinding);
7506
- const storedBindings = workflow.bindings;
7507
- const storedName = storedBindings.find((b) => b.resourceKey === nameBinding.resourceKey && b.propertyAttribute === nameBinding.propertyAttribute) ?? nameBinding;
7508
- const storedFolder = storedBindings.find((b) => b.resourceKey === folderBinding.resourceKey && b.propertyAttribute === folderBinding.propertyAttribute) ?? folderBinding;
7509
- resolveProcessBindingsInContext(node, storedName, storedFolder);
7510
- if (defModel?.context) {
7511
- for (const entry of defModel.context) {
7512
- if (entry.name === "name" && typeof entry.value === "string" && UNRESOLVED_BINDING_PATTERN.test(entry.value)) {
7513
- entry.default = storedName.default;
7514
- entry.value = `=bindings.${storedName.id}`;
7515
- } else if (entry.name === "folderPath" && typeof entry.value === "string" && UNRESOLVED_BINDING_PATTERN.test(entry.value)) {
7516
- entry.default = storedFolder.default;
7517
- entry.value = `=bindings.${storedFolder.id}`;
7518
- }
6565
+ if (c === "'" || c === '"' || c === "`") {
6566
+ let j = i2 + 1;
6567
+ while (j < n && source[j] !== c) {
6568
+ if (source[j] === "\\")
6569
+ j++;
6570
+ else if (c !== "`" && source[j] === `
6571
+ `)
6572
+ break;
6573
+ j++;
7519
6574
  }
6575
+ out += source.slice(i2, Math.min(j + 1, n));
6576
+ i2 = j + 1;
6577
+ continue;
7520
6578
  }
7521
- const added = (workflow.bindings?.length ?? 0) - beforeCount;
7522
- bindingsCreated += added;
7523
- logger.info(`Resolved process bindings for node "${node.id}" (${node.type})`);
7524
- }
7525
- if (bindingsCreated > 0) {
7526
- logger.info(`ensureProcessBindings: created ${bindingsCreated} binding(s) for directly-authored nodes`);
6579
+ out += c;
6580
+ i2++;
7527
6581
  }
7528
- return bindingsCreated;
6582
+ return out;
7529
6583
  }
7530
- var BINDING_REF_PATTERN = /^=bindings\.(.+)$/;
7531
- function collectNodeBindingRefs(node) {
7532
- const refs = new Set;
7533
- if (node.inputs) {
7534
- for (const value of Object.values(node.inputs)) {
7535
- if (typeof value === "string") {
7536
- const match = value.match(BINDING_REF_PATTERN);
7537
- if (match)
7538
- refs.add(match[1]);
7539
- }
6584
+ function isExpressionObject(v) {
6585
+ return typeof v === "object" && v !== null && !Array.isArray(v) && typeof v.expression === "string" && typeof v.type === "string";
6586
+ }
6587
+ function parseRefs(text) {
6588
+ const refs = [];
6589
+ for (const m of text.matchAll(VARS_REF_RE)) {
6590
+ const chain = m[1];
6591
+ const segments = [];
6592
+ const guarded = new Set;
6593
+ for (const step of chain.matchAll(VARS_STEP_RE)) {
6594
+ if (step[1] === "?.")
6595
+ guarded.add(segments.length);
6596
+ const key = step[2] ?? step[3] ?? step[4] ?? "";
6597
+ for (const part of key.split(".")) {
6598
+ if (part)
6599
+ segments.push(part);
6600
+ }
6601
+ }
6602
+ if (segments.length > 0) {
6603
+ refs.push({
6604
+ segments,
6605
+ text: `$vars${chain.replace(/\s+/g, "")}`,
6606
+ guarded
6607
+ });
7540
6608
  }
7541
6609
  }
7542
6610
  return refs;
7543
6611
  }
7544
- function collectNodeBindingResourceKeys(node, bindings, definitions) {
7545
- const keys = new Set;
7546
- const processKey = resolveProcessTargetKey(node, definitions);
7547
- if (processKey) {
7548
- keys.add(processKey);
7549
- }
7550
- const inputs = node.inputs;
7551
- if (typeof inputs?.detail?.connectionResourceId === "string") {
7552
- keys.add(inputs.detail.connectionResourceId);
7553
- }
7554
- const refs = collectNodeBindingRefs(node);
7555
- for (const binding of bindings) {
7556
- if (refs.has(binding.id)) {
7557
- keys.add(binding.resourceKey);
6612
+ function scanNodeFields(node, updates) {
6613
+ const out = [];
6614
+ const walk = (val, path, underAgentBinding) => {
6615
+ const isScriptBody = node.type === SCRIPT_NODE_TYPE && path === "inputs.script";
6616
+ if (typeof val === "string") {
6617
+ if (!val.includes("$vars"))
6618
+ return;
6619
+ out.push({
6620
+ fieldPath: path,
6621
+ isAgentBinding: underAgentBinding,
6622
+ isJs: isScriptBody || val.startsWith(JS_EXPRESSION_PREFIX),
6623
+ text: val
6624
+ });
6625
+ return;
6626
+ }
6627
+ if (isExpressionObject(val)) {
6628
+ if (!val.expression.includes("$vars"))
6629
+ return;
6630
+ out.push({
6631
+ fieldPath: `${path}.expression`,
6632
+ isAgentBinding: underAgentBinding,
6633
+ isJs: isScriptBody || val.type === JS_EXPRESSION_TYPE,
6634
+ text: val.expression
6635
+ });
6636
+ return;
6637
+ }
6638
+ if (Array.isArray(val)) {
6639
+ for (const [i2, v] of val.entries()) {
6640
+ walk(v, `${path}[${i2}]`, underAgentBinding);
6641
+ }
6642
+ return;
6643
+ }
6644
+ if (val && typeof val === "object") {
6645
+ for (const [k, v] of Object.entries(val)) {
6646
+ if (path === "inputs.detail" && k === "configuration")
6647
+ continue;
6648
+ walk(v, `${path}.${k}`, underAgentBinding || path === "inputs" && k === "agentInputVariables");
6649
+ }
6650
+ }
6651
+ };
6652
+ if (node.inputs)
6653
+ walk(node.inputs, "inputs", false);
6654
+ if (node.outputs)
6655
+ walk(node.outputs, "outputs", false);
6656
+ if (Array.isArray(updates)) {
6657
+ for (const [i2, u] of updates.entries()) {
6658
+ const expr = u?.expression;
6659
+ if (typeof expr === "string" || isExpressionObject(expr)) {
6660
+ walk(expr, `variableUpdates[${i2}]`, false);
6661
+ }
7558
6662
  }
7559
6663
  }
7560
- return keys;
7561
- }
7562
- var addNodeToFlow = async (filePath, nodeType, options = {}) => {
7563
- const [registryErr, registryManifest] = await catchError(getNode(nodeType));
7564
- let manifest = registryManifest ?? null;
7565
- if (registryErr) {
7566
- logger.debug(`Registry node lookup failed for ${nodeType}: ${registryErr.message}`);
7567
- }
7568
- let localErr = null;
7569
- if (!manifest) {
7570
- const [err, localManifest] = await catchError(getNode(nodeType, { local: true }));
7571
- manifest = localManifest ?? null;
7572
- if (err) {
7573
- localErr = err;
7574
- logger.warn(`In-solution node lookup failed for ${nodeType}: ${err.message}`);
7575
- }
7576
- }
7577
- if (!manifest) {
7578
- if (isKnownSdkNodeType(nodeType)) {
7579
- throw new NodeTypeNotEnabledError(`Node type '${nodeType}' is not enabled for this tenant.`, "Ask an admin to enable the feature flag for this node type, " + "or run `uip maestro flow registry list` to see every " + "known type with its `AvailableOnTenant` flag.");
7580
- }
7581
- const details = [
7582
- registryErr && `Registry lookup failed: ${registryErr.message}`,
7583
- localErr && `In-solution lookup failed: ${localErr.message}`
7584
- ].filter(Boolean).join(". ");
7585
- const hint = details || "If this is an in-solution node, make sure you are running " + "from inside a solution directory (with a .uipx file in CWD, parent, or grandparent).";
7586
- throw new NodeTypeNotFoundError(`Node type not found: ${nodeType}. ${hint}`, "Run `uip maestro flow registry search <keyword>` to find the " + "correct node type, or `uip maestro flow registry list` " + "to see every known type (including ones not enabled on this tenant).");
7587
- }
7588
- if (manifest.model?.source === true) {
7589
- const fromFlag = typeof options.source === "string" && options.source.length > 0;
7590
- const inputsSourceCandidate = options.inputs?.source;
7591
- const fromInputs = typeof inputsSourceCandidate === "string" && inputsSourceCandidate.length > 0;
7592
- if (!fromFlag && !fromInputs) {
7593
- throw new SourceRequiredError(`Node type "${nodeType}" requires a source UUID at inputs.source. Pass --source <uuid>.`, "Use the agent's ProjectId (returned by " + '`uip agent init "<flow-dir>" --inline-in-flow`) for inline ' + "agent nodes, or the resource id declared in the parent " + "inline agent's `resources[]` for agent-tool resource nodes. " + '`--input \'{"source":"<uuid>"}\'` is also accepted.');
7594
- }
7595
- }
7596
- const { workflow, refMap } = await readFlowWorkflow(filePath);
7597
- const existingIds = new Set(workflow.nodes.map((n) => n.id));
7598
- const existingDefCount = workflow.definitions.length;
7599
- const { id, displayName } = generateNodeIdAndName(options.label ?? manifest.display.label, existingIds);
7600
- const bindingsBefore = workflow.bindings?.length ?? 0;
7601
- const node = addNode(workflow, manifest, id, options.position ?? { x: 0, y: 0 }, options.label ?? displayName);
7602
- const schema = manifest.inputDefinition;
7603
- if (manifest.inputDefaults === undefined && schema?.type === "object") {
7604
- for (const schemaKey of Object.keys(schema)) {
7605
- delete node.inputs[schemaKey];
7606
- }
7607
- }
7608
- let bindingsCreated = 0;
7609
- if (isProcessNode(manifest)) {
7610
- const { nameBinding, folderBinding } = createProcessBindings(manifest);
7611
- addBinding(workflow, nameBinding);
7612
- addBinding(workflow, folderBinding);
7613
- const storedBindings = workflow.bindings;
7614
- const storedName = storedBindings.find((b) => b.resourceKey === nameBinding.resourceKey && b.propertyAttribute === nameBinding.propertyAttribute) ?? nameBinding;
7615
- const storedFolder = storedBindings.find((b) => b.resourceKey === folderBinding.resourceKey && b.propertyAttribute === folderBinding.propertyAttribute) ?? folderBinding;
7616
- if (folderBinding.default === "" && storedFolder.default === undefined) {
7617
- storedFolder.default = "";
7618
- }
7619
- resolveProcessBindingsInContext(node, storedName, storedFolder);
7620
- bindingsCreated = (workflow.bindings?.length ?? 0) - bindingsBefore;
7621
- }
7622
- if (options.inputs && Object.keys(options.inputs).length > 0) {
7623
- node.inputs = { ...node.inputs ?? {}, ...options.inputs };
7624
- }
7625
- const manifestModel = manifest.model;
7626
- if (manifestModel?.source === true) {
7627
- if (typeof options.source === "string" && options.source.length > 0) {
7628
- const inputs = node.inputs ?? {};
7629
- inputs.source = options.source;
7630
- node.inputs = inputs;
7631
- }
7632
- if (node.model) {
7633
- delete node.model;
7634
- }
7635
- }
7636
- if (typeof options.parent === "string" && options.parent.length > 0) {
7637
- const allNodes = workflow.nodes;
7638
- if (!allNodes.some((n) => n.id === options.parent)) {
7639
- throw new Error(`--parent value "${options.parent}" is not an existing node id in this flow. ` + "Run 'uip maestro flow node list <file>' to see valid ids.");
7640
- }
7641
- node.parentId = options.parent;
7642
- }
7643
- await writeFlowWorkflow(filePath, workflow, refMap);
7644
- if (isProcessNode(manifest)) {
7645
- const fs = getFileSystem();
7646
- const [regenErr] = await catchError(regenerateBindingsFile(fs, filePath));
7647
- if (regenErr) {
7648
- logger.warn(`Failed to regenerate bindings_v2.json after adding ${manifest.nodeType}: ${regenErr.message}`);
7649
- }
7650
- }
7651
- const definitionAdded = workflow.definitions.length > existingDefCount;
7652
- const variableCount = workflow.variables?.nodes?.length ?? 0;
7653
- if (isConnectorNode(manifest)) {
7654
- const connInfo = getConnectorInfo(manifest);
7655
- return {
7656
- node,
7657
- definitionAdded,
7658
- bindingsCreated,
7659
- variableCount,
7660
- connectorInfo: connInfo ?? undefined
7661
- };
7662
- } else {
7663
- return { node, definitionAdded, bindingsCreated, variableCount };
7664
- }
7665
- };
7666
- function removeConnectedEdges(workflow, nodeId) {
7667
- const edges = workflow.edges ?? [];
7668
- const before = edges.length;
7669
- workflow.edges = edges.filter((e) => e.sourceNodeId !== nodeId && e.targetNodeId !== nodeId);
7670
- return before - workflow.edges.length;
6664
+ return out;
7671
6665
  }
7672
- function removeOrphanedBindings(workflow, deletedNodeKeys, remainingNodes, bindings) {
7673
- if (deletedNodeKeys.size === 0 || bindings.length === 0)
7674
- return 0;
7675
- const defs = workflow.definitions ?? [];
7676
- const remainingKeys = new Set;
7677
- for (const node of remainingNodes) {
7678
- for (const key of collectNodeBindingResourceKeys(node, bindings, defs)) {
7679
- remainingKeys.add(key);
6666
+ function buildAncestors(flow) {
6667
+ const preds = new Map;
6668
+ for (const e of flow.edges) {
6669
+ const set = preds.get(e.targetNodeId) ?? new Set;
6670
+ set.add(e.sourceNodeId);
6671
+ preds.set(e.targetNodeId, set);
6672
+ }
6673
+ const result = new Map;
6674
+ for (const n of flow.nodes) {
6675
+ const seen = new Set;
6676
+ const stack = [...preds.get(n.id) ?? []];
6677
+ while (stack.length > 0) {
6678
+ const x = stack.pop();
6679
+ if (seen.has(x))
6680
+ continue;
6681
+ seen.add(x);
6682
+ for (const p of preds.get(x) ?? [])
6683
+ stack.push(p);
7680
6684
  }
6685
+ result.set(n.id, seen);
7681
6686
  }
7682
- const before = bindings.length;
7683
- workflow.bindings = bindings.filter((b) => !deletedNodeKeys.has(b.resourceKey) || remainingKeys.has(b.resourceKey));
7684
- return before - workflow.bindings.length;
7685
- }
7686
- function connectorConnectionBindingName(node, definitions) {
7687
- if (!node.type.startsWith("uipath.connector"))
7688
- return "";
7689
- const def = definitions.find((d) => d.nodeType === node.type);
7690
- const context = def?.model?.context;
7691
- const connectorKey = context?.find((c) => c.name === "connectorKey")?.value;
7692
- return typeof connectorKey === "string" && connectorKey.length > 0 ? `${connectorKey} connection` : "";
7693
- }
7694
- function removeOrphanedConnectorStub(workflow, deletedNode, remainingNodes, definitions) {
7695
- const stubName = connectorConnectionBindingName(deletedNode, definitions);
7696
- if (!stubName)
7697
- return 0;
7698
- const stillOwned = remainingNodes.some((n) => connectorConnectionBindingName(n, definitions) === stubName);
7699
- if (stillOwned)
7700
- return 0;
7701
- const bindings = workflow.bindings ?? [];
7702
- if (bindings.length === 0)
7703
- return 0;
7704
- const before = bindings.length;
7705
- workflow.bindings = bindings.filter((b) => !(b.resource?.toLowerCase() === "connection" && b.propertyAttribute === "ConnectionId" && !b.resourceKey && !b.default && b.name === stubName));
7706
- return before - workflow.bindings.length;
6687
+ return result;
7707
6688
  }
7708
- function removeOrphanedDefinitions(workflow, remainingNodes) {
7709
- const definitions = workflow.definitions ?? [];
7710
- const usedKeys = new Set(remainingNodes.map((n) => `${n.type}:${n.typeVersion}`));
7711
- const before = definitions.length;
7712
- workflow.definitions = definitions.filter((d) => usedKeys.has(`${d.nodeType}:${d.version}`));
7713
- return before - workflow.definitions.length;
6689
+ function buildMustRun(flow, modelTypeOf) {
6690
+ const nodesById = new Map(flow.nodes.map((n) => [n.id, n]));
6691
+ const incoming = new Map;
6692
+ for (const e of flow.edges) {
6693
+ if (e.targetPort === LOOP_BACK_TARGET_PORT && nodesById.get(e.targetNodeId)?.type === LOOP_NODE_TYPE) {
6694
+ continue;
6695
+ }
6696
+ const list2 = incoming.get(e.targetNodeId) ?? [];
6697
+ list2.push(e.sourceNodeId);
6698
+ incoming.set(e.targetNodeId, list2);
6699
+ }
6700
+ const memo = new Map;
6701
+ const visiting = new Set;
6702
+ const mustRun = (id) => {
6703
+ const hit = memo.get(id);
6704
+ if (hit)
6705
+ return hit;
6706
+ if (visiting.has(id))
6707
+ return new Set;
6708
+ visiting.add(id);
6709
+ const ins = incoming.get(id) ?? [];
6710
+ let acc = new Set;
6711
+ if (ins.length > 0) {
6712
+ const sets = ins.map((s) => new Set([...mustRun(s), s]));
6713
+ const node = nodesById.get(id);
6714
+ const isJoin = node !== undefined && (node.type === "core.logic.merge" || modelTypeOf(node) === "bpmn:ParallelGateway");
6715
+ if (isJoin) {
6716
+ for (const s of sets)
6717
+ for (const x of s)
6718
+ acc.add(x);
6719
+ } else {
6720
+ acc = new Set(sets[0]);
6721
+ for (const s of sets.slice(1)) {
6722
+ for (const x of [...acc])
6723
+ if (!s.has(x))
6724
+ acc.delete(x);
6725
+ }
6726
+ }
6727
+ }
6728
+ acc.add(id);
6729
+ visiting.delete(id);
6730
+ memo.set(id, acc);
6731
+ return acc;
6732
+ };
6733
+ return mustRun;
6734
+ }
6735
+ function declaredOutputs(node, definition) {
6736
+ const names = new Set;
6737
+ if (node.outputs && typeof node.outputs === "object") {
6738
+ for (const k of Object.keys(node.outputs))
6739
+ names.add(k);
6740
+ }
6741
+ const outDef = definition?.outputDefinition;
6742
+ if (outDef && typeof outDef === "object") {
6743
+ for (const k of Object.keys(outDef))
6744
+ names.add(k);
6745
+ }
6746
+ if (node.type === "core.subflow")
6747
+ names.add("output");
6748
+ const isListOutput = node.type.startsWith("uipath.connector.") && connectorOperation(node) === "list";
6749
+ const declaredType = (name) => {
6750
+ const entry = outDef?.[name];
6751
+ const t = entry?.type;
6752
+ return typeof t === "string" ? t : undefined;
6753
+ };
6754
+ const typeOf = (name) => name === "output" && isListOutput ? "array" : declaredType(name);
6755
+ const whyArray = (name) => declaredType(name) === "array" ? 'declared type "array"' : 'a list operation — inputMetadata.operation is "list", the response is the bare array of records';
6756
+ return { names, typeOf, whyArray };
7714
6757
  }
7715
- function removeVariableUpdates(workflow, nodeId) {
7716
- const variables = workflow.variables;
7717
- if (!variables?.variableUpdates)
7718
- return 0;
7719
- const updates = variables.variableUpdates[nodeId];
7720
- if (!updates)
7721
- return 0;
7722
- const count = updates.length;
7723
- delete variables.variableUpdates[nodeId];
7724
- return count;
6758
+ function connectorOperation(node) {
6759
+ const detail = node.inputs?.detail;
6760
+ const op = detail?.inputMetadata?.operation;
6761
+ return typeof op === "string" ? op.toLowerCase() : undefined;
6762
+ }
6763
+ function boundedEditDistance(a, b, max) {
6764
+ if (Math.abs(a.length - b.length) > max)
6765
+ return max + 1;
6766
+ let prev = Array.from({ length: b.length + 1 }, (_, j) => j);
6767
+ for (let i2 = 1;i2 <= a.length; i2++) {
6768
+ const cur = [i2];
6769
+ let rowMin = i2;
6770
+ for (let j = 1;j <= b.length; j++) {
6771
+ const cost = a[i2 - 1] === b[j - 1] ? 0 : 1;
6772
+ cur[j] = Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + cost);
6773
+ rowMin = Math.min(rowMin, cur[j]);
6774
+ }
6775
+ if (rowMin > max)
6776
+ return max + 1;
6777
+ prev = cur;
6778
+ }
6779
+ return prev[b.length];
6780
+ }
6781
+ var HINT_MAX_EDITS = 2;
6782
+ var HINT_MIN_PREFIX = 3;
6783
+ function nearestNodeId(root, ids) {
6784
+ const lower = root.toLowerCase();
6785
+ let best;
6786
+ let bestScore = Number.POSITIVE_INFINITY;
6787
+ for (const id of ids) {
6788
+ const l = id.toLowerCase();
6789
+ if (l === lower)
6790
+ return id;
6791
+ if (lower.length < HINT_MIN_PREFIX)
6792
+ continue;
6793
+ let score = boundedEditDistance(lower, l, HINT_MAX_EDITS);
6794
+ if (score > HINT_MAX_EDITS) {
6795
+ const [short, long] = lower.length <= l.length ? [lower, l] : [l, lower];
6796
+ const isPrefix = short.length >= HINT_MIN_PREFIX && short.length * 2 >= long.length && long.startsWith(short);
6797
+ if (!isPrefix)
6798
+ continue;
6799
+ score = HINT_MAX_EDITS + (long.length - short.length);
6800
+ }
6801
+ if (score < bestScore) {
6802
+ best = id;
6803
+ bestScore = score;
6804
+ }
6805
+ }
6806
+ return best;
7725
6807
  }
7726
- function removeNodeVariables(workflow, nodeId) {
7727
- const variables = workflow.variables;
7728
- if (!variables?.nodes)
7729
- return 0;
7730
- const before = variables.nodes.length;
7731
- variables.nodes = variables.nodes.filter((v) => v.binding.nodeId !== nodeId);
7732
- return before - variables.nodes.length;
6808
+ function labelOf(node) {
6809
+ return node.display?.label ?? node.id;
7733
6810
  }
7734
- var deleteNodeFromFlow = async (filePath, nodeId) => {
7735
- const { workflow, refMap } = await readFlowWorkflow(filePath);
7736
- const nodes = workflow.nodes;
7737
- const nodeIndex = nodes.findIndex((n) => n.id === nodeId);
7738
- if (nodeIndex === -1) {
7739
- const available = nodes.map((n) => n.id).join(", ") || "(none)";
7740
- throw new Error(`Node not found: "${nodeId}". Available node IDs: ${available}`);
7741
- }
7742
- const targetNode = nodes[nodeIndex];
7743
- const deletedWasProcessNode = isProcessNode({ nodeType: targetNode.type });
7744
- const deletedNode = {
7745
- id: targetNode.id,
7746
- type: targetNode.type,
7747
- label: targetNode.display.label ?? "",
7748
- position: targetNode.ui.position
7749
- };
7750
- const bindings = workflow.bindings ?? [];
7751
- const definitions = workflow.definitions ?? [];
7752
- const deletedNodeResourceKeys = collectNodeBindingResourceKeys(targetNode, bindings, definitions);
7753
- nodes.splice(nodeIndex, 1);
7754
- const edgesRemoved = removeConnectedEdges(workflow, nodeId);
7755
- const bindingsRemoved = removeOrphanedBindings(workflow, deletedNodeResourceKeys, nodes, bindings) + removeOrphanedConnectorStub(workflow, targetNode, nodes, definitions);
7756
- const definitionsRemoved = removeOrphanedDefinitions(workflow, nodes);
7757
- const variablesRemoved = removeNodeVariables(workflow, nodeId);
7758
- const variableUpdatesRemoved = removeVariableUpdates(workflow, nodeId);
7759
- await writeFlowWorkflow(filePath, workflow, refMap);
7760
- if (deletedWasProcessNode || bindingsRemoved > 0) {
7761
- const fs = getFileSystem();
7762
- const [regenErr] = await catchError(regenerateBindingsFile(fs, filePath));
7763
- if (regenErr) {
7764
- logger.warn(`Failed to regenerate bindings_v2.json after deleting ${targetNode.type}: ${regenErr.message}`);
7765
- }
6811
+ function arrayMemberIssue(args) {
6812
+ const { names, typeOf, whyArray } = declaredOutputs(args.producer, args.definition);
6813
+ if (!names.has(args.second) || typeOf(args.second) !== "array") {
6814
+ return;
6815
+ }
6816
+ if (/^\d+$/.test(args.third) || ARRAY_MEMBERS.has(args.third)) {
6817
+ return;
7766
6818
  }
6819
+ const { root, second, third } = args;
7767
6820
  return {
7768
- deletedNode,
7769
- edgesRemoved,
7770
- bindingsRemoved,
7771
- definitionsRemoved,
7772
- variablesRemoved,
7773
- variableUpdatesRemoved
6821
+ path: args.path,
6822
+ severity: args.undefinedSafe || args.embedded ? "warning" : args.severity,
6823
+ message: `"${args.reader}" reads "${args.refText}", but "$vars.${root}.${second}" is an array (${whyArray(second)}), so ".${third}" is undefined. ` + `Iterate it (a Loop's collection is "$vars.${root}.${second}" itself), index it ("[0].${third}"), or use an Array method.`
7774
6824
  };
7775
- };
6825
+ }
6826
+ function validateVarsReferences(flow, options = {}) {
6827
+ const issues = [];
6828
+ const nodesById = new Map(flow.nodes.map((n) => [n.id, n]));
6829
+ if (nodesById.size === 0)
6830
+ return issues;
6831
+ const knownRoots = new Set(options.extraKnownRoots ?? []);
6832
+ const variables = flow.variables;
6833
+ for (const g of variables?.globals ?? []) {
6834
+ if (typeof g?.id === "string")
6835
+ knownRoots.add(g.id);
6836
+ }
6837
+ const updatesByNode = variables?.variableUpdates ?? {};
6838
+ const defByKey = new Map;
6839
+ const defByType = new Map;
6840
+ for (const d of flow.definitions) {
6841
+ defByKey.set(`${d.nodeType}:${d.version}`, d);
6842
+ if (!defByType.has(d.nodeType))
6843
+ defByType.set(d.nodeType, d);
6844
+ }
6845
+ const definitionOf = (n) => (n.typeVersion ? defByKey.get(`${n.type}:${n.typeVersion}`) : undefined) ?? defByType.get(n.type);
6846
+ const modelTypeOf = (n) => typeof n.model?.type === "string" ? n.model.type : definitionOf(n)?.model?.type;
6847
+ const ancestors = buildAncestors(flow);
6848
+ const mustRun = buildMustRun(flow, modelTypeOf);
6849
+ for (const node of flow.nodes) {
6850
+ const reader = labelOf(node);
6851
+ const reported = new Set;
6852
+ for (const field of scanNodeFields(node, updatesByNode[node.id])) {
6853
+ const path = `nodes[${node.id}].${field.fieldPath}`;
6854
+ const severity = field.fieldPath.startsWith("inputs") ? "error" : "warning";
6855
+ const text = field.isJs ? stripJsComments(field.text) : field.text;
6856
+ const bareValue = text.replace(/^=(js:)?/, "").replace(/\s+/g, "");
6857
+ for (const ref2 of parseRefs(text)) {
6858
+ const embedded = bareValue !== ref2.text;
6859
+ const [root, second, third] = ref2.segments;
6860
+ const key = `${field.fieldPath}|${ref2.segments.join(".")}`;
6861
+ if (reported.has(key))
6862
+ continue;
6863
+ reported.add(key);
6864
+ if (root === node.id)
6865
+ continue;
6866
+ if (knownRoots.has(root))
6867
+ continue;
6868
+ const producer = nodesById.get(root);
6869
+ const anc = ancestors.get(node.id) ?? new Set;
6870
+ if (field.isAgentBinding) {
6871
+ if (producer && anc.size > 0 && anc.has(root)) {
6872
+ if (!mustRun(node.id).has(root)) {
6873
+ issues.push({
6874
+ path,
6875
+ severity: undefinedSafe(ref2, 0) ? "warning" : severity,
6876
+ message: `Agent "${reader}" input binds "${ref2.text}", but "${root}" runs only on some of the paths that reach "${node.id}" (it sits behind a Decision or Switch branch the agent does not depend on). ` + "On the other paths the input is undefined and the agent invocation faults ([400300] Error evaluating expression in activity inputs). " + "Bind a node that runs on every path to the agent, or compute the value on each branch before they rejoin."
6877
+ });
6878
+ } else if (second !== undefined && third !== undefined) {
6879
+ const issue = arrayMemberIssue({
6880
+ producer,
6881
+ definition: definitionOf(producer),
6882
+ root,
6883
+ second,
6884
+ third,
6885
+ reader,
6886
+ refText: ref2.text,
6887
+ path,
6888
+ undefinedSafe: undefinedSafe(ref2, 2),
6889
+ embedded,
6890
+ severity
6891
+ });
6892
+ if (issue)
6893
+ issues.push(issue);
6894
+ }
6895
+ }
6896
+ continue;
6897
+ }
6898
+ if (!producer) {
6899
+ const hint = nearestNodeId(root, nodesById.keys());
6900
+ issues.push({
6901
+ path,
6902
+ severity: undefinedSafe(ref2, 0) ? "warning" : severity,
6903
+ message: `"${reader}" reads "${ref2.text}", but no node or workflow variable named "${root}" exists in this flow` + (hint ? ` (did you mean node "${hint}"?)` : "") + ". At runtime the reference resolves to nothing — a Script reading it faults ([300501]), a Decision or Switch faults ([400302]), a Transform or connector input silently gets an empty value. Fix the id or declare the variable under variables.globals."
6904
+ });
6905
+ continue;
6906
+ }
6907
+ if (anc.size > 0 && !anc.has(root)) {
6908
+ const runsAfter = (ancestors.get(root) ?? new Set).has(node.id);
6909
+ const why = runsAfter ? `"${root}" runs AFTER "${node.id}" (it is downstream of it)` : `"${root}" is not on any path that reaches "${node.id}" (another branch, or not connected)`;
6910
+ issues.push({
6911
+ path,
6912
+ severity: undefinedSafe(ref2, 0) ? "warning" : severity,
6913
+ message: `"${reader}" reads "${ref2.text}", but ${why}, so "${root}" has not produced a value when this expression is evaluated ` + "(Decision/Switch: [400302]; Script: [300501]; agent or connector input: [400300]/empty value). " + `Reference a node that runs earlier on this path, or move "${node.id}" after "${root}".`
6914
+ });
6915
+ continue;
6916
+ }
6917
+ if (second !== undefined) {
6918
+ const { names } = declaredOutputs(producer, definitionOf(producer));
6919
+ const declaresOutputs = [...names].some((n) => n !== "error");
6920
+ if (declaresOutputs && !names.has(second)) {
6921
+ const available = [...names].sort((a, b) => a.localeCompare(b)).join(", ");
6922
+ issues.push({
6923
+ path,
6924
+ severity: undefinedSafe(ref2, 1) ? "warning" : severity,
6925
+ message: `"${reader}" reads "${ref2.text}", but node "${root}" has no output named "${second}" — its outputs are: ${available}. ` + `Read "$vars.${root}.<one of those>" (e.g. a Decision exposes "$vars.${root}.matchedCaseId", not ".output.matchedCaseId").`
6926
+ });
6927
+ continue;
6928
+ }
6929
+ if (third !== undefined) {
6930
+ const issue = arrayMemberIssue({
6931
+ producer,
6932
+ definition: definitionOf(producer),
6933
+ root,
6934
+ second,
6935
+ third,
6936
+ reader,
6937
+ refText: ref2.text,
6938
+ path,
6939
+ undefinedSafe: undefinedSafe(ref2, 2),
6940
+ embedded,
6941
+ severity
6942
+ });
6943
+ if (issue)
6944
+ issues.push(issue);
6945
+ }
6946
+ }
6947
+ }
6948
+ }
6949
+ }
6950
+ return issues;
6951
+ }
7776
6952
 
7777
6953
  // src/services/flow-validate-service.ts
7778
6954
  if (!instance.isInitialized) {
@@ -7947,19 +7123,7 @@ function validationErrorToIssue(error) {
7947
7123
  };
7948
7124
  }
7949
7125
  function buildValidationContext(flow) {
7950
- const nodes = flow.nodes.map((n) => ({
7951
- id: n.id,
7952
- type: n.type,
7953
- data: {
7954
- inputs: n.inputs ?? {},
7955
- outputs: n.outputs ?? {},
7956
- ...n.typeVersion !== undefined && { typeVersion: n.typeVersion },
7957
- ...n.display !== undefined && {
7958
- display: n.display,
7959
- label: n.display.label
7960
- }
7961
- }
7962
- }));
7126
+ const nodes = toSerializedNodes(flow.nodes);
7963
7127
  const edges = flow.edges.map((e) => ({
7964
7128
  id: e.id,
7965
7129
  source: e.sourceNodeId,
@@ -8026,6 +7190,7 @@ class FlowValidateService {
8026
7190
  validateCurrentManifests;
8027
7191
  currentManifestOverrides;
8028
7192
  strictBindings;
7193
+ strictExpressions;
8029
7194
  connectorCatalogOverride;
8030
7195
  currentManifestCache;
8031
7196
  connectorCatalogCache;
@@ -8041,6 +7206,7 @@ class FlowValidateService {
8041
7206
  this.validateCurrentManifests = options.validateCurrentManifests === true || options.currentManifests !== undefined;
8042
7207
  this.currentManifestOverrides = options.currentManifests;
8043
7208
  this.strictBindings = options.strictBindings === true;
7209
+ this.strictExpressions = options.strictExpressions === true;
8044
7210
  this.connectorCatalogOverride = options.connectorCatalog;
8045
7211
  }
8046
7212
  async execute(flowFilePath) {
@@ -8118,13 +7284,13 @@ ${warnings.map((i2) => ` - [${i2.path}] ${i2.message}`).join(`
8118
7284
  ]));
8119
7285
  }
8120
7286
  async validateFile(flowFilePath) {
8121
- const absolutePath = this.fs.path.resolve(flowFilePath);
7287
+ let absolutePath = this.fs.path.resolve(flowFilePath);
8122
7288
  if (!await this.fs.exists(absolutePath)) {
8123
7289
  throw new Error(`File not found: ${absolutePath}`);
8124
7290
  }
8125
7291
  const stats = await this.fs.stat(absolutePath);
8126
7292
  if (stats?.isDirectory()) {
8127
- throw new Error(`Expected a .flow file but got a directory: ${absolutePath}`);
7293
+ absolutePath = await resolveProjectFlowFile(absolutePath);
8128
7294
  }
8129
7295
  if (!absolutePath.endsWith(".flow")) {
8130
7296
  throw new Error(`Expected a .flow file but got: ${this.fs.path.basename(absolutePath)}`);
@@ -8176,6 +7342,7 @@ Validating: ${absolutePath}
8176
7342
  issues.push(...this.validateAgentInputScopeRefs(workflow, hydrationDiagnoses, ""));
8177
7343
  issues.push(...this.validateVoiceAgentSettings(workflow, hydrationDiagnoses, ""));
8178
7344
  issues.push(...await this.validateSolutionRegistrationAndLayout(absolutePath));
7345
+ issues.push(...await validateExpressions(workflow, "", this.strictExpressions));
8179
7346
  const subflows = workflow.subflows ?? {};
8180
7347
  for (const [subflowId, entry] of Object.entries(subflows)) {
8181
7348
  const subNodes = entry.nodes;
@@ -8189,7 +7356,7 @@ Validating: ${absolutePath}
8189
7356
  variables: entry.variables
8190
7357
  };
8191
7358
  const prefix = `subflows[${subflowId}].`;
8192
- issues.push(...this.validateGraph(subGraph, prefix, rawDefErrorHandling, currentManifests));
7359
+ issues.push(...this.validateGraph(subGraph, prefix, rawDefErrorHandling, currentManifests, (workflow.variables?.globals ?? []).map((g) => g.id).filter((id) => typeof id === "string")));
8193
7360
  issues.push(...this.validateGlobalVariableUniqueness(subGraph, prefix));
8194
7361
  issues.push(...this.validateGlobalTriggerBindings(subGraph, prefix));
8195
7362
  issues.push(...this.validateUnboundInputGlobals(subGraph, prefix));
@@ -8197,6 +7364,10 @@ Validating: ${absolutePath}
8197
7364
  issues.push(...this.validateAgentPromptInputRefs(subGraph, hydrationDiagnoses, prefix));
8198
7365
  issues.push(...this.validateAgentInputScopeRefs(subGraph, hydrationDiagnoses, prefix));
8199
7366
  issues.push(...this.rejectSubflowVoiceAgents(subGraph, prefix));
7367
+ issues.push(...await validateExpressions({
7368
+ ...subGraph,
7369
+ subflows
7370
+ }, prefix, this.strictExpressions));
8200
7371
  }
8201
7372
  this.enrichInlineAgentPromptIssues(issues, hydrationDiagnoses, flowDir);
8202
7373
  return {
@@ -8352,6 +7523,12 @@ Validating: ${absolutePath}
8352
7523
  const props = inputSchema.properties;
8353
7524
  if (props && typeof props === "object") {
8354
7525
  diag.declaredInputKeys = Object.keys(props);
7526
+ const leaves = collectAgentInputLeaves(inputSchema);
7527
+ diag.declaredInputLeaves = leaves;
7528
+ diag.declaredInputPaths = new Set([
7529
+ ...leaves.map((leaf) => leaf.path),
7530
+ ...diag.declaredInputKeys.map(canonicalAgentInputPath)
7531
+ ]);
8355
7532
  }
8356
7533
  }
8357
7534
  }
@@ -8397,9 +7574,10 @@ Validating: ${absolutePath}
8397
7574
  if (!byField)
8398
7575
  continue;
8399
7576
  const declared = new Set(diag.declaredInputKeys ?? []);
7577
+ const declaredPaths = diag.declaredInputPaths ?? new Set;
8400
7578
  const label = node.display?.label ?? node.id;
8401
7579
  for (const [field, vars] of Object.entries(byField)) {
8402
- issues.push(...this.buildPromptInputRefIssues(node, field, vars ?? [], declared, label, pathPrefix));
7580
+ issues.push(...this.buildPromptInputRefIssues(node, field, vars ?? [], declared, declaredPaths, label, pathPrefix));
8403
7581
  }
8404
7582
  }
8405
7583
  return issues;
@@ -8461,7 +7639,7 @@ Validating: ${absolutePath}
8461
7639
  }
8462
7640
  return issues;
8463
7641
  }
8464
- buildPromptInputRefIssues(node, field, vars, declared, label, pathPrefix) {
7642
+ buildPromptInputRefIssues(node, field, vars, declared, declaredPaths, label, pathPrefix) {
8465
7643
  const issues = [];
8466
7644
  const malformed = [];
8467
7645
  const undeclared = [];
@@ -8469,7 +7647,7 @@ Validating: ${absolutePath}
8469
7647
  const key = this.canonicalInputKey(raw);
8470
7648
  if (key === undefined) {
8471
7649
  malformed.push(raw);
8472
- } else if (!declared.has(key)) {
7650
+ } else if (!declared.has(key) && !declaredPaths.has(canonicalAgentInputPath(key))) {
8473
7651
  undeclared.push(key);
8474
7652
  }
8475
7653
  }
@@ -8539,8 +7717,8 @@ Validating: ${absolutePath}
8539
7717
  if (notUpstream.length > 0) {
8540
7718
  issues.push({
8541
7719
  path,
8542
- message: `Agent "${label}" reads ${notUpstream.join(", ")}, but no edge path leads from that node to "${node.id}", so it has not run when the agent does and its output is not written yet. Studio Web reports the same variable as not available in this scope. Wire the node upstream of the agent, or bind an input the agent can see.`,
8543
- severity: "warning"
7720
+ message: `Agent "${label}" reads ${notUpstream.join(", ")}, but no edge path leads from that node to "${node.id}", so it has not run when the agent does and its output is not written yet ([400300] Error evaluating expression in activity inputs). Studio Web reports the same variable as not available in this scope. Wire the node upstream of the agent, or bind an input the agent can see.`,
7721
+ severity: "error"
8544
7722
  });
8545
7723
  }
8546
7724
  const invalidFields = [];
@@ -8585,10 +7763,10 @@ Validating: ${absolutePath}
8585
7763
  }
8586
7764
  }
8587
7765
  };
8588
- for (const key of diag?.declaredInputKeys ?? []) {
8589
- const ref2 = decodeSchemaKeyNodeRef(key);
7766
+ for (const leaf of diag?.declaredInputLeaves ?? []) {
7767
+ const ref2 = decodeSchemaKeyNodeRef(leaf.flatKey);
8590
7768
  if (ref2) {
8591
- add(ref2.nodeId, ref2.field, `\`$vars.${key.split("__").join(".")}\` (agent.json input "${key}")`);
7769
+ add(ref2.nodeId, ref2.field, `\`$vars.${leaf.path}\` (agent.json input "${leaf.flatKey}")`);
8592
7770
  }
8593
7771
  }
8594
7772
  const bound = node.inputs?.agentInputVariables;
@@ -8648,11 +7826,13 @@ Validating: ${absolutePath}
8648
7826
  Hint: ${hint}`;
8649
7827
  }
8650
7828
  }
8651
- validateGraph(graph, pathPrefix, rawDefErrorHandling = new Map, currentManifests = new Map) {
7829
+ validateGraph(graph, pathPrefix, rawDefErrorHandling = new Map, currentManifests = new Map, parentVariableIds = []) {
8652
7830
  const issues = [];
8653
7831
  issues.push(...this.validateEdgeReferences(graph));
8654
7832
  issues.push(...this.validateNodeTypeDefinitions(graph));
8655
- issues.push(...this.validateUniqueIds(graph));
7833
+ issues.push(...this.validateUniqueIds(graph), ...this.validateExclusiveBranchJoins(graph), ...validateVarsReferences(graph, {
7834
+ extraKnownRoots: parentVariableIds
7835
+ }));
8656
7836
  issues.push(...this.validateEdgeHandles(graph, rawDefErrorHandling));
8657
7837
  issues.push(...this.validateEdgeHandlesAgainstCurrentManifests(graph, currentManifests));
8658
7838
  const ctx = buildValidationContext(graph);
@@ -8662,7 +7842,10 @@ Validating: ${absolutePath}
8662
7842
  if (this.availableModelNames) {
8663
7843
  ctx.availableModelNames = this.availableModelNames;
8664
7844
  }
8665
- const rules = pathPrefix ? cliRules.filter((r) => r.id !== "trigger-required") : cliRules;
7845
+ const dropped = new Set(["expression-ref"]);
7846
+ if (pathPrefix)
7847
+ dropped.add("trigger-required");
7848
+ const rules = cliRules.filter((r) => !dropped.has(r.id));
8666
7849
  const ruleErrors = runRules([
8667
7850
  ...rules,
8668
7851
  conditionExpressionRule,
@@ -8672,6 +7855,17 @@ Validating: ${absolutePath}
8672
7855
  issues.push(...this.runNodeValidators(graph));
8673
7856
  return pathPrefix ? issues.map((i2) => ({ ...i2, path: `${pathPrefix}${i2.path}` })) : issues;
8674
7857
  }
7858
+ validateExclusiveBranchJoins(flow) {
7859
+ const graph = indexJoinGraph(flow);
7860
+ const issues = [];
7861
+ for (const node of flow.nodes) {
7862
+ const finding = findUnsatisfiableJoin(node, graph);
7863
+ if (finding) {
7864
+ issues.push(describeUnsatisfiableJoin(node, finding, graph));
7865
+ }
7866
+ }
7867
+ return issues;
7868
+ }
8675
7869
  validateEdgeReferences(flow) {
8676
7870
  const issues = [];
8677
7871
  const nodeIds = new Set(flow.nodes.map((n) => n.id));
@@ -8703,6 +7897,9 @@ Validating: ${absolutePath}
8703
7897
  definedVersionsByType.set(d.nodeType, versions);
8704
7898
  }
8705
7899
  for (const node of flow.nodes) {
7900
+ if (UI_ONLY_NODE_TYPES.has(node.type)) {
7901
+ continue;
7902
+ }
8706
7903
  const key = `${node.type}:${node.typeVersion}`;
8707
7904
  if (!definedTypes.has(key)) {
8708
7905
  const sameTypeVersions = definedVersionsByType.get(node.type);
@@ -9177,6 +8374,13 @@ Validating: ${absolutePath}
9177
8374
  visible: buildErrorHandle().visible
9178
8375
  });
9179
8376
  }
8377
+ if (entry.source.size > 0 || entry.sourceTemplates.length > 0) {
8378
+ for (const outcomeHandleId of deriveOutcomeHandleIds(node)) {
8379
+ if (!entry.source.has(outcomeHandleId)) {
8380
+ entry.source.set(outcomeHandleId, {});
8381
+ }
8382
+ }
8383
+ }
9180
8384
  handlesByNode.set(node.id, entry);
9181
8385
  }
9182
8386
  const sourceCounts = new Map;
@@ -9296,7 +8500,78 @@ Validating: ${absolutePath}
9296
8500
  return issues;
9297
8501
  }
9298
8502
  }
8503
+ function indexJoinGraph(flow) {
8504
+ const modelTypeByNodeType = new Map;
8505
+ for (const def of flow.definitions) {
8506
+ if (typeof def.model?.type === "string") {
8507
+ modelTypeByNodeType.set(def.nodeType, def.model.type);
8508
+ }
8509
+ }
8510
+ const incomingByTarget = new Map;
8511
+ for (const edge of flow.edges) {
8512
+ const list2 = incomingByTarget.get(edge.targetNodeId) ?? [];
8513
+ list2.push(edge);
8514
+ incomingByTarget.set(edge.targetNodeId, list2);
8515
+ }
8516
+ return {
8517
+ nodesById: new Map(flow.nodes.map((n) => [n.id, n])),
8518
+ incomingByTarget,
8519
+ modelTypeOf: (node) => typeof node.model?.type === "string" ? node.model.type : modelTypeByNodeType.get(node.type)
8520
+ };
8521
+ }
8522
+ function isParallelJoin(node, graph) {
8523
+ return node.type === "core.logic.merge" || graph.modelTypeOf(node) === "bpmn:ParallelGateway";
8524
+ }
8525
+ function isExclusiveSplit(node, graph) {
8526
+ return node.type === "core.logic.decision" || node.type === "core.logic.switch" || graph.modelTypeOf(node) === "bpmn:ExclusiveGateway";
8527
+ }
8528
+ function walkToExclusiveSplit(edge, graph) {
8529
+ let current2 = edge;
8530
+ const seen = new Set;
8531
+ while (current2 !== undefined && !seen.has(current2.sourceNodeId)) {
8532
+ const source = graph.nodesById.get(current2.sourceNodeId);
8533
+ if (!source)
8534
+ return;
8535
+ seen.add(source.id);
8536
+ if (isExclusiveSplit(source, graph)) {
8537
+ return { splitId: source.id, port: current2.sourcePort };
8538
+ }
8539
+ const upstream = graph.incomingByTarget.get(source.id) ?? [];
8540
+ current2 = upstream.length === 1 ? upstream[0] : undefined;
8541
+ }
8542
+ return;
8543
+ }
8544
+ function findUnsatisfiableJoin(node, graph) {
8545
+ if (!isParallelJoin(node, graph))
8546
+ return;
8547
+ const incoming = graph.incomingByTarget.get(node.id) ?? [];
8548
+ if (incoming.length < 2)
8549
+ return;
8550
+ const origins = incoming.map((edge) => walkToExclusiveSplit(edge, graph));
8551
+ if (origins.includes(undefined))
8552
+ return;
8553
+ const resolved = origins;
8554
+ const splitIds = new Set(resolved.map((o) => o.splitId));
8555
+ if (splitIds.size !== 1)
8556
+ return;
8557
+ const ports = [...new Set(resolved.map((o) => o.port))].sort((a, b) => a.localeCompare(b));
8558
+ if (ports.length < 2)
8559
+ return;
8560
+ return { splitId: resolved[0].splitId, ports };
8561
+ }
8562
+ function describeUnsatisfiableJoin(node, finding, graph) {
8563
+ const split = graph.nodesById.get(finding.splitId);
8564
+ const splitLabel = split?.display?.label ?? finding.splitId;
8565
+ const joinLabel = node.display?.label ?? node.id;
8566
+ const splitKind = split?.type === "core.logic.switch" ? "Switch" : "Decision";
8567
+ const portList = finding.ports.map((p) => `"${p}"`).join(", ");
8568
+ return {
8569
+ path: `nodes[${node.id}]`,
8570
+ message: `Merge "${joinLabel}" can never complete: every one of its incoming paths comes from a ` + `different branch of the same ${splitKind} "${splitLabel}" (ports ${portList}). ` + `A Merge is a parallel join that waits for ALL incoming paths, but a ${splitKind} takes exactly one branch, ` + `so the run would stop at "${joinLabel}" and never reach an End node. ` + `Connect each branch directly to the node that should run next (a node accepts several incoming edges), ` + `and use Merge only to rejoin branches that run in parallel.`,
8571
+ severity: "error"
8572
+ };
8573
+ }
9299
8574
 
9300
- export { ensureDirectory, FlowEvalFileStore, fileNodesToPackagingNodes, packageInlineAgents, stageInlineAgentPackageFiles, buildInlineAgentDescriptors, writePackagingArtifacts, writePackagingArtifactsDetailed, regenerateBindingsFile, NodeTypeNotFoundError, NodeTypeNotEnabledError, SourceRequiredError, listNodesInFlow, ensureProcessBindings, collectNodeBindingResourceKeys, addNodeToFlow, deleteNodeFromFlow, ERROR_SOURCE_PORT, enableErrorHandlingForErrorEdges, expandHandleIds, portMatchesTemplate, evaluatorTypeAliases, resolveEvaluatorType, isRecord, isUUID, stripJsonExt, slugify, getEvaluatorRef, buildEvaluatorConfig, buildDefaultCriteria, captureMigrationIssues, formatMigrationFailureMessage, isConnectorTriggerType, isConnectorWaitForEventType, isEventDrivenConnectorType, scanDetailForCrossNodeBindings, connectorNodeValidator, FlowValidateService };
8575
+ export { connectorNodeValidator, FlowValidateService };
9301
8576
 
9302
- //# debugId=9B1959973F3B05AD64756E2164756E21
8577
+ //# debugId=17529DB3913E727964756E2164756E21