@poetic-ai/poetic 1.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (782) hide show
  1. package/.github/SECURITY.md +47 -0
  2. package/.nvmrc +1 -0
  3. package/.poetic/README.md +37 -0
  4. package/.poetic/providers/catalog.json +12051 -0
  5. package/.poetic/providers/pricing.json +1272 -0
  6. package/.poetic/providers/registry.json +3369 -0
  7. package/CHANGELOG.md +552 -0
  8. package/CODE_OF_CONDUCT.md +40 -0
  9. package/CONTRIBUTING.md +23 -0
  10. package/INSTALL.md +454 -0
  11. package/LICENSE +21 -0
  12. package/README.md +474 -0
  13. package/dist/BasicOptimizationCompetitionRunner-5H5TBYO4.js +153 -0
  14. package/dist/ExecutionTracker-UVONC4C6.js +16 -0
  15. package/dist/OptimizationConfig-7DFY2TST.js +17 -0
  16. package/dist/OptimizationEngine-JIMGP3LY.js +1597 -0
  17. package/dist/PromptStore-U6ZD3ZMQ.js +18 -0
  18. package/dist/actions-LUJPINLJ.js +322 -0
  19. package/dist/agent-ingest-3DJUJ7FU.js +53 -0
  20. package/dist/aggregator-DNCBINFO.js +12 -0
  21. package/dist/ai-judge-5QT5QJVU.js +156 -0
  22. package/dist/allowlist-grounding-RO6HKUFI.js +16 -0
  23. package/dist/allowlist-utils-23V7TJ3G.js +28 -0
  24. package/dist/anchored-turn-service-JULUCUIK.js +489 -0
  25. package/dist/api-transport-4TYTNLTJ.js +1087 -0
  26. package/dist/apply-completion-mode-AW2MOS3R.js +89 -0
  27. package/dist/artifact-migrator-23L45ISD.js +267 -0
  28. package/dist/ask-HWVV6QFR.js +135 -0
  29. package/dist/auth-5KEDKAPP.js +67 -0
  30. package/dist/auth-7TT3JINV.js +78 -0
  31. package/dist/auth-E6XUNZ5M.js +68 -0
  32. package/dist/auth-H3XDZE22.js +134 -0
  33. package/dist/auth-OC4E6633.js +71 -0
  34. package/dist/auth-S4CTX4GQ.js +44 -0
  35. package/dist/auth-YLH3S7EY.js +69 -0
  36. package/dist/auth-liveness-TDDEZY3T.js +46 -0
  37. package/dist/auto-optimizer-VPRWOWGU.js +80 -0
  38. package/dist/autoloop-cleanup-JOGKTLWA.js +109 -0
  39. package/dist/autoloop-evidence-gates-PCDALGVJ.js +38 -0
  40. package/dist/autoloop-gate-policy-Z7FVJVXV.js +175 -0
  41. package/dist/autoloop-helpers-2KTK43GL.js +22 -0
  42. package/dist/autoloop-ledger-W7QO62PX.js +96 -0
  43. package/dist/autoloop-ledger-subscriber-Z5RW5EIE.js +162 -0
  44. package/dist/autoloop-run-defaults-FERGRZGP.js +19 -0
  45. package/dist/autoloop-run-lock-CT2NWSV3.js +197 -0
  46. package/dist/autoloop-success-J2VKKBXQ.js +85 -0
  47. package/dist/autoloop-termination-summary-RN75F422.js +58 -0
  48. package/dist/autoloop-trajectory-XFIEXP5Z.js +282 -0
  49. package/dist/autoloop-wall-clock-T7ZVIQOC.js +12 -0
  50. package/dist/autonomous-loop-controller-PW4XVFGQ.js +4120 -0
  51. package/dist/backend-P3DAYRP7.js +29 -0
  52. package/dist/background-executor-CBN552V4.js +257 -0
  53. package/dist/backlog-execution-intent-U4XYPTV6.js +15 -0
  54. package/dist/backup-active-store-5WXG6SXT.js +17 -0
  55. package/dist/backup-telemetry-db-XGLXAA3N.js +254 -0
  56. package/dist/basic-competition-master-VCSBJVRN.js +344 -0
  57. package/dist/branch-archive-manager-RP6FP3ZC.js +254 -0
  58. package/dist/branch-cleanup-manager-RSHAI7YR.js +20 -0
  59. package/dist/build-gate-YHGRB4QB.js +71 -0
  60. package/dist/change-summary-WY7J5TOX.js +33 -0
  61. package/dist/chunk-23A26CSN.js +123 -0
  62. package/dist/chunk-27UTJD3M.js +265 -0
  63. package/dist/chunk-2A5CILN3.js +310 -0
  64. package/dist/chunk-2AQUWJPW.js +225 -0
  65. package/dist/chunk-2BZ53J6J.js +2344 -0
  66. package/dist/chunk-2DY5KNVM.js +276 -0
  67. package/dist/chunk-2EIA4RBE.js +659 -0
  68. package/dist/chunk-2IUXIGQD.js +1064 -0
  69. package/dist/chunk-2N42MS2Z.js +2193 -0
  70. package/dist/chunk-2QJ3H3L7.js +42 -0
  71. package/dist/chunk-2QLYTVYX.js +791 -0
  72. package/dist/chunk-2VSQMRCB.js +18 -0
  73. package/dist/chunk-2XQXYBM2.js +130 -0
  74. package/dist/chunk-2YFUIER7.js +426 -0
  75. package/dist/chunk-34CNP2HB.js +148 -0
  76. package/dist/chunk-35P3W3JX.js +456 -0
  77. package/dist/chunk-36PEBZAF.js +18 -0
  78. package/dist/chunk-3AOKYKA7.js +22 -0
  79. package/dist/chunk-3BCUNHKF.js +475 -0
  80. package/dist/chunk-3FLXLLB7.js +26 -0
  81. package/dist/chunk-3FOZ2VHV.js +100 -0
  82. package/dist/chunk-3G6FZCRF.js +106 -0
  83. package/dist/chunk-3M57DADF.js +44 -0
  84. package/dist/chunk-3S62LLWJ.js +543 -0
  85. package/dist/chunk-3ZPQLGV7.js +2904 -0
  86. package/dist/chunk-44N5WZZH.js +45 -0
  87. package/dist/chunk-45FPSA3B.js +125 -0
  88. package/dist/chunk-4BJ3O4RQ.js +929 -0
  89. package/dist/chunk-4BOP7T6L.js +2321 -0
  90. package/dist/chunk-4BTDUT2S.js +42 -0
  91. package/dist/chunk-4CSS7WVI.js +143 -0
  92. package/dist/chunk-4CUY7AFY.js +247 -0
  93. package/dist/chunk-4GSN5O5J.js +62 -0
  94. package/dist/chunk-4HN6DF7V.js +1027 -0
  95. package/dist/chunk-4IAPOG5V.js +415 -0
  96. package/dist/chunk-4IYIZQWV.js +48 -0
  97. package/dist/chunk-4NXPXE62.js +84 -0
  98. package/dist/chunk-4RCCF5BR.js +712 -0
  99. package/dist/chunk-4V7NAQ4R.js +19527 -0
  100. package/dist/chunk-4VJITV4P.js +445 -0
  101. package/dist/chunk-4YX7J6QL.js +1859 -0
  102. package/dist/chunk-527OBWQB.js +338 -0
  103. package/dist/chunk-5D4A7E3D.js +448 -0
  104. package/dist/chunk-5DLKYTQX.js +4003 -0
  105. package/dist/chunk-5EERLVZB.js +139 -0
  106. package/dist/chunk-5H72XE4H.js +256 -0
  107. package/dist/chunk-5HDP7XZG.js +91 -0
  108. package/dist/chunk-5LAMRH4X.js +969 -0
  109. package/dist/chunk-5LTN43AS.js +1972 -0
  110. package/dist/chunk-5RBHQYDB.js +2206 -0
  111. package/dist/chunk-5WCQRDRB.js +588 -0
  112. package/dist/chunk-5WRLK5KW.js +700 -0
  113. package/dist/chunk-5ZCXC23G.js +595 -0
  114. package/dist/chunk-6BM72ZMG.js +31 -0
  115. package/dist/chunk-6EDAJH2I.js +68 -0
  116. package/dist/chunk-6EQKFDBH.js +457 -0
  117. package/dist/chunk-6MFRHTRI.js +115 -0
  118. package/dist/chunk-6TZJRKNW.js +321 -0
  119. package/dist/chunk-6V7HGQFZ.js +20 -0
  120. package/dist/chunk-6VWVO2TU.js +3746 -0
  121. package/dist/chunk-6Y5TWI7H.js +146 -0
  122. package/dist/chunk-6Y5U7UFY.js +91 -0
  123. package/dist/chunk-6ZLAK3XG.js +14 -0
  124. package/dist/chunk-72XCRQED.js +34 -0
  125. package/dist/chunk-72YTZMAM.js +589 -0
  126. package/dist/chunk-73BBJOKA.js +263 -0
  127. package/dist/chunk-73NCTWKL.js +188 -0
  128. package/dist/chunk-77I6G4CO.js +1 -0
  129. package/dist/chunk-7DHRDWFS.js +3104 -0
  130. package/dist/chunk-7DNSNKJV.js +78 -0
  131. package/dist/chunk-7FMJVYBS.js +307 -0
  132. package/dist/chunk-7GDRQBQC.js +419 -0
  133. package/dist/chunk-7GPCEFUV.js +270 -0
  134. package/dist/chunk-7IL4A2PP.js +948 -0
  135. package/dist/chunk-7MMLMXO6.js +3679 -0
  136. package/dist/chunk-7QCZSLBH.js +1 -0
  137. package/dist/chunk-7R2WLDOS.js +62 -0
  138. package/dist/chunk-7T7RUJI7.js +949 -0
  139. package/dist/chunk-A2WKSVX7.js +43 -0
  140. package/dist/chunk-A3YGID55.js +133 -0
  141. package/dist/chunk-A722DEVA.js +14 -0
  142. package/dist/chunk-ACDIT7OP.js +1376 -0
  143. package/dist/chunk-ACKIPAOJ.js +302 -0
  144. package/dist/chunk-APPNGGN7.js +365 -0
  145. package/dist/chunk-APV6MK5E.js +137 -0
  146. package/dist/chunk-ASEP3M2W.js +968 -0
  147. package/dist/chunk-AT4TNPWW.js +2931 -0
  148. package/dist/chunk-ATVKCSGT.js +250 -0
  149. package/dist/chunk-AURFMVCD.js +899 -0
  150. package/dist/chunk-AX6GWE7V.js +47 -0
  151. package/dist/chunk-AY5EWJPF.js +385 -0
  152. package/dist/chunk-BAV2HJXS.js +194 -0
  153. package/dist/chunk-BBHRN366.js +89 -0
  154. package/dist/chunk-BBPSTTPA.js +1004 -0
  155. package/dist/chunk-BDATUDDJ.js +992 -0
  156. package/dist/chunk-BKE5PG5L.js +20414 -0
  157. package/dist/chunk-BLPHWMDK.js +797 -0
  158. package/dist/chunk-BSE4R6XD.js +322 -0
  159. package/dist/chunk-BXGMAU4A.js +396 -0
  160. package/dist/chunk-BXI4NXL3.js +507 -0
  161. package/dist/chunk-BZU2O43F.js +1125 -0
  162. package/dist/chunk-C3L6YQ7P.js +147 -0
  163. package/dist/chunk-C57KJOUQ.js +121 -0
  164. package/dist/chunk-CCV7BPSY.js +118 -0
  165. package/dist/chunk-CD7ISXA4.js +826 -0
  166. package/dist/chunk-CE5OZBYY.js +21 -0
  167. package/dist/chunk-CFBIG37O.js +154 -0
  168. package/dist/chunk-CJC6GZ46.js +457 -0
  169. package/dist/chunk-CKCDGXIV.js +408 -0
  170. package/dist/chunk-CKNX3TTP.js +10338 -0
  171. package/dist/chunk-CLKSETWE.js +10 -0
  172. package/dist/chunk-CP7H3HSP.js +1552 -0
  173. package/dist/chunk-CPLEWXNZ.js +66 -0
  174. package/dist/chunk-CQM3A35X.js +844 -0
  175. package/dist/chunk-CS6P76D3.js +103 -0
  176. package/dist/chunk-CTLUBNCW.js +622 -0
  177. package/dist/chunk-CUSRN6RJ.js +632 -0
  178. package/dist/chunk-D5EP5D2W.js +26 -0
  179. package/dist/chunk-D5RYINO7.js +412 -0
  180. package/dist/chunk-DBFS4HMH.js +751 -0
  181. package/dist/chunk-DC4ZYMXJ.js +115 -0
  182. package/dist/chunk-DCBZP442.js +9243 -0
  183. package/dist/chunk-DCYF7EKG.js +26 -0
  184. package/dist/chunk-DDMAFNUK.js +5351 -0
  185. package/dist/chunk-DF5SLDE4.js +966 -0
  186. package/dist/chunk-DJFW7SMX.js +348 -0
  187. package/dist/chunk-DQFLLBJW.js +121 -0
  188. package/dist/chunk-DSFM56OA.js +1203 -0
  189. package/dist/chunk-DTY4APYV.js +218 -0
  190. package/dist/chunk-DXH5JBRS.js +437 -0
  191. package/dist/chunk-E3NTPHEO.js +194 -0
  192. package/dist/chunk-E74LUIID.js +302 -0
  193. package/dist/chunk-EI57M5BI.js +194 -0
  194. package/dist/chunk-EJ4ZAWLV.js +305 -0
  195. package/dist/chunk-EJGCZGUF.js +1483 -0
  196. package/dist/chunk-EK2U3YEG.js +486 -0
  197. package/dist/chunk-ELMFYNV7.js +109 -0
  198. package/dist/chunk-ENRGKNR5.js +25 -0
  199. package/dist/chunk-ETYDXCK7.js +679 -0
  200. package/dist/chunk-EYRH3W74.js +239 -0
  201. package/dist/chunk-F23DIWNN.js +1024 -0
  202. package/dist/chunk-F5JO7HAS.js +94 -0
  203. package/dist/chunk-F7ER6ANO.js +174 -0
  204. package/dist/chunk-FATUVIIN.js +374 -0
  205. package/dist/chunk-FC23CTXV.js +322 -0
  206. package/dist/chunk-FD4ERYEG.js +22 -0
  207. package/dist/chunk-FH7WOJAE.js +79 -0
  208. package/dist/chunk-FHOWVDF5.js +1342 -0
  209. package/dist/chunk-FKAUPHMR.js +96 -0
  210. package/dist/chunk-FONNFJXA.js +137 -0
  211. package/dist/chunk-FQ7FSZRW.js +75 -0
  212. package/dist/chunk-FRG57FPM.js +240 -0
  213. package/dist/chunk-FUVP64ER.js +31 -0
  214. package/dist/chunk-FYOILAN5.js +6818 -0
  215. package/dist/chunk-G35UYQ6Z.js +69 -0
  216. package/dist/chunk-G36W2T2S.js +1143 -0
  217. package/dist/chunk-G3L2L5XZ.js +49 -0
  218. package/dist/chunk-G4THLFV3.js +148 -0
  219. package/dist/chunk-GAFJEYLK.js +29 -0
  220. package/dist/chunk-GFGYB2ZU.js +1689 -0
  221. package/dist/chunk-GG6KJYW6.js +85 -0
  222. package/dist/chunk-GHHFDU2U.js +55 -0
  223. package/dist/chunk-GHTZSQB7.js +57 -0
  224. package/dist/chunk-GK37ILCX.js +1231 -0
  225. package/dist/chunk-GKN3HMN4.js +2809 -0
  226. package/dist/chunk-GNVDBVJP.js +156 -0
  227. package/dist/chunk-GPEL3FBM.js +924 -0
  228. package/dist/chunk-GPSNGPZS.js +1604 -0
  229. package/dist/chunk-GSGD5E4C.js +30 -0
  230. package/dist/chunk-GSUQJJXQ.js +331 -0
  231. package/dist/chunk-GSV226X6.js +110 -0
  232. package/dist/chunk-H2AYQIHW.js +224 -0
  233. package/dist/chunk-H66DXFS5.js +1374 -0
  234. package/dist/chunk-H6G7QRMQ.js +35 -0
  235. package/dist/chunk-H7JAGHZT.js +59 -0
  236. package/dist/chunk-H7ZEFECA.js +316 -0
  237. package/dist/chunk-HAC6EHZZ.js +79 -0
  238. package/dist/chunk-HIO33P3G.js +19 -0
  239. package/dist/chunk-HMVQIPH3.js +547 -0
  240. package/dist/chunk-HOYBYAOA.js +257 -0
  241. package/dist/chunk-HX5P3CSP.js +1784 -0
  242. package/dist/chunk-I46EG2XQ.js +65 -0
  243. package/dist/chunk-I4NPDSCB.js +279 -0
  244. package/dist/chunk-I5WRT7ZR.js +514 -0
  245. package/dist/chunk-IC7I6YIJ.js +301 -0
  246. package/dist/chunk-IDCSOZVN.js +78 -0
  247. package/dist/chunk-IFCBYECK.js +112 -0
  248. package/dist/chunk-IFZCPEY2.js +66 -0
  249. package/dist/chunk-IKFP2KUR.js +48 -0
  250. package/dist/chunk-IRFBN336.js +878 -0
  251. package/dist/chunk-IUXNGKA6.js +152 -0
  252. package/dist/chunk-IV2RVAN7.js +1356 -0
  253. package/dist/chunk-IZYIQQ7X.js +53 -0
  254. package/dist/chunk-J3UUR7DE.js +210 -0
  255. package/dist/chunk-J54VUAY2.js +566 -0
  256. package/dist/chunk-J62KPGII.js +464 -0
  257. package/dist/chunk-J6P3FWWW.js +130 -0
  258. package/dist/chunk-JKBHJQMT.js +434 -0
  259. package/dist/chunk-JLS65NUQ.js +14 -0
  260. package/dist/chunk-JOSYEJKY.js +141 -0
  261. package/dist/chunk-JPKSXKNB.js +94 -0
  262. package/dist/chunk-JQNJB2BB.js +2440 -0
  263. package/dist/chunk-JRVNSWSQ.js +2626 -0
  264. package/dist/chunk-JSWMRQYG.js +28 -0
  265. package/dist/chunk-JZKNBBIB.js +152 -0
  266. package/dist/chunk-K54Y7MLK.js +160 -0
  267. package/dist/chunk-K65546RE.js +183 -0
  268. package/dist/chunk-KM3F7SYE.js +702 -0
  269. package/dist/chunk-KNDYMVWN.js +102 -0
  270. package/dist/chunk-KNT72VR6.js +132 -0
  271. package/dist/chunk-KP6YILMU.js +482 -0
  272. package/dist/chunk-KQEBSK3T.js +274 -0
  273. package/dist/chunk-KT6VHSPF.js +84 -0
  274. package/dist/chunk-KTMW65UX.js +14 -0
  275. package/dist/chunk-KZ5CJVBP.js +1813 -0
  276. package/dist/chunk-L4427KOE.js +26 -0
  277. package/dist/chunk-L6OM4A22.js +189 -0
  278. package/dist/chunk-L7E6XCRA.js +1042 -0
  279. package/dist/chunk-L7JZLXQL.js +173 -0
  280. package/dist/chunk-LAMKBTXX.js +40 -0
  281. package/dist/chunk-LDCF2MKN.js +132 -0
  282. package/dist/chunk-LEIIWPWQ.js +78 -0
  283. package/dist/chunk-LFTQVYBB.js +31 -0
  284. package/dist/chunk-LG3PDRTR.js +2872 -0
  285. package/dist/chunk-LGHII5ET.js +23 -0
  286. package/dist/chunk-LH5QY22X.js +1205 -0
  287. package/dist/chunk-LIVJ6266.js +438 -0
  288. package/dist/chunk-LKRAR3IH.js +276 -0
  289. package/dist/chunk-LO23NABI.js +3063 -0
  290. package/dist/chunk-LO3X5NLS.js +326 -0
  291. package/dist/chunk-LPITVM7M.js +339 -0
  292. package/dist/chunk-LR5IJIGV.js +810 -0
  293. package/dist/chunk-LRGMHROI.js +79 -0
  294. package/dist/chunk-LUVKFFWR.js +315 -0
  295. package/dist/chunk-LWCBNGH6.js +35 -0
  296. package/dist/chunk-LWTN3WRV.js +260 -0
  297. package/dist/chunk-M3HQYKQX.js +308 -0
  298. package/dist/chunk-M6GVSPEH.js +1016 -0
  299. package/dist/chunk-MF5HP6XV.js +221 -0
  300. package/dist/chunk-MHLCBZJB.js +328 -0
  301. package/dist/chunk-MN6PL4AN.js +120 -0
  302. package/dist/chunk-MOEY65Z6.js +5678 -0
  303. package/dist/chunk-MQ4WA34C.js +206 -0
  304. package/dist/chunk-MWHF5V7U.js +223 -0
  305. package/dist/chunk-MWHLBPNU.js +211 -0
  306. package/dist/chunk-MWK5UZQ3.js +1068 -0
  307. package/dist/chunk-MYLH2S4G.js +64 -0
  308. package/dist/chunk-MZ5WYKNA.js +28 -0
  309. package/dist/chunk-N4VTRA7K.js +131 -0
  310. package/dist/chunk-N5DX4JAK.js +12 -0
  311. package/dist/chunk-N65O4XTH.js +5011 -0
  312. package/dist/chunk-NEQUQHOX.js +223 -0
  313. package/dist/chunk-NGK6PEOG.js +25 -0
  314. package/dist/chunk-NJVD4PWE.js +1033 -0
  315. package/dist/chunk-NM6PMYY4.js +768 -0
  316. package/dist/chunk-NN4PJDHP.js +708 -0
  317. package/dist/chunk-NP2V3L7K.js +226 -0
  318. package/dist/chunk-NRLY536M.js +260 -0
  319. package/dist/chunk-NRNE225N.js +1270 -0
  320. package/dist/chunk-NS2K2GTP.js +605 -0
  321. package/dist/chunk-NS33V3IM.js +51 -0
  322. package/dist/chunk-NSHASMZZ.js +71 -0
  323. package/dist/chunk-NWOYOA6H.js +378 -0
  324. package/dist/chunk-NWRUSEXG.js +322 -0
  325. package/dist/chunk-NZGDAWIP.js +1905 -0
  326. package/dist/chunk-O47UOKU3.js +395 -0
  327. package/dist/chunk-O4G2W3ST.js +9831 -0
  328. package/dist/chunk-O6V4PNLO.js +63 -0
  329. package/dist/chunk-OA4GPILI.js +624 -0
  330. package/dist/chunk-OGMSYL6J.js +227 -0
  331. package/dist/chunk-OIS7J26S.js +319 -0
  332. package/dist/chunk-OMX5VL43.js +79 -0
  333. package/dist/chunk-ON3G73BU.js +264 -0
  334. package/dist/chunk-OPYFYTWQ.js +220 -0
  335. package/dist/chunk-OQ6K46CK.js +1734 -0
  336. package/dist/chunk-OYZYO7TV.js +47 -0
  337. package/dist/chunk-OZ4REHIN.js +4386 -0
  338. package/dist/chunk-P47VN5F4.js +282 -0
  339. package/dist/chunk-P5I4X7A7.js +353 -0
  340. package/dist/chunk-P6VQROCO.js +594 -0
  341. package/dist/chunk-P7CQGPLS.js +30 -0
  342. package/dist/chunk-PCAGC5MR.js +1763 -0
  343. package/dist/chunk-PFTQBXS6.js +5181 -0
  344. package/dist/chunk-PGSPX4SU.js +15 -0
  345. package/dist/chunk-PIKLF7BM.js +432 -0
  346. package/dist/chunk-PJWJ3SAV.js +22 -0
  347. package/dist/chunk-PKIFMV72.js +100 -0
  348. package/dist/chunk-PL37JDNA.js +189 -0
  349. package/dist/chunk-PTH5E5XO.js +195 -0
  350. package/dist/chunk-PW6AXLQC.js +4128 -0
  351. package/dist/chunk-PYITM4N2.js +79 -0
  352. package/dist/chunk-PZ5AY32C.js +10 -0
  353. package/dist/chunk-Q3RO7N35.js +45 -0
  354. package/dist/chunk-Q3WIC6GQ.js +2670 -0
  355. package/dist/chunk-Q5XIXSHX.js +271 -0
  356. package/dist/chunk-QGJDMEOV.js +34 -0
  357. package/dist/chunk-QNOB37UH.js +58 -0
  358. package/dist/chunk-QOCOVLUH.js +462 -0
  359. package/dist/chunk-QTCJ5CC5.js +172 -0
  360. package/dist/chunk-QVFV5IP2.js +232 -0
  361. package/dist/chunk-QVZMFDYG.js +29 -0
  362. package/dist/chunk-R35PEUKH.js +511 -0
  363. package/dist/chunk-R4UWBC35.js +200 -0
  364. package/dist/chunk-R6MLCREW.js +44 -0
  365. package/dist/chunk-R6W23LKN.js +254 -0
  366. package/dist/chunk-R7XDDX2A.js +4007 -0
  367. package/dist/chunk-RDFRCT64.js +168 -0
  368. package/dist/chunk-RE5VZDFQ.js +58 -0
  369. package/dist/chunk-RGROYC2G.js +638 -0
  370. package/dist/chunk-RGWHUI5E.js +68 -0
  371. package/dist/chunk-RHVG6UNL.js +205 -0
  372. package/dist/chunk-RI4EX2QE.js +18 -0
  373. package/dist/chunk-RJAAKDRX.js +17 -0
  374. package/dist/chunk-ROMHOSMQ.js +185 -0
  375. package/dist/chunk-RWREC3KJ.js +517 -0
  376. package/dist/chunk-RYNETRDJ.js +118 -0
  377. package/dist/chunk-RZY7RKM5.js +500 -0
  378. package/dist/chunk-S2MNWFAG.js +52 -0
  379. package/dist/chunk-S2VQCZO4.js +22 -0
  380. package/dist/chunk-S54MKU6V.js +117 -0
  381. package/dist/chunk-S5OIDFRM.js +302 -0
  382. package/dist/chunk-SCW4ZF6R.js +150 -0
  383. package/dist/chunk-SLS2N4PH.js +2213 -0
  384. package/dist/chunk-SNLBO4BF.js +247 -0
  385. package/dist/chunk-SP3LFU6B.js +60 -0
  386. package/dist/chunk-SQQTDDQA.js +537 -0
  387. package/dist/chunk-STV6LYYE.js +45 -0
  388. package/dist/chunk-SURZ2WFE.js +326 -0
  389. package/dist/chunk-SZ7DL357.js +1047 -0
  390. package/dist/chunk-T5E4NQCM.js +5742 -0
  391. package/dist/chunk-TAJPCXSB.js +13 -0
  392. package/dist/chunk-TAOOYK3P.js +358 -0
  393. package/dist/chunk-TDSEX5CF.js +24 -0
  394. package/dist/chunk-TFTGP7Z7.js +174 -0
  395. package/dist/chunk-TGON4N4O.js +197 -0
  396. package/dist/chunk-TGQZHDY2.js +2373 -0
  397. package/dist/chunk-TJJZ2OKV.js +6783 -0
  398. package/dist/chunk-TRSVUPCX.js +25 -0
  399. package/dist/chunk-TSXGRLPR.js +107 -0
  400. package/dist/chunk-U2S3YEX3.js +224 -0
  401. package/dist/chunk-U45RTRGY.js +818 -0
  402. package/dist/chunk-U6C3VVWS.js +13 -0
  403. package/dist/chunk-UDMS5AD3.js +307 -0
  404. package/dist/chunk-UGX7GI37.js +94 -0
  405. package/dist/chunk-UH3JJSHK.js +1 -0
  406. package/dist/chunk-UHRBTZYY.js +208 -0
  407. package/dist/chunk-UHT2KRG5.js +193 -0
  408. package/dist/chunk-UI2F6DJ5.js +118 -0
  409. package/dist/chunk-UMAKSB4Z.js +284 -0
  410. package/dist/chunk-UR2IBGIM.js +521 -0
  411. package/dist/chunk-UUH2RVKS.js +585 -0
  412. package/dist/chunk-UVJ4PJDK.js +4533 -0
  413. package/dist/chunk-V53UG2OT.js +9924 -0
  414. package/dist/chunk-V72RMBM4.js +48 -0
  415. package/dist/chunk-VBNCKCCI.js +16 -0
  416. package/dist/chunk-VNSYKC25.js +24 -0
  417. package/dist/chunk-VPHVFK4A.js +1984 -0
  418. package/dist/chunk-VTLNJQ44.js +133 -0
  419. package/dist/chunk-VTW7HP3R.js +100 -0
  420. package/dist/chunk-VVGEPBPS.js +218 -0
  421. package/dist/chunk-VVLLL7I4.js +166 -0
  422. package/dist/chunk-VX3UMWB7.js +483 -0
  423. package/dist/chunk-VXF4Q3FW.js +20 -0
  424. package/dist/chunk-W3JMT2YY.js +712 -0
  425. package/dist/chunk-WDUORIHF.js +877 -0
  426. package/dist/chunk-WDVTY4U6.js +148 -0
  427. package/dist/chunk-WIFZCHEG.js +12566 -0
  428. package/dist/chunk-WIRN3F75.js +736 -0
  429. package/dist/chunk-WMPU2UOV.js +82 -0
  430. package/dist/chunk-WTOKKE2V.js +784 -0
  431. package/dist/chunk-WX5IRLF6.js +740 -0
  432. package/dist/chunk-WZ6U3O7I.js +1581 -0
  433. package/dist/chunk-XAONGNST.js +57 -0
  434. package/dist/chunk-XB5YLCLB.js +13 -0
  435. package/dist/chunk-XEP5NQ5Y.js +688 -0
  436. package/dist/chunk-XGYF2QMZ.js +351 -0
  437. package/dist/chunk-XHEKQENB.js +255 -0
  438. package/dist/chunk-XNO4FM6X.js +1124 -0
  439. package/dist/chunk-XPHKYHO4.js +878 -0
  440. package/dist/chunk-XPK2I4NC.js +405 -0
  441. package/dist/chunk-XPU2XADL.js +2175 -0
  442. package/dist/chunk-XQD2B6BB.js +507 -0
  443. package/dist/chunk-XT2ZQVTC.js +558 -0
  444. package/dist/chunk-XTXJGGUV.js +351 -0
  445. package/dist/chunk-XUXVDPSZ.js +50 -0
  446. package/dist/chunk-XV7NZL4B.js +57 -0
  447. package/dist/chunk-XZE4XARH.js +563 -0
  448. package/dist/chunk-XZYR5EDO.js +152 -0
  449. package/dist/chunk-Y3J4JMTU.js +61 -0
  450. package/dist/chunk-Y55LZN5U.js +52 -0
  451. package/dist/chunk-Y5VN7DMP.js +112 -0
  452. package/dist/chunk-Y67VAHN4.js +459 -0
  453. package/dist/chunk-YAXSKEUH.js +3544 -0
  454. package/dist/chunk-YB3JD4E6.js +975 -0
  455. package/dist/chunk-YESZJFK6.js +220 -0
  456. package/dist/chunk-YGXKOBQQ.js +292 -0
  457. package/dist/chunk-YMX76IOS.js +31 -0
  458. package/dist/chunk-YOTXESEH.js +257 -0
  459. package/dist/chunk-YTYIEZQY.js +119 -0
  460. package/dist/chunk-YVORHQ2S.js +579 -0
  461. package/dist/chunk-Z2CUQDAR.js +3429 -0
  462. package/dist/chunk-Z2KYOFHS.js +7000 -0
  463. package/dist/chunk-Z6PC7QX6.js +161 -0
  464. package/dist/chunk-ZDTGECTN.js +235 -0
  465. package/dist/chunk-ZIPWI2LY.js +151 -0
  466. package/dist/chunk-ZSKKMTQJ.js +554 -0
  467. package/dist/chunk-ZTT5IVPY.js +1160 -0
  468. package/dist/chunk-ZX65UI5W.js +78 -0
  469. package/dist/chunk-ZYG7GGKO.js +218 -0
  470. package/dist/chunk-ZZZUL4OF.js +38 -0
  471. package/dist/cli-utils-IXL26KJT.js +40 -0
  472. package/dist/cli-validation-WLXWLUJL.js +111 -0
  473. package/dist/commit-utils-P7CRJF5N.js +202 -0
  474. package/dist/compete-config-resolver-R5ULXMYH.js +76 -0
  475. package/dist/compete-request-62JESVET.js +364 -0
  476. package/dist/compete-results-QEPG6FZX.js +208 -0
  477. package/dist/competition-outcome-tracker-R32OOZ43.js +38 -0
  478. package/dist/config-JCOKXOQT.js +166 -0
  479. package/dist/config-audit-EL3GHXS7.js +360 -0
  480. package/dist/config-explain-TNILDEVJ.js +12 -0
  481. package/dist/config-loader-VPFPFO4B.js +38 -0
  482. package/dist/config-manager-7T4E2BQO.js +67 -0
  483. package/dist/config-validator-KKOHOW7O.js +72 -0
  484. package/dist/cost-YC42XUF3.js +53 -0
  485. package/dist/coverage-orchestrator-CISNKJC2.js +772 -0
  486. package/dist/coverage-scanner-YVD62MLH.js +12 -0
  487. package/dist/createCompetitionRunner-LJG6ZQSO.js +46 -0
  488. package/dist/data-migration-state-VJK64DLT.js +31 -0
  489. package/dist/db-migrator-XSEIOGWY.js +34 -0
  490. package/dist/discovery-JGYGDD25.js +25 -0
  491. package/dist/doctor-GJOYE7AE.js +186 -0
  492. package/dist/domain-analyzer-AWF3RP6E.js +29 -0
  493. package/dist/ensure-initialized-744DIZEZ.js +52 -0
  494. package/dist/entry.js +940 -0
  495. package/dist/environment-YS45U5ZI.js +81 -0
  496. package/dist/error-parser-core-PPZ36A4S.js +50 -0
  497. package/dist/escalation-ladder-MKTCEGSA.js +130 -0
  498. package/dist/evaluation-context-KV4GZNN7.js +35 -0
  499. package/dist/evidence-plan-resolver-GBSYSAPX.js +85 -0
  500. package/dist/execution-data-writer-3ODTBDLH.js +53 -0
  501. package/dist/execution-policy-applier-ZHD3DCF3.js +31 -0
  502. package/dist/execution-preflight-Z4Y64V3I.js +209 -0
  503. package/dist/execution-roles-R3DPPMD3.js +66 -0
  504. package/dist/exit-code-error-Z4SW2DVK.js +14 -0
  505. package/dist/external-temp-cleanup-N2RZH4QP.js +311 -0
  506. package/dist/factory-XBN7DFIM.js +149 -0
  507. package/dist/file-utils-XIVR2ZMA.js +47 -0
  508. package/dist/flywheel-autoloop-executor-UILGOFFK.js +249 -0
  509. package/dist/flywheel-competition-executor-JOBEXTRB.js +259 -0
  510. package/dist/flywheel-executor-6JFLA6J5.js +369 -0
  511. package/dist/flywheel-git-isolation-UC5NIEVU.js +48 -0
  512. package/dist/flywheel-manifest-5UC4VBMA.js +108 -0
  513. package/dist/flywheel-model-defaults-7CVKP53V.js +27 -0
  514. package/dist/flywheel-preflight-XEY5SHM6.js +104 -0
  515. package/dist/flywheel-resume-7HELH7QS.js +23 -0
  516. package/dist/flywheel-safety-7U7DPOAP.js +28 -0
  517. package/dist/flywheel-scope-decision-ZHKF6ZIN.js +11 -0
  518. package/dist/get-telemetry-logger-DPVWWIYY.js +73 -0
  519. package/dist/git-worktree-IY6V6DUO.js +18 -0
  520. package/dist/github-pr-manager-4LXEKJTA.js +211 -0
  521. package/dist/guidance-profile-config-E7XJL2VP.js +117 -0
  522. package/dist/guidance-profile-renderer-QK2YMAAP.js +21 -0
  523. package/dist/index-query-4JEUKA44.js +31 -0
  524. package/dist/index.js +108661 -0
  525. package/dist/instructions-6BURLQJC.js +64 -0
  526. package/dist/invoke-provider-auth-GRUYP44M.js +223 -0
  527. package/dist/judge-scoring.json +80 -0
  528. package/dist/judge-test.js +555 -0
  529. package/dist/lab-mode-OTWVHN63.js +39 -0
  530. package/dist/lab-utils-BJRFLGK4.js +23 -0
  531. package/dist/linux-host-class-UY4KVLFD.js +29 -0
  532. package/dist/llm-judge-executor-F7Z3HO77.js +133 -0
  533. package/dist/local-executor-CEHWE2PL.js +223 -0
  534. package/dist/logger-33TR6EE5.js +72 -0
  535. package/dist/loop-spec-XTLQAVZ7.js +191 -0
  536. package/dist/manager-2HJG5CLT.js +25 -0
  537. package/dist/matrix-prompt-builder-6UDN5X3F.js +497 -0
  538. package/dist/matrix-result-parser-7W35EUOV.js +15 -0
  539. package/dist/metadata-HQ43NDEK.js +22 -0
  540. package/dist/model-invocations-db-QBO4Y7WZ.js +38 -0
  541. package/dist/monitor-XGYBG2DW.js +72 -0
  542. package/dist/next-PB5ZXZKB.js +90 -0
  543. package/dist/next-ZBDK725T.js +69 -0
  544. package/dist/optimization-config-resolver-O6WKR47U.js +75 -0
  545. package/dist/package-3YCWIQQ5.js +10 -0
  546. package/dist/parallel-orchestrator-NL7YJJU2.js +297 -0
  547. package/dist/parallel-worker.js +279 -0
  548. package/dist/parse-git-status-PIAF3OTP.js +10 -0
  549. package/dist/path-security-ETTH6TZL.js +39 -0
  550. package/dist/pattern-bank-UNJR5ADV.js +15 -0
  551. package/dist/plan-backlog-list-fast-VAGYBV3J.js +270 -0
  552. package/dist/plan-backlog-show-fast-SG2CZPW3.js +406 -0
  553. package/dist/plan-sprint-list-fast-LURAX47V.js +162 -0
  554. package/dist/plan-sprint-status-fast-FJAODCHD.js +208 -0
  555. package/dist/plan-task-status-fast-HNYBMQI4.js +349 -0
  556. package/dist/plan-to-flywheel-Z4U3GWPN.js +456 -0
  557. package/dist/planning-backlog-3CQ5QQBQ.js +319 -0
  558. package/dist/poetic-root-V5DNXEAE.js +17 -0
  559. package/dist/preflight-OPANWMME.js +12 -0
  560. package/dist/process-registry-PDZJPTAS.js +27 -0
  561. package/dist/process-scanner-C22SYXYD.js +22 -0
  562. package/dist/processes-KMQUD7HY.js +29 -0
  563. package/dist/processes-json-fast-IBDXZ6WW.js +135 -0
  564. package/dist/profile-SE5EVXAP.js +149 -0
  565. package/dist/prompts-WZZPGWBX.js +168 -0
  566. package/dist/protected-branches-RNTEX7ET.js +57 -0
  567. package/dist/provider-aware-resource-manager-QBTZJMNP.js +18 -0
  568. package/dist/provider-matrix-N5X57V3Y.js +154 -0
  569. package/dist/provider-matrix-renderer-MZDWKKID.js +139 -0
  570. package/dist/provider-output-forwarding-DERID3TP.js +30 -0
  571. package/dist/provider-registry-J5NRBJKI.js +128 -0
  572. package/dist/provider-temp-cleanup-KYGLF6YU.js +14 -0
  573. package/dist/prune-engine-Q6E2DXBN.js +451 -0
  574. package/dist/quality-gate-YRHMQAEI.js +70 -0
  575. package/dist/quickstart-FIRLKGJI.js +62 -0
  576. package/dist/readiness-VZTMSG6J.js +96 -0
  577. package/dist/registry-YODFY77A.js +153 -0
  578. package/dist/repair-helpers-TTV5FEF4.js +117 -0
  579. package/dist/repo-root-2IGD4H7X.js +22 -0
  580. package/dist/resolution-engine-D6TX6FRG.js +127 -0
  581. package/dist/resolve-provider-cli-O2P6XZBZ.js +35 -0
  582. package/dist/restore-telemetry-db-BQL6DTQF.js +360 -0
  583. package/dist/result-streamer-WEHW476R.js +19 -0
  584. package/dist/routing-events-DHPUZDDF.js +27 -0
  585. package/dist/routing-history-store-UWCEXAP3.js +46 -0
  586. package/dist/routing-planner-F5WQEUOM.js +160 -0
  587. package/dist/run-poetic-tui-J6LWRJUP.js +13517 -0
  588. package/dist/run-simulation.js +376 -0
  589. package/dist/runner-CS2TNGHA.js +1092 -0
  590. package/dist/runner-HHH7ZN2Z.js +1571 -0
  591. package/dist/safety-OCC4KJJR.js +64 -0
  592. package/dist/safety-stanza-7SV3HGG3.js +60 -0
  593. package/dist/sandbox-32QXJEMV.js +81 -0
  594. package/dist/sandbox-RSO7VP6V.js +94 -0
  595. package/dist/schema-extensions.sql +234 -0
  596. package/dist/security-2KI5XNDG.js +17 -0
  597. package/dist/setup-bb-plugin-QAQWZCV5.js +738 -0
  598. package/dist/setup-claude-code-P7BTTSPO.js +317 -0
  599. package/dist/setup-temp-cleanup-GASCWZ2I.js +20 -0
  600. package/dist/shared-utils-D6U6UREP.js +37 -0
  601. package/dist/simple-artifact-goal-OTXNGZY6.js +25 -0
  602. package/dist/sprint-UIXPYOXQ.js +338 -0
  603. package/dist/sprint-bridge-4BHMSC3M.js +68 -0
  604. package/dist/sprint-execution-service-2B7WHL5L.js +311 -0
  605. package/dist/sprint-manager-IDQUDNQI.js +91 -0
  606. package/dist/sqlite-wrapper-UDWCTNLJ.js +17 -0
  607. package/dist/stale-cleanup-orchestrator-XWXV7KCZ.js +62 -0
  608. package/dist/storage-access-F6ALDN4S.js +22 -0
  609. package/dist/synthesis-XD6EDVHF.js +185 -0
  610. package/dist/task-classifier-LNLXSHOM.js +494 -0
  611. package/dist/task-list-fast-PTMA4LUC.js +147 -0
  612. package/dist/task-manager-XAT7GOWB.js +93 -0
  613. package/dist/task-splitter-U7DJ7W6A.js +79 -0
  614. package/dist/task-type-detector-OLVOMXZO.js +21 -0
  615. package/dist/task-type-resolver-KKNQYSB4.js +42 -0
  616. package/dist/telemetry-5HWBBXLX.js +131 -0
  617. package/dist/telemetry-health-tracker-DMSSGBZ2.js +11 -0
  618. package/dist/telemetry-path-resolver-7ICSG276.js +28 -0
  619. package/dist/telemetry-reliability-XUOZNZZ6.js +125 -0
  620. package/dist/token-estimator-MEQUL3EJ.js +37 -0
  621. package/dist/transports-KNSSV2V4.js +255 -0
  622. package/dist/unified-cost-tracker-4TFRBVPR.js +35 -0
  623. package/dist/unified-state-cleanup-LJPF2BOW.js +276 -0
  624. package/dist/universal-cost-calculator-BAJV35GA.js +42 -0
  625. package/dist/user-agents-GHUGCSKN.js +22 -0
  626. package/dist/variant-delivery-state-KLRNG6XA.js +33 -0
  627. package/dist/variant-state-cleanup-MZGGLQAJ.js +280 -0
  628. package/dist/variant-success-PJXWE3ZV.js +12 -0
  629. package/dist/variant-worker-KUWKBLAH.js +4196 -0
  630. package/dist/variant-worker.js +24 -0
  631. package/dist/variants-JE2FSAQS.js +233 -0
  632. package/dist/verification-toolchains-V24UHW6Q.js +28 -0
  633. package/dist/verify-commands-H3DTCSGI.js +37 -0
  634. package/dist/warning-EGQGUUIO.js +12 -0
  635. package/dist/work-edge-RWEDWJZF.js +49 -0
  636. package/dist/work-item-writer-WHAVZXAY.js +19 -0
  637. package/dist/worker-7SA2VS2Y.js +1435 -0
  638. package/dist/worker.js +19 -0
  639. package/dist/worktree-metrics-3DFUYVYE.js +26 -0
  640. package/dist/writeback-VZKHYHSN.js +44 -0
  641. package/docs/CLI_REFERENCE.md +7042 -0
  642. package/docs/PROVIDER_SETUP.md +1570 -0
  643. package/docs/README.md +96 -0
  644. package/docs/TROUBLESHOOTING.md +2232 -0
  645. package/docs/getting-started/QUICK_START.md +294 -0
  646. package/docs/getting-started/README.md +188 -0
  647. package/docs/getting-started/SETUP.md +52 -0
  648. package/docs/reference/AGENT_CONTEXT.md +38 -0
  649. package/docs/reference/PROVIDER_RELEASE_TIERS.md +34 -0
  650. package/docs/reference/README.md +381 -0
  651. package/docs/reference/SECURITY.md +262 -0
  652. package/integrations/bb-plugin-poetic/README.md +362 -0
  653. package/integrations/bb-plugin-poetic/app.css +341 -0
  654. package/integrations/bb-plugin-poetic/app.tsx +5059 -0
  655. package/integrations/bb-plugin-poetic/package.json +45 -0
  656. package/integrations/bb-plugin-poetic/server.ts +444 -0
  657. package/integrations/bb-plugin-poetic/src/adapter.ts +3312 -0
  658. package/integrations/bb-plugin-poetic/src/backlog-authoring-model.ts +150 -0
  659. package/integrations/bb-plugin-poetic/src/backlog-authoring-schema.ts +355 -0
  660. package/integrations/bb-plugin-poetic/src/backlog-authoring-service.ts +419 -0
  661. package/integrations/bb-plugin-poetic/src/backlog-authoring-view.ts +1026 -0
  662. package/integrations/bb-plugin-poetic/src/competition-defaults-schema.ts +122 -0
  663. package/integrations/bb-plugin-poetic/src/competition-defaults-service.ts +105 -0
  664. package/integrations/bb-plugin-poetic/src/competition-defaults-view.ts +138 -0
  665. package/integrations/bb-plugin-poetic/src/contract.ts +615 -0
  666. package/integrations/bb-plugin-poetic/src/finalize-model.ts +205 -0
  667. package/integrations/bb-plugin-poetic/src/finalize-schema.ts +158 -0
  668. package/integrations/bb-plugin-poetic/src/finalize-service.ts +382 -0
  669. package/integrations/bb-plugin-poetic/src/finalize-view.ts +159 -0
  670. package/integrations/bb-plugin-poetic/src/judge-operations-readback.ts +303 -0
  671. package/integrations/bb-plugin-poetic/src/judge-operations-schema.ts +33 -0
  672. package/integrations/bb-plugin-poetic/src/judge-operations-view.ts +459 -0
  673. package/integrations/bb-plugin-poetic/src/model.ts +1302 -0
  674. package/integrations/bb-plugin-poetic/src/monitor-service.ts +233 -0
  675. package/integrations/bb-plugin-poetic/src/panel-read-ux.ts +97 -0
  676. package/integrations/bb-plugin-poetic/src/patch-preview-schema.ts +166 -0
  677. package/integrations/bb-plugin-poetic/src/patch-preview-service.ts +480 -0
  678. package/integrations/bb-plugin-poetic/src/patch-preview-view.ts +109 -0
  679. package/integrations/bb-plugin-poetic/src/planning-readback.ts +204 -0
  680. package/integrations/bb-plugin-poetic/src/planning-service.ts +594 -0
  681. package/integrations/bb-plugin-poetic/src/planning-workspace-schema.ts +95 -0
  682. package/integrations/bb-plugin-poetic/src/planning-workspace.ts +323 -0
  683. package/integrations/bb-plugin-poetic/src/poll-handoff.ts +136 -0
  684. package/integrations/bb-plugin-poetic/src/project-target-server.ts +21 -0
  685. package/integrations/bb-plugin-poetic/src/project-target.ts +45 -0
  686. package/integrations/bb-plugin-poetic/src/reference-index.ts +192 -0
  687. package/integrations/bb-plugin-poetic/src/repository-schema.ts +30 -0
  688. package/integrations/bb-plugin-poetic/src/result-explorer-view.ts +597 -0
  689. package/integrations/bb-plugin-poetic/src/result-readback-model.ts +163 -0
  690. package/integrations/bb-plugin-poetic/src/result-readback-schema.ts +319 -0
  691. package/integrations/bb-plugin-poetic/src/result-readback-service.ts +333 -0
  692. package/integrations/bb-plugin-poetic/src/run-page-view.ts +177 -0
  693. package/integrations/bb-plugin-poetic/src/setup-config-schema.ts +291 -0
  694. package/integrations/bb-plugin-poetic/src/setup-config-service.ts +590 -0
  695. package/integrations/bb-plugin-poetic/src/setup-config-view.ts +413 -0
  696. package/integrations/bb-plugin-poetic/src/sprint-close-model.ts +150 -0
  697. package/integrations/bb-plugin-poetic/src/sprint-close-schema.ts +136 -0
  698. package/integrations/bb-plugin-poetic/src/sprint-close-service.ts +341 -0
  699. package/integrations/bb-plugin-poetic/src/sprint-close-view.ts +116 -0
  700. package/integrations/bb-plugin-poetic/src/sprint-composition-model.ts +714 -0
  701. package/integrations/bb-plugin-poetic/src/sprint-composition-readback.ts +231 -0
  702. package/integrations/bb-plugin-poetic/src/sprint-composition-schema.ts +601 -0
  703. package/integrations/bb-plugin-poetic/src/sprint-composition-service.ts +775 -0
  704. package/integrations/bb-plugin-poetic/src/sprint-composition-view.ts +1221 -0
  705. package/integrations/bb-plugin-poetic/src/task-authoring-model.ts +567 -0
  706. package/integrations/bb-plugin-poetic/src/task-authoring-schema.ts +635 -0
  707. package/integrations/bb-plugin-poetic/src/task-authoring-service.ts +842 -0
  708. package/integrations/bb-plugin-poetic/src/task-authoring-view.ts +1227 -0
  709. package/integrations/bb-plugin-poetic/src/task-detail-readback.ts +56 -0
  710. package/integrations/bb-plugin-poetic/src/task-detail-schema.ts +144 -0
  711. package/integrations/bb-plugin-poetic/src/task-navigation.ts +446 -0
  712. package/integrations/bb-plugin-poetic/src/workbench-route.ts +74 -0
  713. package/integrations/bb-plugin-poetic/tests/host-contract.test.ts +773 -0
  714. package/integrations/bb-plugin-poetic/tsconfig.json +18 -0
  715. package/integrations/bb-plugin-poetic/types/PROVENANCE.json +52 -0
  716. package/integrations/bb-plugin-poetic/types/bb-plugin-sdk-app.d.ts +1444 -0
  717. package/integrations/bb-plugin-poetic/types/bb-plugin-sdk.d.ts +13030 -0
  718. package/integrations/bb-plugin-poetic/vitest.host.config.ts +71 -0
  719. package/npm-shrinkwrap.json +4950 -0
  720. package/package.json +331 -0
  721. package/schemas/README.md +80 -0
  722. package/schemas/config-v1.schema.json +136 -0
  723. package/schemas/execution-config.schema.json +47 -0
  724. package/schemas/judge-scoring.schema.json +370 -0
  725. package/schemas/poetic.config.schema.json +2214 -0
  726. package/schemas/provider-config.schema.json +203 -0
  727. package/schemas/telemetry-config.schema.json +79 -0
  728. package/schemas/user-preferences.schema.json +141 -0
  729. package/scripts/assert-node-runtime.mjs +140 -0
  730. package/scripts/preflight-native.mjs +49 -0
  731. package/scripts/preinstall-node-check.mjs +78 -0
  732. package/scripts/setup-git-hooks.mjs +24 -0
  733. package/scripts/sync.sh +2722 -0
  734. package/scripts/write-node-launcher.sh +108 -0
  735. package/src/resources/gemini/slash-packs/default/plan.toml +15 -0
  736. package/src/resources/gemini/slash-packs/default/summary.toml +16 -0
  737. package/src/resources/gemini/slash-packs/default/tests.toml +16 -0
  738. package/templates/.poetic/README.md +37 -0
  739. package/templates/.poetic/agents/README.md +296 -0
  740. package/templates/.poetic/agents/api-documenter.md +147 -0
  741. package/templates/.poetic/agents/backend-architect.md +31 -0
  742. package/templates/.poetic/agents/code-reviewer.md +157 -0
  743. package/templates/.poetic/agents/data-scientist.md +179 -0
  744. package/templates/.poetic/agents/database-optimizer.md +145 -0
  745. package/templates/.poetic/agents/debugger.md +31 -0
  746. package/templates/.poetic/agents/deployment-engineer.md +164 -0
  747. package/templates/.poetic/agents/devops-troubleshooter.md +139 -0
  748. package/templates/.poetic/agents/frontend-developer.md +150 -0
  749. package/templates/.poetic/agents/javascript-pro.md +36 -0
  750. package/templates/.poetic/agents/performance-engineer.md +151 -0
  751. package/templates/.poetic/agents/python-pro.md +137 -0
  752. package/templates/.poetic/agents/test-automator.md +147 -0
  753. package/templates/.poetic/agents/typescript-pro.md +34 -0
  754. package/templates/.poetic/config/poetic.config.jsonc +69 -0
  755. package/templates/.poetic/config/project-context.template.json +6 -0
  756. package/templates/.poetic/config/task-type-aliases.presets/kanban.yaml +14 -0
  757. package/templates/.poetic/config/task-type-aliases.presets/scrum.yaml +17 -0
  758. package/templates/.poetic/config/task-type-aliases.presets/xp.yaml +12 -0
  759. package/templates/.poetic/config/task-type-aliases.yaml +28 -0
  760. package/templates/.poetic/gitignore.template +55 -0
  761. package/templates/.poetic/task-types/analysis.yaml +40 -0
  762. package/templates/.poetic/task-types/architecture.yaml +38 -0
  763. package/templates/.poetic/task-types/doc.yaml +35 -0
  764. package/templates/.poetic/task-types/feature.yaml +23 -0
  765. package/templates/.poetic/task-types/general.yaml +6 -0
  766. package/templates/.poetic/task-types/security.yaml +39 -0
  767. package/templates/AGENTS.template.md +99 -0
  768. package/templates/CLAUDE.template.md +1 -0
  769. package/templates/GEMINI.template.md +1 -0
  770. package/templates/builtin-workflows/code-review.yaml +73 -0
  771. package/templates/builtin-workflows/compete-streak.yaml +78 -0
  772. package/templates/builtin-workflows/hello-verify.yaml +10 -0
  773. package/templates/builtin-workflows/judge-regression.yaml +114 -0
  774. package/templates/builtin-workflows/skills/code-review/SKILL.md +60 -0
  775. package/templates/builtin-workflows/skills/hello-verify/SKILL.md +6 -0
  776. package/templates/guard-kit/GUARD_SETUP.md.template +255 -0
  777. package/templates/guard-kit/check.mjs.template +777 -0
  778. package/templates/guard-kit/config.json.template +6 -0
  779. package/templates/guard-kit/poetic-guard.yml.template +189 -0
  780. package/templates/profiles/README.md +56 -0
  781. package/templates/profiles/frontier-claude.json +27 -0
  782. package/templates/profiles/frontier-codex.json +26 -0
@@ -0,0 +1,2904 @@
1
+ import {
2
+ extractChangedFilesMeta
3
+ } from "./chunk-CFBIG37O.js";
4
+ import {
5
+ hasRecordedTestExecutionEvidence,
6
+ hasUnrecognizedRecordedTestStatus,
7
+ normalizeRecordedTestStatus
8
+ } from "./chunk-KT6VHSPF.js";
9
+ import {
10
+ stripAnsiSequences
11
+ } from "./chunk-VTW7HP3R.js";
12
+ import {
13
+ changedFilesRequireVerification,
14
+ resolveVerificationChannelScope,
15
+ selectScopedTestCommands
16
+ } from "./chunk-KP6YILMU.js";
17
+ import {
18
+ extractDiffText
19
+ } from "./chunk-ETYDXCK7.js";
20
+ import {
21
+ JUDGE_FEATURE_FLAGS
22
+ } from "./chunk-BSE4R6XD.js";
23
+ import {
24
+ createVerificationCommandEnv,
25
+ runVerificationCommand
26
+ } from "./chunk-D5RYINO7.js";
27
+ import {
28
+ detectProjectCapabilities,
29
+ hasProjectLanguage
30
+ } from "./chunk-FHOWVDF5.js";
31
+ import {
32
+ isProjectTestPath,
33
+ languageForProjectPath
34
+ } from "./chunk-UDMS5AD3.js";
35
+ import {
36
+ tailLines,
37
+ truncateToByteLimit
38
+ } from "./chunk-TSXGRLPR.js";
39
+ import {
40
+ describeVerificationCommand,
41
+ detectExitZeroVerifyFailure,
42
+ detectVerificationToolUnavailable,
43
+ detectZeroCollectedTests,
44
+ isPythonStdlibUnittestCommand,
45
+ resolveVerificationExitCode,
46
+ selectFallbacksForCommand
47
+ } from "./chunk-2QLYTVYX.js";
48
+
49
+ // src/core/judge/lint-on-diff.ts
50
+ function isTimeoutLike(error) {
51
+ return error.timedOut === true || error.killed === true || error.signal === "SIGTERM";
52
+ }
53
+ function isToolUnavailable(exitCode, output, error) {
54
+ const normalized = output.toLowerCase();
55
+ return error?.code === "ENOENT" || exitCode === 127 || normalized.includes("command not found") || normalized.includes("not recognized as an internal or external command") || normalized.includes("no such file or directory");
56
+ }
57
+ function verificationCoverageForLint(params) {
58
+ if (params.error && isTimeoutLike(params.error)) {
59
+ return {
60
+ status: "unverified",
61
+ command: params.command,
62
+ reason: "Lint command timed out or was interrupted."
63
+ };
64
+ }
65
+ if (isToolUnavailable(params.exitCode, params.output, params.error)) {
66
+ return {
67
+ status: "skipped_tool_unavailable",
68
+ command: params.command,
69
+ reason: "Lint command was unavailable in the execution environment."
70
+ };
71
+ }
72
+ return { status: "verified", command: params.command };
73
+ }
74
+ function errorMessage(error) {
75
+ if (error instanceof Error) return error.message;
76
+ if (typeof error === "object" && error !== null && "message" in error) {
77
+ return String(error.message);
78
+ }
79
+ return String(error);
80
+ }
81
+ function extractJsonObject(text) {
82
+ const raw = String(text ?? "").trim();
83
+ if (!raw) return null;
84
+ const start = raw.indexOf("{");
85
+ const end = raw.lastIndexOf("}");
86
+ if (start < 0 || end < 0 || end <= start) return null;
87
+ const candidate = raw.slice(start, end + 1);
88
+ try {
89
+ return { text: candidate, parsed: JSON.parse(candidate) };
90
+ } catch {
91
+ return null;
92
+ }
93
+ }
94
+ function formatBiomeDiagnosticSummary(extracted) {
95
+ if (!extracted) return "";
96
+ try {
97
+ const json = extracted.parsed;
98
+ const diagnostics = Array.isArray(json?.diagnostics) ? json.diagnostics : [];
99
+ const lines = [];
100
+ for (const diag of diagnostics) {
101
+ const loc = diag?.location;
102
+ const filePath = loc?.path;
103
+ if (typeof filePath !== "string" || filePath.trim().length === 0) continue;
104
+ const span = loc?.span;
105
+ const start = span?.start;
106
+ const line = typeof start?.line === "number" ? start.line : 1;
107
+ const column = typeof start?.column === "number" ? start.column : 1;
108
+ const category = typeof diag?.category === "string" ? diag.category : typeof diag?.code === "string" ? diag.code : typeof diag?.rule === "string" ? diag.rule : typeof diag?.severity === "string" ? diag.severity : "issue";
109
+ lines.push(`${filePath}:${line}:${column} ${category}`);
110
+ }
111
+ return lines.length > 0 ? lines.slice(0, 200).join("\n") : "";
112
+ } catch {
113
+ return "";
114
+ }
115
+ }
116
+ function isBiomeLintCommand(command) {
117
+ return /\bbiome\s+check\b/.test(command);
118
+ }
119
+ function appendBiomeSinceArg(command, baseBranch) {
120
+ if (!baseBranch || !isBiomeLintCommand(command) || !command.includes("--changed")) {
121
+ return command;
122
+ }
123
+ if (command.includes("--since=")) {
124
+ return command;
125
+ }
126
+ if (!/^[A-Za-z0-9._/-]+$/.test(baseBranch) || baseBranch.startsWith("-")) {
127
+ return command;
128
+ }
129
+ return command.replace(/\s--changed(?=\s|$)/, ` --changed --since=${baseBranch}`);
130
+ }
131
+ function buildBiomeArtifactResult(params) {
132
+ const extracted = extractJsonObject(params.stdoutRaw) ?? extractJsonObject(params.combined);
133
+ const jsonCandidateText = extracted?.text ?? params.stdoutRaw;
134
+ const diagnosticSummary = formatBiomeDiagnosticSummary(
135
+ extracted ?? (jsonCandidateText ? { text: jsonCandidateText, parsed: void 0 } : null)
136
+ );
137
+ const outputTail = truncateToByteLimit(
138
+ [diagnosticSummary, tailLines(params.combined, params.maxTailLines)].filter(Boolean).join("\n"),
139
+ 1e5
140
+ );
141
+ const parsed = params.exitCode === 0 || params.exitCode === 1 ? parseBiomeOutput(jsonCandidateText, params.exitCode, extracted?.parsed) : null;
142
+ const noopLint = params.combined.includes("No files were processed") || params.combined.includes("No files were processed in the specified paths");
143
+ return {
144
+ exitCode: noopLint ? 0 : params.exitCode,
145
+ outputTail,
146
+ result: noopLint || params.exitCode === 0 && (!params.stdoutRaw.trim() || parsed === null) ? {
147
+ success: true,
148
+ errorCount: 0,
149
+ warningCount: 0,
150
+ fixableCount: 0,
151
+ filesWithIssues: [],
152
+ exitCode: 0
153
+ } : parsed,
154
+ verificationCoverage: {
155
+ status: noopLint ? "skipped_not_relevant" : "verified",
156
+ command: params.command
157
+ }
158
+ };
159
+ }
160
+ async function runLintOnDiffWithArtifacts(workingDirectory, options) {
161
+ const start = Date.now();
162
+ const timeoutMs = options?.timeoutMs;
163
+ const maxTailLines = options?.tailLines ?? 200;
164
+ if (options?.command && options.command.trim().length > 0) {
165
+ const scopedCommand = options.command;
166
+ const scopedLanguage = describeVerificationCommand(scopedCommand).language;
167
+ try {
168
+ const result = await runVerificationCommand(scopedCommand, {
169
+ cwd: workingDirectory,
170
+ timeoutMs,
171
+ abortSignal: options?.abortSignal
172
+ });
173
+ const { exitCode: resolvedExitCode } = resolveVerificationExitCode(scopedCommand, result);
174
+ const rawOutput = String(result.all ?? "");
175
+ const exitZeroFailure = resolvedExitCode === 0 ? detectExitZeroVerifyFailure(scopedCommand, rawOutput)?.message : void 0;
176
+ const exitCode = exitZeroFailure ? 1 : resolvedExitCode;
177
+ const output = exitZeroFailure ? `${rawOutput}
178
+ ${exitZeroFailure}`.trim() : rawOutput;
179
+ return {
180
+ command: scopedCommand,
181
+ exitCode,
182
+ durationMs: Date.now() - start,
183
+ outputTail: truncateToByteLimit(tailLines(output, maxTailLines), 1e5),
184
+ result: {
185
+ success: exitCode === 0,
186
+ errorCount: exitCode === 0 ? 0 : 1,
187
+ warningCount: 0,
188
+ fixableCount: 0,
189
+ filesWithIssues: [],
190
+ exitCode
191
+ },
192
+ verificationCoverage: verificationCoverageForLint({
193
+ command: scopedCommand,
194
+ exitCode,
195
+ output
196
+ }),
197
+ language: scopedLanguage
198
+ };
199
+ } catch (error) {
200
+ const err = error;
201
+ const message = errorMessage(error);
202
+ const timedOut = isTimeoutLike(err);
203
+ const exitCode = timedOut ? 124 : 1;
204
+ return {
205
+ command: scopedCommand,
206
+ exitCode,
207
+ durationMs: Date.now() - start,
208
+ outputTail: truncateToByteLimit(tailLines(message, maxTailLines), 1e5),
209
+ result: timedOut ? null : {
210
+ success: false,
211
+ errorCount: 1,
212
+ warningCount: 0,
213
+ fixableCount: 0,
214
+ filesWithIssues: [],
215
+ exitCode
216
+ },
217
+ verificationCoverage: verificationCoverageForLint({
218
+ command: scopedCommand,
219
+ exitCode,
220
+ output: message,
221
+ error: err
222
+ }),
223
+ language: scopedLanguage
224
+ };
225
+ }
226
+ }
227
+ const detectedProjectLintCommand = detectProjectCapabilities(workingDirectory).verification.lint[0];
228
+ const projectLintCommand = detectedProjectLintCommand ? appendBiomeSinceArg(detectedProjectLintCommand, options?.baseBranch) : void 0;
229
+ const projectLintLanguage = projectLintCommand ? describeVerificationCommand(projectLintCommand).language : void 0;
230
+ if (projectLintCommand) {
231
+ try {
232
+ const result = await runVerificationCommand(projectLintCommand, {
233
+ cwd: workingDirectory,
234
+ timeoutMs,
235
+ abortSignal: options?.abortSignal
236
+ });
237
+ const { exitCode: resolvedExitCode } = resolveVerificationExitCode(
238
+ projectLintCommand,
239
+ result
240
+ );
241
+ const rawOutput = String(result.all ?? "");
242
+ const exitZeroFailure = resolvedExitCode === 0 ? detectExitZeroVerifyFailure(projectLintCommand, rawOutput)?.message : void 0;
243
+ const exitCode = exitZeroFailure ? 1 : resolvedExitCode;
244
+ const output = exitZeroFailure ? `${rawOutput}
245
+ ${exitZeroFailure}`.trim() : rawOutput;
246
+ if (isBiomeLintCommand(projectLintCommand)) {
247
+ const biomeArtifact = buildBiomeArtifactResult({
248
+ command: projectLintCommand,
249
+ exitCode,
250
+ durationMs: Date.now() - start,
251
+ combined: output,
252
+ stdoutRaw: String(result.stdout ?? result.all ?? ""),
253
+ maxTailLines
254
+ });
255
+ return {
256
+ command: projectLintCommand,
257
+ durationMs: Date.now() - start,
258
+ ...biomeArtifact,
259
+ language: projectLintLanguage
260
+ };
261
+ }
262
+ return {
263
+ command: projectLintCommand,
264
+ exitCode,
265
+ durationMs: Date.now() - start,
266
+ outputTail: truncateToByteLimit(tailLines(output, maxTailLines), 1e5),
267
+ result: {
268
+ success: exitCode === 0,
269
+ errorCount: exitCode === 0 ? 0 : 1,
270
+ warningCount: 0,
271
+ fixableCount: 0,
272
+ filesWithIssues: [],
273
+ exitCode
274
+ },
275
+ verificationCoverage: verificationCoverageForLint({
276
+ command: projectLintCommand,
277
+ exitCode,
278
+ output
279
+ }),
280
+ language: projectLintLanguage
281
+ };
282
+ } catch (error) {
283
+ const err = error;
284
+ const message = errorMessage(error);
285
+ const timedOut = isTimeoutLike(err);
286
+ const exitCode = timedOut ? 124 : 1;
287
+ return {
288
+ command: projectLintCommand,
289
+ exitCode,
290
+ durationMs: Date.now() - start,
291
+ outputTail: truncateToByteLimit(tailLines(message, maxTailLines), 1e5),
292
+ result: timedOut ? null : {
293
+ success: false,
294
+ errorCount: 1,
295
+ warningCount: 0,
296
+ fixableCount: 0,
297
+ filesWithIssues: [],
298
+ exitCode
299
+ },
300
+ verificationCoverage: verificationCoverageForLint({
301
+ command: projectLintCommand,
302
+ exitCode,
303
+ output: message,
304
+ error: err
305
+ }),
306
+ language: projectLintLanguage
307
+ };
308
+ }
309
+ }
310
+ const outputTail = "Skipped lint gate: no project lint command detected by resolver.";
311
+ const skippedCommand = "lint (not configured)";
312
+ return {
313
+ command: skippedCommand,
314
+ exitCode: 127,
315
+ durationMs: Date.now() - start,
316
+ outputTail,
317
+ result: null,
318
+ verificationCoverage: {
319
+ status: "skipped_no_command",
320
+ command: skippedCommand,
321
+ reason: "No project lint command was detected by the capabilities resolver."
322
+ },
323
+ language: "unknown"
324
+ };
325
+ }
326
+ function parseBiomeOutput(output, exitCode, preParsed) {
327
+ try {
328
+ const json = preParsed !== void 0 ? preParsed : JSON.parse(output);
329
+ const summary = json.summary ?? {};
330
+ const errorCount = summary.errors ?? 0;
331
+ const warningCount = summary.warnings ?? 0;
332
+ const diagnostics = json.diagnostics ?? [];
333
+ const filesWithIssues = Array.from(
334
+ new Set(
335
+ diagnostics.map((d) => d.location?.path).filter((path2) => Boolean(path2))
336
+ )
337
+ );
338
+ const fixableCount = diagnostics.filter((d) => d.canFix === true).length;
339
+ return {
340
+ success: exitCode === 0,
341
+ errorCount,
342
+ warningCount,
343
+ fixableCount,
344
+ filesWithIssues,
345
+ exitCode,
346
+ rawOutput: output
347
+ };
348
+ } catch (_parseError) {
349
+ console.debug("[lint-on-diff] Failed to parse Biome JSON, returning null");
350
+ return null;
351
+ }
352
+ }
353
+
354
+ // src/core/project/poetic-vitest-harness.ts
355
+ import { existsSync } from "fs";
356
+ import path from "path";
357
+ function hasPoeticVitestHarness(root) {
358
+ return existsSync(path.join(root, "scripts", "dynamic-node-options.mjs"));
359
+ }
360
+ function displayArg(value) {
361
+ return /[\s"'\\]/.test(value) ? JSON.stringify(value) : value;
362
+ }
363
+ function buildExternalVitestRunInvocation(args = []) {
364
+ const commandArgs = ["--no-install", "vitest", "run", ...args, "--reporter=verbose"];
365
+ return {
366
+ display: ["npx", ...commandArgs].map(displayArg).join(" "),
367
+ cmd: "npx",
368
+ args: commandArgs
369
+ };
370
+ }
371
+
372
+ // src/core/judge/test-gate.ts
373
+ import { existsSync as existsSync2, readdirSync, readFileSync } from "fs";
374
+ import { dirname, extname, join, posix as pathPosix, relative, resolve, sep } from "path";
375
+ import { execa } from "execa";
376
+ var DEFAULT_CONFIG = {
377
+ timeout: 12e4,
378
+ testFilePatterns: [
379
+ /\.(test|spec)\.(ts|js|tsx|jsx)$/,
380
+ /__tests__\/.*\.(ts|js|tsx|jsx)$/,
381
+ /(^|\/)test_.*\.py$/,
382
+ /(^|\/).*_test\.py$/,
383
+ /_test\.go$/,
384
+ /(^|\/)tests\/.*\.rs$/,
385
+ /\.tests\.ps1$/i
386
+ ]
387
+ };
388
+ var TEST_DISCOVERY_ROOTS = ["tests", "test", "src"];
389
+ var SKIPPED_TEST_DISCOVERY_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", ".poetic", "dist", "build"]);
390
+ var SOURCE_FILE_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mts", ".cts", ".mjs", ".cjs"];
391
+ var JS_LIKE_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".jsx", ".mjs", ".cjs"]);
392
+ var MULTI_COMMAND_TEST_BUDGET_MS = 12e4;
393
+ function createVerificationTestEnv() {
394
+ return createVerificationCommandEnv();
395
+ }
396
+ function extractFailingTestsFromVitestOutput(output) {
397
+ if (!output) return [];
398
+ const names = /* @__PURE__ */ new Set();
399
+ const failHeader = /^\s*FAIL\s+(.+?)\s+>\s+(.+)$/gm;
400
+ let match = failHeader.exec(output);
401
+ while (match !== null) {
402
+ const remainder = (match[2] ?? "").trim();
403
+ if (remainder) names.add(remainder);
404
+ match = failHeader.exec(output);
405
+ }
406
+ const cross = /^\s*[×]\s+(.+?)(?:\s+\(\d+ms\))?\s*$/gm;
407
+ let crossMatch = cross.exec(output);
408
+ while (crossMatch !== null) {
409
+ const name = (crossMatch[1] ?? "").trim();
410
+ if (name) names.add(name);
411
+ crossMatch = cross.exec(output);
412
+ }
413
+ return Array.from(names).slice(0, 20);
414
+ }
415
+ function asMeasuredMetrics(metrics) {
416
+ return { ...metrics, metricsMeasured: metrics.testsRun > 0 };
417
+ }
418
+ function inferSuccessStatusFromMetrics(metrics) {
419
+ if (metrics.testsRun === 0) {
420
+ return "error";
421
+ }
422
+ return metrics.testsFailed === 0 ? "passed" : "failed";
423
+ }
424
+ function inferSuccessStatusForRunner(_runner, metrics) {
425
+ return inferSuccessStatusFromMetrics(metrics);
426
+ }
427
+ function isPoeticSuiteSkipOutput(command, output) {
428
+ if (!/skipping\s+tests/i.test(output)) return false;
429
+ const normalizedCommand = command ?? "";
430
+ return /\bnpm\s+run\s+test:(?:fast|changed)\b/.test(normalizedCommand) || normalizedCommand.includes("scripts/dynamic-node-options.mjs");
431
+ }
432
+ function fullProvenanceCoversRequiredCommands(testsExecuted, worktreePath, changedFiles) {
433
+ if (changedFiles.length === 0) return true;
434
+ const changedLanguages = changedProjectLanguages(changedFiles);
435
+ if (changedLanguages.size === 0 && !changedFilesRequireVerification(changedFiles)) {
436
+ return true;
437
+ }
438
+ const scope = resolveVerificationChannelScope(worktreePath, changedFiles);
439
+ const testScope = scope.test;
440
+ if (testScope.availability === "unavailable") {
441
+ return false;
442
+ }
443
+ const required = testScope.availability === "relevant" ? selectScopedTestCommands(scope) : [];
444
+ if (required.length === 0) return true;
445
+ const recorded = testsExecuted.commands;
446
+ if (!recorded || recorded.length === 0) return false;
447
+ const recordedSet = new Set(recorded);
448
+ return required.every((command) => recordedSet.has(command));
449
+ }
450
+ function canReuseRecordedProvenance(testsExecuted, mode, worktreePath, changedFiles) {
451
+ if (testsExecuted.scope === "none") return false;
452
+ if (mode !== "full") return true;
453
+ if (testsExecuted.scope !== "full") return false;
454
+ return fullProvenanceCoversRequiredCommands(testsExecuted, worktreePath, changedFiles);
455
+ }
456
+ async function executeRequiredTestCommands(worktreePath, commands, options) {
457
+ const abortSignal = options?.abortSignal;
458
+ const scope = options?.scope ?? "full";
459
+ const startedAt = Date.now();
460
+ const artifacts = [];
461
+ const fallbacks = detectProjectCapabilities(worktreePath).verification.testFallback ?? [];
462
+ const coveredPrimaries = [];
463
+ for (const command of commands) {
464
+ if (abortSignal?.aborted) {
465
+ break;
466
+ }
467
+ const remaining = Math.max(0, MULTI_COMMAND_TEST_BUDGET_MS - (Date.now() - startedAt));
468
+ if (remaining <= 0) {
469
+ artifacts.push({
470
+ command,
471
+ exitCode: 124,
472
+ durationMs: 0,
473
+ outputTail: "Test command skipped: shared multi-command timeout budget exhausted.",
474
+ status: "timeout",
475
+ failingTests: []
476
+ });
477
+ continue;
478
+ }
479
+ const commandStart = Date.now();
480
+ artifacts.push(
481
+ await runCapabilityTestCommandWithFallback(worktreePath, command, fallbacks, {
482
+ timeoutMs: remaining,
483
+ tailLines: 200,
484
+ start: commandStart,
485
+ abortSignal
486
+ })
487
+ );
488
+ coveredPrimaries.push(command);
489
+ if (abortSignal?.aborted) break;
490
+ }
491
+ if (abortSignal?.aborted && artifacts.length !== commands.length) {
492
+ return {
493
+ testStatus: "error",
494
+ availability: "executed",
495
+ testsRun: 0,
496
+ testsPassed: 0,
497
+ testsFailed: 0,
498
+ metricsAvailable: false,
499
+ duration: Date.now() - startedAt,
500
+ filesTested: [],
501
+ command: artifacts.map((artifact) => artifact.command).join("\n"),
502
+ commands: coveredPrimaries,
503
+ scope,
504
+ exitCode: 130,
505
+ outputTail: "Test verification aborted before every selected command completed.",
506
+ failingTests: []
507
+ };
508
+ }
509
+ const combined = combineVitestPlanResults(artifacts);
510
+ const capabilityRunner = detectTestRunner(worktreePath) ?? "generic";
511
+ const commandMetrics = artifacts.map(
512
+ (artifact) => (
513
+ // Per-artifact runner: a multi-command plan can mix toolchains, and the
514
+ // project-wide runner id would parse a stdlib-unittest tail with the wrong
515
+ // parser (in a polyglot repo detectTestRunner reports the Node runner).
516
+ parseTestOutput(
517
+ resolveArtifactMetricRunner(artifact.command, capabilityRunner),
518
+ artifact.outputTail
519
+ )
520
+ )
521
+ );
522
+ const metrics = commandMetrics.reduce(
523
+ (total, current) => ({
524
+ testsRun: total.testsRun + current.testsRun,
525
+ testsPassed: total.testsPassed + current.testsPassed,
526
+ testsFailed: total.testsFailed + current.testsFailed
527
+ }),
528
+ { testsRun: 0, testsPassed: 0, testsFailed: 0 }
529
+ );
530
+ const metricsAvailable = commandMetrics.length > 0 && commandMetrics.every((command) => command.metricsMeasured);
531
+ const combinedUnavailable = combined.status === "unavailable" || combined.status === "passed" && !metricsAvailable;
532
+ return {
533
+ testStatus: combinedUnavailable ? "not_run" : combined.status === "passed" ? "passed" : combined.status === "timeout" ? "timeout" : combined.status === "unavailable" ? "not_run" : combined.status === "error" ? "error" : "failed",
534
+ availability: combinedUnavailable ? "unavailable" : "executed",
535
+ ...combinedUnavailable ? { skipReason: "no-supported-test-runner" } : {},
536
+ testsRun: metrics.testsRun,
537
+ testsPassed: metrics.testsPassed,
538
+ testsFailed: metrics.testsFailed,
539
+ metricsAvailable,
540
+ duration: Date.now() - startedAt,
541
+ filesTested: [],
542
+ // Display/audit: actual commands that ran (may be approved fallbacks).
543
+ command: combined.command,
544
+ // Structured coverage: resolver primaries for completed plan steps only.
545
+ commands: coveredPrimaries,
546
+ scope,
547
+ exitCode: combinedUnavailable ? void 0 : combined.exitCode,
548
+ outputTail: combined.outputTail,
549
+ failingTests: combined.failingTests
550
+ };
551
+ }
552
+ async function runTestGate(variant, worktreePath, enabledOrOptions) {
553
+ const enabled = typeof enabledOrOptions === "boolean" ? enabledOrOptions : enabledOrOptions.enabled;
554
+ const mode = typeof enabledOrOptions === "boolean" ? "touched" : enabledOrOptions.mode ?? "touched";
555
+ const abortSignal = typeof enabledOrOptions === "boolean" ? void 0 : enabledOrOptions.abortSignal;
556
+ if (!enabled || !JUDGE_FEATURE_FLAGS.TEST_GATE_FOR_TEST_INTENT) {
557
+ return {
558
+ testStatus: "not_run",
559
+ availability: "skipped",
560
+ skipReason: "disabled",
561
+ testsRun: 0,
562
+ testsPassed: 0,
563
+ testsFailed: 0,
564
+ duration: 0,
565
+ filesTested: [],
566
+ command: "",
567
+ scope: "none"
568
+ };
569
+ }
570
+ const recordedChangedFiles = extractChangedFilesMeta(extractDiffText(variant)).map(
571
+ (file) => file.path
572
+ );
573
+ if (variant.testsExecuted && canReuseRecordedProvenance(variant.testsExecuted, mode, worktreePath, recordedChangedFiles)) {
574
+ const scope = variant.testsExecuted.scope === "targeted" ? "touched" : variant.testsExecuted.scope;
575
+ const exitCode = variant.testsExecuted.exitCode;
576
+ const isEnvCommandFailure = (code) => code === 126 || code === 127;
577
+ const recordedStatus = normalizeRecordedTestStatus(variant.testStatus);
578
+ const inferredStatus = recordedStatus !== void 0 ? recordedStatus : (
579
+ // Fail closed: a status was recorded but is outside the vocabulary Poetic
580
+ // can interpret (VariantResult.testStatus is `... | string`, so a provider
581
+ // vocabulary, a stale value, or a fabricated one all type-check). A bare
582
+ // exit-0 beside such a status is not a pass observation. Failure inference
583
+ // from a non-zero exit is deliberately unchanged — downgrading an observed
584
+ // failure would fail open in the dangerous direction.
585
+ hasUnrecognizedRecordedTestStatus(variant.testStatus) && exitCode === 0 ? "not_run" : exitCode === 0 ? "passed" : exitCode === 124 ? "timeout" : isEnvCommandFailure(exitCode) ? "error" : exitCode === void 0 ? "not_run" : "failed"
586
+ );
587
+ const failedTests = variant.testMetrics?.failedTests ?? 0;
588
+ const totalTests = variant.testMetrics?.totalTests ?? 0;
589
+ const hasExecutionEvidence = hasRecordedTestExecutionEvidence({
590
+ command: variant.testsExecuted.command,
591
+ filesTested: variant.testsExecuted.filesTested,
592
+ totalTests,
593
+ exitCode: variant.testsExecuted.exitCode
594
+ });
595
+ if (!hasExecutionEvidence) {
596
+ if (!existsSync2(worktreePath)) {
597
+ return {
598
+ testStatus: "not_run",
599
+ availability: "skipped",
600
+ skipReason: "no-execution-provenance",
601
+ testsRun: 0,
602
+ testsPassed: 0,
603
+ testsFailed: 0,
604
+ duration: variant.testsExecuted.durationMs ?? variant.testMetrics?.durationMs ?? 0,
605
+ filesTested: [],
606
+ command: "",
607
+ scope: "none",
608
+ exitCode: void 0,
609
+ outputTail: void 0,
610
+ failingTests: [],
611
+ signalConsistency: "consistent"
612
+ };
613
+ }
614
+ } else {
615
+ const normalizedStatus = inferredStatus === "passed" && totalTests === 0 ? "not_run" : inferredStatus;
616
+ const isContradiction = inferredStatus === "failed" && failedTests === 0 && totalTests > 0;
617
+ const signalConsistency = isContradiction ? "inconsistent" : "consistent";
618
+ const recordedCommands = variant.testsExecuted.commands;
619
+ return {
620
+ testStatus: normalizedStatus,
621
+ availability: normalizedStatus === "not_run" ? "unavailable" : "executed",
622
+ skipReason: normalizedStatus === "not_run" ? "no-execution-provenance" : void 0,
623
+ testsRun: normalizedStatus === "not_run" ? 0 : totalTests,
624
+ testsPassed: normalizedStatus === "not_run" ? 0 : variant.testMetrics?.passedTests ?? 0,
625
+ testsFailed: normalizedStatus === "not_run" ? 0 : failedTests,
626
+ // Reused provenance carries no parse provenance of its own, so a recorded
627
+ // count is the only measurement evidence available. Reporting it keeps a
628
+ // zero-count reuse from reading as measured verification downstream.
629
+ ...normalizedStatus === "not_run" ? { metricsAvailable: false } : { metricsAvailable: true },
630
+ duration: variant.testsExecuted.durationMs ?? variant.testMetrics?.durationMs ?? 0,
631
+ filesTested: normalizedStatus === "not_run" ? [] : variant.testsExecuted.filesTested ?? [],
632
+ command: normalizedStatus === "not_run" ? "" : variant.testsExecuted.command ?? "",
633
+ ...normalizedStatus !== "not_run" && recordedCommands && recordedCommands.length > 0 ? { commands: recordedCommands } : {},
634
+ scope,
635
+ exitCode: normalizedStatus === "not_run" ? void 0 : exitCode,
636
+ outputTail: variant.testsExecuted.outputTail,
637
+ failingTests: variant.testsExecuted.failingTests ?? [],
638
+ signalConsistency,
639
+ evidenceSource: "reused_provenance"
640
+ };
641
+ }
642
+ }
643
+ const diffText = extractDiffText(variant);
644
+ const changedTestFiles = getChangedTestFiles(diffText);
645
+ const changedFilesMeta = extractChangedFilesMeta(diffText);
646
+ const changedFiles = changedFilesMeta.map((file) => file.path);
647
+ if (mode === "full") {
648
+ const changedLanguages = changedProjectLanguages(changedFiles);
649
+ if (changedLanguages.size > 0 || changedFilesRequireVerification(changedFiles)) {
650
+ const scope = resolveVerificationChannelScope(worktreePath, changedFiles);
651
+ const commands = scope.test.availability === "relevant" ? selectScopedTestCommands(scope) : [];
652
+ if (commands.length === 0) {
653
+ return {
654
+ testStatus: "not_run",
655
+ availability: "unavailable",
656
+ skipReason: "no-supported-test-runner",
657
+ testsRun: 0,
658
+ testsPassed: 0,
659
+ testsFailed: 0,
660
+ metricsAvailable: false,
661
+ duration: 0,
662
+ filesTested: [],
663
+ command: "",
664
+ scope: "none",
665
+ exitCode: 127,
666
+ outputTail: "Full test verification unavailable: no command covers every changed language.",
667
+ failingTests: []
668
+ };
669
+ }
670
+ return executeRequiredTestCommands(worktreePath, commands, {
671
+ abortSignal,
672
+ scope: "full"
673
+ });
674
+ }
675
+ return executeRequestedSuite(worktreePath, abortSignal);
676
+ }
677
+ {
678
+ const scope = resolveVerificationChannelScope(worktreePath, changedFiles);
679
+ const requiredCommands = scope.test.availability === "relevant" ? selectScopedTestCommands(scope) : [];
680
+ const changedLanguages = changedProjectLanguages(changedFiles);
681
+ if (changedLanguages.size > 1 && requiredCommands.length > 1) {
682
+ return executeRequiredTestCommands(worktreePath, requiredCommands, {
683
+ abortSignal,
684
+ scope: "full"
685
+ });
686
+ }
687
+ }
688
+ const selectedTestFiles = mode === "affected" ? selectTestFilesForAffectedMode(worktreePath, changedFilesMeta, changedTestFiles) : selectTestFilesForTouchedMode(worktreePath, changedFilesMeta, changedTestFiles);
689
+ const runner = detectTestRunner(worktreePath);
690
+ if (selectedTestFiles.files.length === 0) {
691
+ if (shouldRunFullSuiteForUnmappedSourceChange(runner, changedFilesMeta)) {
692
+ return executeRequestedSuite(worktreePath, abortSignal);
693
+ }
694
+ return {
695
+ testStatus: "not_run",
696
+ availability: "skipped",
697
+ skipReason: "no-test-files-selected",
698
+ testsRun: 0,
699
+ testsPassed: 0,
700
+ testsFailed: 0,
701
+ duration: 0,
702
+ filesTested: [],
703
+ command: "",
704
+ scope: "none"
705
+ };
706
+ }
707
+ if (!runner) {
708
+ return {
709
+ testStatus: "not_run",
710
+ availability: "unavailable",
711
+ skipReason: "no-supported-test-runner",
712
+ testsRun: 0,
713
+ testsPassed: 0,
714
+ testsFailed: 0,
715
+ duration: 0,
716
+ filesTested: [],
717
+ command: "",
718
+ scope: selectedTestFiles.scope,
719
+ exitCode: void 0,
720
+ outputTail: "Skipped test gate: no supported test runner detected from project manifests.",
721
+ failingTests: []
722
+ };
723
+ }
724
+ const scopedNodeInvocation = runner === "vitest" || runner === "jest" || runner === "mocha" || runner === "ava" || runner === "node-test" ? resolveScopedNodeTestInvocation(runner, selectedTestFiles.files, worktreePath) : void 0;
725
+ if ((runner === "vitest" || runner === "jest" || runner === "mocha" || runner === "ava" || runner === "node-test") && !scopedNodeInvocation) {
726
+ return {
727
+ testStatus: "not_run",
728
+ availability: "unavailable",
729
+ skipReason: "no-supported-test-runner",
730
+ testsRun: 0,
731
+ testsPassed: 0,
732
+ testsFailed: 0,
733
+ duration: 0,
734
+ filesTested: [],
735
+ command: "",
736
+ scope: selectedTestFiles.scope,
737
+ exitCode: void 0,
738
+ outputTail: "Skipped test gate: no safely scoped or declared project test command is available.",
739
+ failingTests: []
740
+ };
741
+ }
742
+ const unscopedFullSuiteRunner = runner === "maven" || runner === "gradle" || runner === "unittest";
743
+ const executionScope = unscopedFullSuiteRunner || scopedNodeInvocation?.scope === "full" ? "full" : selectedTestFiles.scope;
744
+ const testCommand = scopedNodeInvocation?.display ?? buildTestCommand(runner, selectedTestFiles.files, worktreePath);
745
+ const result = await executeTests(
746
+ runner,
747
+ selectedTestFiles.files,
748
+ worktreePath,
749
+ abortSignal,
750
+ scopedNodeInvocation
751
+ );
752
+ const unavailableSignal = detectVerificationToolUnavailable(testCommand, result.outputTail ?? "");
753
+ if (result.status === "unavailable") {
754
+ return {
755
+ testStatus: "not_run",
756
+ availability: "unavailable",
757
+ skipReason: "no-matching-tests",
758
+ testsRun: 0,
759
+ testsPassed: 0,
760
+ testsFailed: 0,
761
+ duration: result.duration,
762
+ filesTested: [],
763
+ command: testCommand,
764
+ scope: executionScope,
765
+ exitCode: void 0,
766
+ outputTail: result.outputTail,
767
+ failingTests: []
768
+ };
769
+ }
770
+ const resultUnavailable = result.status === "error" && result.testsRun === 0 && (result.exitCode === 126 || result.exitCode === 127 || /\b(?:ENOENT|command not found)\b/i.test(result.outputTail ?? "") || unavailableSignal !== void 0);
771
+ return {
772
+ testStatus: resultUnavailable ? "not_run" : result.status,
773
+ availability: resultUnavailable ? "unavailable" : "executed",
774
+ skipReason: resultUnavailable ? "no-supported-test-runner" : void 0,
775
+ testsRun: result.testsRun,
776
+ testsPassed: result.testsPassed,
777
+ testsFailed: result.testsFailed,
778
+ // Carry the measurement flag on the executed path too: previously only the
779
+ // suite/multi-command paths set it, so a scoped run's unmeasured counts
780
+ // reached consumers as if they had been parsed.
781
+ ...resultUnavailable ? {} : { metricsAvailable: result.metricsMeasured },
782
+ duration: result.duration,
783
+ filesTested: executionScope === "full" ? [] : selectedTestFiles.files,
784
+ command: testCommand,
785
+ scope: executionScope,
786
+ exitCode: resultUnavailable ? void 0 : result.exitCode,
787
+ outputTail: resultUnavailable && unavailableSignal ? truncateToByteLimit(
788
+ [result.outputTail, unavailableSignal.message].filter(Boolean).join("\n"),
789
+ 1e5
790
+ ) : result.outputTail,
791
+ failingTests: result.failingTests
792
+ };
793
+ }
794
+ async function executeRequestedSuite(worktreePath, abortSignal) {
795
+ const startTime = Date.now();
796
+ const suiteCommand = detectSuiteCommand(worktreePath);
797
+ if (!suiteCommand) {
798
+ return {
799
+ testStatus: "not_run",
800
+ availability: "unavailable",
801
+ skipReason: "no-supported-test-runner",
802
+ testsRun: 0,
803
+ testsPassed: 0,
804
+ testsFailed: 0,
805
+ duration: 0,
806
+ filesTested: [],
807
+ command: "",
808
+ scope: "full",
809
+ exitCode: void 0,
810
+ outputTail: "No test suite command detected (package.json missing or no supported runner/scripts)",
811
+ failingTests: []
812
+ };
813
+ }
814
+ const { display, cmd, args, timeoutMs, runner } = suiteCommand;
815
+ try {
816
+ const result = await execa(cmd, args, {
817
+ cwd: worktreePath,
818
+ stdio: "pipe",
819
+ all: true,
820
+ reject: false,
821
+ timeout: timeoutMs,
822
+ env: createVerificationTestEnv(),
823
+ extendEnv: false,
824
+ cancelSignal: abortSignal
825
+ });
826
+ const duration = Date.now() - startTime;
827
+ const { exitCode } = resolveVerificationExitCode(display, result);
828
+ const all = String(result.all ?? "");
829
+ const outputTail = truncateToByteLimit(tailLines(all, 200), 1e5);
830
+ if (isPoeticSuiteSkipOutput(display, all)) {
831
+ return {
832
+ testStatus: "not_run",
833
+ availability: "skipped",
834
+ skipReason: "suite-command-skipped",
835
+ testsRun: 0,
836
+ testsPassed: 0,
837
+ testsFailed: 0,
838
+ duration,
839
+ filesTested: [],
840
+ command: display,
841
+ scope: "none",
842
+ exitCode: void 0,
843
+ outputTail,
844
+ failingTests: []
845
+ };
846
+ }
847
+ if (exitCode === 0 && detectZeroCollectedTests(
848
+ runner === "maven" ? "mvn test" : runner === "gradle" ? "gradle test" : display,
849
+ all
850
+ )) {
851
+ return {
852
+ testStatus: "not_run",
853
+ availability: "unavailable",
854
+ skipReason: "no-matching-tests",
855
+ testsRun: 0,
856
+ testsPassed: 0,
857
+ testsFailed: 0,
858
+ duration,
859
+ filesTested: [],
860
+ command: display,
861
+ scope: "full",
862
+ exitCode: void 0,
863
+ outputTail,
864
+ failingTests: []
865
+ };
866
+ }
867
+ const failingTests = exitCode === 0 ? [] : runner === "vitest" ? extractFailingTestsFromVitestOutput(all) : extractGenericFailures(all);
868
+ const metrics = parseTestOutput(resolveArtifactMetricRunner(display, runner), all);
869
+ if (exitCode === 1 && /No test files found/i.test(all)) {
870
+ return {
871
+ testStatus: "not_run",
872
+ availability: "unavailable",
873
+ skipReason: "no-matching-tests",
874
+ testsRun: 0,
875
+ testsPassed: 0,
876
+ testsFailed: 0,
877
+ duration,
878
+ filesTested: [],
879
+ command: display,
880
+ scope: "full",
881
+ exitCode: void 0,
882
+ outputTail,
883
+ failingTests: []
884
+ };
885
+ }
886
+ const unavailableSignal = detectVerificationToolUnavailable(display, all);
887
+ if (unavailableSignal) {
888
+ return {
889
+ testStatus: "not_run",
890
+ availability: "unavailable",
891
+ skipReason: "no-supported-test-runner",
892
+ testsRun: 0,
893
+ testsPassed: 0,
894
+ testsFailed: 0,
895
+ duration,
896
+ filesTested: [],
897
+ command: display,
898
+ scope: "full",
899
+ exitCode: void 0,
900
+ outputTail: truncateToByteLimit(
901
+ [outputTail, unavailableSignal.message].filter(Boolean).join("\n"),
902
+ 1e5
903
+ ),
904
+ failingTests: []
905
+ };
906
+ }
907
+ const exitZeroFailure = exitCode === 0 ? detectExitZeroVerifyFailure(display, all) : void 0;
908
+ if (exitZeroFailure) {
909
+ return {
910
+ testStatus: "failed",
911
+ availability: "executed",
912
+ testsRun: metrics.testsRun,
913
+ testsPassed: metrics.testsPassed,
914
+ testsFailed: Math.max(metrics.testsFailed, 1),
915
+ duration,
916
+ filesTested: [],
917
+ command: display,
918
+ scope: "full",
919
+ exitCode: 1,
920
+ outputTail: truncateToByteLimit(
921
+ [outputTail, exitZeroFailure.message].filter(Boolean).join("\n"),
922
+ 1e5
923
+ ),
924
+ failingTests: [exitZeroFailure.message]
925
+ };
926
+ }
927
+ if (exitCode === 0) {
928
+ if (!metrics.metricsMeasured && metrics.testsFailed === 0) {
929
+ return {
930
+ testStatus: "not_run",
931
+ availability: "unavailable",
932
+ skipReason: "no-supported-test-runner",
933
+ testsRun: 0,
934
+ testsPassed: 0,
935
+ testsFailed: 0,
936
+ metricsAvailable: false,
937
+ duration,
938
+ filesTested: [],
939
+ command: display,
940
+ scope: "full",
941
+ exitCode: void 0,
942
+ outputTail,
943
+ failingTests: []
944
+ };
945
+ }
946
+ const testStatus = inferSuccessStatusForRunner(runner, metrics);
947
+ const metricsAvailable = metrics.metricsMeasured;
948
+ return {
949
+ testStatus,
950
+ availability: "executed",
951
+ testsRun: metrics.testsRun,
952
+ testsPassed: metrics.testsPassed,
953
+ testsFailed: metrics.testsFailed,
954
+ metricsAvailable,
955
+ duration,
956
+ filesTested: [],
957
+ command: display,
958
+ scope: "full",
959
+ // DERIVED, not observed: failure prose on a clean process exit remains a
960
+ // non-zero verification result so exit-code-first consumers cannot launder
961
+ // it into a pass.
962
+ exitCode: testStatus === "passed" ? exitCode : 1,
963
+ outputTail,
964
+ failingTests
965
+ };
966
+ }
967
+ if (exitCode === 124) {
968
+ return {
969
+ testStatus: "timeout",
970
+ availability: "executed",
971
+ testsRun: metrics.testsRun,
972
+ testsPassed: metrics.testsPassed,
973
+ testsFailed: metrics.testsFailed,
974
+ duration,
975
+ filesTested: [],
976
+ command: display,
977
+ scope: "full",
978
+ exitCode,
979
+ outputTail,
980
+ failingTests
981
+ };
982
+ }
983
+ return {
984
+ testStatus: "failed",
985
+ availability: "executed",
986
+ testsRun: metrics.testsRun,
987
+ testsPassed: metrics.testsPassed,
988
+ testsFailed: metrics.testsFailed,
989
+ duration,
990
+ filesTested: [],
991
+ command: display,
992
+ scope: "full",
993
+ exitCode,
994
+ outputTail,
995
+ failingTests
996
+ };
997
+ } catch (error) {
998
+ const err = error;
999
+ const duration = Date.now() - startTime;
1000
+ const output = String(err?.all ?? err?.stdout ?? err?.stderr ?? err?.message ?? "");
1001
+ const isNotFound = err?.code === "ENOENT" || /\bENOENT\b/i.test(output) || /command not found/i.test(output);
1002
+ const isTimedOut = Boolean(err?.timedOut) || err?.killed && err?.signal === "SIGTERM";
1003
+ if (isNotFound) {
1004
+ return {
1005
+ testStatus: "error",
1006
+ availability: "unavailable",
1007
+ testsRun: 0,
1008
+ testsPassed: 0,
1009
+ testsFailed: 0,
1010
+ duration,
1011
+ filesTested: [],
1012
+ command: display,
1013
+ scope: "full",
1014
+ exitCode: 127,
1015
+ outputTail: truncateToByteLimit(tailLines(output, 200), 1e5),
1016
+ failingTests: runner === "vitest" ? extractFailingTestsFromVitestOutput(output) : extractGenericFailures(output)
1017
+ };
1018
+ }
1019
+ if (isTimedOut) {
1020
+ return {
1021
+ testStatus: "timeout",
1022
+ availability: "executed",
1023
+ testsRun: 0,
1024
+ testsPassed: 0,
1025
+ testsFailed: 0,
1026
+ duration,
1027
+ filesTested: [],
1028
+ command: display,
1029
+ scope: "full",
1030
+ exitCode: 124,
1031
+ outputTail: truncateToByteLimit(tailLines(output, 200), 1e5),
1032
+ failingTests: runner === "vitest" ? extractFailingTestsFromVitestOutput(output) : extractGenericFailures(output)
1033
+ };
1034
+ }
1035
+ return {
1036
+ testStatus: "error",
1037
+ availability: "unavailable",
1038
+ testsRun: 0,
1039
+ testsPassed: 0,
1040
+ testsFailed: 0,
1041
+ duration,
1042
+ filesTested: [],
1043
+ command: display,
1044
+ scope: "full",
1045
+ exitCode: 1,
1046
+ outputTail: truncateToByteLimit(tailLines(output, 200), 1e5),
1047
+ failingTests: runner === "vitest" ? extractFailingTestsFromVitestOutput(output) : extractGenericFailures(output)
1048
+ };
1049
+ }
1050
+ }
1051
+ function detectSuiteCommand(worktreePath) {
1052
+ try {
1053
+ const pkgJsonPath = join(worktreePath, "package.json");
1054
+ const scripts = existsSync2(pkgJsonPath) ? JSON.parse(readFileSync(pkgJsonPath, "utf-8"))?.scripts ?? {} : {};
1055
+ const runner = detectTestRunner(worktreePath);
1056
+ const capabilities = detectProjectCapabilities(worktreePath);
1057
+ const isPoeticSelfHarness = hasPoeticVitestHarness(worktreePath);
1058
+ if (isPoeticSelfHarness && typeof scripts["test:fast"] === "string") {
1059
+ return {
1060
+ display: "npm run test:fast",
1061
+ cmd: "npm",
1062
+ args: ["run", "test:fast"],
1063
+ timeoutMs: 12e4,
1064
+ runner: runner === "jest" ? "jest" : "vitest"
1065
+ };
1066
+ }
1067
+ if (isPoeticSelfHarness && typeof scripts["test:changed"] === "string") {
1068
+ return {
1069
+ display: "npm run test:changed -- --local",
1070
+ cmd: "npm",
1071
+ args: ["run", "test:changed", "--", "--local"],
1072
+ timeoutMs: 12e4,
1073
+ runner: runner === "jest" ? "jest" : "vitest"
1074
+ };
1075
+ }
1076
+ const resolverCommand = selectSuiteResolverCommand(capabilities.verification.test);
1077
+ if (!runner || runner === "vitest" && !isPoeticSelfHarness && resolverCommand) {
1078
+ const command = resolverCommand;
1079
+ if (command) {
1080
+ const [cmd, ...args] = splitCommand(command);
1081
+ if (cmd) {
1082
+ return {
1083
+ display: command,
1084
+ cmd,
1085
+ args,
1086
+ timeoutMs: 12e4,
1087
+ runner: "generic"
1088
+ };
1089
+ }
1090
+ }
1091
+ }
1092
+ if (runner === "vitest") {
1093
+ if (!isPoeticSelfHarness) {
1094
+ const invocation = buildExternalVitestRunInvocation();
1095
+ return {
1096
+ display: invocation.display,
1097
+ cmd: invocation.cmd,
1098
+ args: invocation.args,
1099
+ timeoutMs: 12e4,
1100
+ runner
1101
+ };
1102
+ }
1103
+ return {
1104
+ display: "node scripts/dynamic-node-options.mjs vitest run --changed --reporter=verbose",
1105
+ cmd: "node",
1106
+ args: [
1107
+ "scripts/dynamic-node-options.mjs",
1108
+ "vitest",
1109
+ "run",
1110
+ "--changed",
1111
+ "--reporter=verbose"
1112
+ ],
1113
+ timeoutMs: 12e4,
1114
+ runner
1115
+ };
1116
+ }
1117
+ if (runner === "jest") {
1118
+ return {
1119
+ display: "npx --no-install jest --verbose",
1120
+ cmd: "npx",
1121
+ args: ["--no-install", "jest", "--verbose"],
1122
+ timeoutMs: 12e4,
1123
+ runner
1124
+ };
1125
+ }
1126
+ if (runner === "mocha" || runner === "ava" || runner === "node-test") {
1127
+ const fallbackCommand = runner === "mocha" ? "npx --no-install mocha" : runner === "ava" ? "npx --no-install ava" : "node --test";
1128
+ const command = resolverCommand ?? fallbackCommand;
1129
+ const [cmd, ...args] = splitCommand(command);
1130
+ if (!cmd) return null;
1131
+ return { display: command, cmd, args, timeoutMs: 12e4, runner };
1132
+ }
1133
+ if (runner === "pytest" || runner === "unittest") {
1134
+ const command = (runner === "unittest" ? detectPythonUnittestCommand(capabilities) : void 0) ?? capabilities.verification.test[0] ?? "pytest";
1135
+ const [cmd, ...args] = splitCommand(command);
1136
+ if (!cmd) return null;
1137
+ return { display: command, cmd, args, timeoutMs: 12e4, runner };
1138
+ }
1139
+ if (runner === "go" || runner === "cargo") {
1140
+ const fallbackCommand = runner === "go" ? "go test ./..." : "cargo test --locked";
1141
+ const command = selectRunnerLanguageResolverCommand(capabilities.verification.test, runner) ?? fallbackCommand;
1142
+ const [cmd, ...args] = splitCommand(command);
1143
+ if (!cmd) return null;
1144
+ return { display: command, cmd, args, timeoutMs: 12e4, runner };
1145
+ }
1146
+ if (runner === "maven" || runner === "gradle") {
1147
+ const command = selectRunnerLanguageResolverCommand(capabilities.verification.test, runner) ?? capabilities.verification.test[0];
1148
+ if (!command) return null;
1149
+ const [cmd, ...args] = splitCommand(command);
1150
+ if (!cmd) return null;
1151
+ return { display: command, cmd, args, timeoutMs: 12e4, runner };
1152
+ }
1153
+ return null;
1154
+ } catch {
1155
+ return null;
1156
+ }
1157
+ }
1158
+ function selectSuiteResolverCommand(commands) {
1159
+ return commands.find((command) => {
1160
+ const normalized = command.trim();
1161
+ return !/\b(?:npm|pnpm|yarn|bun)\s+run\s+test:(?:fast|changed)\b/.test(normalized);
1162
+ });
1163
+ }
1164
+ var RUNNER_VERIFICATION_LANGUAGES = {
1165
+ go: "go",
1166
+ cargo: "rust",
1167
+ maven: "jvm",
1168
+ gradle: "jvm"
1169
+ };
1170
+ function selectRunnerLanguageResolverCommand(commands, runner) {
1171
+ const language = RUNNER_VERIFICATION_LANGUAGES[runner];
1172
+ if (!language) return void 0;
1173
+ return commands.find((command) => {
1174
+ const described = describeVerificationCommand(command).language;
1175
+ return described === language || described === "unknown";
1176
+ });
1177
+ }
1178
+ var NODE_SCOPED_RUNNERS = /* @__PURE__ */ new Set([
1179
+ "vitest",
1180
+ "jest",
1181
+ "mocha",
1182
+ "ava",
1183
+ "node-test"
1184
+ ]);
1185
+ var SCOPED_SAFE_OPTIONS_COMMON = {
1186
+ "--reporter": { takesValue: true },
1187
+ "--require": { takesValue: true },
1188
+ "-r": { takesValue: true },
1189
+ "--verbose": {},
1190
+ "--silent": {},
1191
+ "--bail": {},
1192
+ "--color": {},
1193
+ "--colors": {},
1194
+ "--no-color": {},
1195
+ "--no-colors": {},
1196
+ "--coverage": {},
1197
+ "--no-coverage": {}
1198
+ };
1199
+ var NODE_SCOPED_SAFE_OPTIONS = {
1200
+ vitest: {
1201
+ ...SCOPED_SAFE_OPTIONS_COMMON,
1202
+ "--preload": { takesValue: true },
1203
+ "--pool": { takesValue: true },
1204
+ "--sequencer": { takesValue: true },
1205
+ "--transformMode": { takesValue: true },
1206
+ "--environment": { takesValue: true },
1207
+ "--no-file-parallelism": {},
1208
+ "--isolate": {},
1209
+ "--no-isolate": {}
1210
+ },
1211
+ jest: {
1212
+ ...SCOPED_SAFE_OPTIONS_COMMON,
1213
+ "--runInBand": {},
1214
+ "--forceExit": {},
1215
+ "--detectOpenHandles": {},
1216
+ "--ci": {},
1217
+ "--json": {},
1218
+ "--maxWorkers": { takesValue: true },
1219
+ "--testTimeout": { takesValue: true },
1220
+ "--outputFile": { takesValue: true }
1221
+ },
1222
+ mocha: {
1223
+ ...SCOPED_SAFE_OPTIONS_COMMON,
1224
+ // Mocha `-t` / `--timeout` are duration, not name selectors (unlike Jest/Vitest `-t`).
1225
+ "--timeout": { takesValue: true },
1226
+ "-t": { takesValue: true },
1227
+ "--ui": { takesValue: true },
1228
+ "-u": { takesValue: true },
1229
+ "--slow": { takesValue: true },
1230
+ "-R": { takesValue: true },
1231
+ "-b": {},
1232
+ "--exit": {},
1233
+ "--recursive": {},
1234
+ "--full-trace": {},
1235
+ "--async-only": {},
1236
+ "-A": {},
1237
+ "--delay": {},
1238
+ "--forbid-only": {},
1239
+ "--forbid-pending": {},
1240
+ "--parallel": {},
1241
+ "--jobs": { takesValue: true }
1242
+ },
1243
+ ava: {
1244
+ ...SCOPED_SAFE_OPTIONS_COMMON,
1245
+ "--timeout": { takesValue: true },
1246
+ "--concurrency": { takesValue: true },
1247
+ "--serial": {},
1248
+ "--tap": {}
1249
+ },
1250
+ "node-test": {
1251
+ "--test-reporter": { takesValue: true },
1252
+ "--test-timeout": { takesValue: true },
1253
+ "--experimental-test-coverage": {}
1254
+ }
1255
+ };
1256
+ function extractPackageManagerScriptName(command) {
1257
+ const normalized = command.trim();
1258
+ const runMatch = normalized.match(/^(?:npm|pnpm|yarn|bun)\s+run\s+([^\s]+)/);
1259
+ if (runMatch?.[1]) return runMatch[1];
1260
+ if (/^(?:npm|pnpm|yarn|bun)\s+test\b/.test(normalized)) return "test";
1261
+ return void 0;
1262
+ }
1263
+ function packageManagerForwardedArgs(command) {
1264
+ const tokens = splitCommand(command.trim());
1265
+ if (tokens[1] === "run" && tokens[2]) {
1266
+ return tokens.slice(3);
1267
+ }
1268
+ if (tokens[1] === "test") {
1269
+ return tokens.slice(2);
1270
+ }
1271
+ return [];
1272
+ }
1273
+ function readPackageScriptBody(worktreePath, scriptName) {
1274
+ try {
1275
+ const pkgJsonPath = join(worktreePath, "package.json");
1276
+ if (!existsSync2(pkgJsonPath)) return void 0;
1277
+ const pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
1278
+ const body = pkgJson.scripts?.[scriptName];
1279
+ return typeof body === "string" && body.trim().length > 0 ? body.trim() : void 0;
1280
+ } catch {
1281
+ return void 0;
1282
+ }
1283
+ }
1284
+ function hasOnlySafeScopedOptions(flagTail, runner) {
1285
+ const safeOptions = NODE_SCOPED_SAFE_OPTIONS[runner];
1286
+ const tokens = splitCommand(flagTail.trim());
1287
+ let i = 0;
1288
+ while (i < tokens.length) {
1289
+ const token = tokens[i];
1290
+ if (token === "--") {
1291
+ return i + 1 >= tokens.length;
1292
+ }
1293
+ if (token.startsWith("-")) {
1294
+ const flagName = token.split("=", 1)[0] ?? token;
1295
+ const option = safeOptions[flagName];
1296
+ if (!option) {
1297
+ return false;
1298
+ }
1299
+ if (option.takesValue && !token.includes("=")) {
1300
+ if (i + 1 >= tokens.length || tokens[i + 1].startsWith("-")) {
1301
+ return false;
1302
+ }
1303
+ i += 2;
1304
+ continue;
1305
+ }
1306
+ i += 1;
1307
+ continue;
1308
+ }
1309
+ return false;
1310
+ }
1311
+ return true;
1312
+ }
1313
+ function isSimpleScopedNodeRunnerInvocation(command, runner) {
1314
+ let normalized = command.trim();
1315
+ if (!normalized) return false;
1316
+ if (/(?:&&|\|\||[;|<>`]|\$\()/.test(normalized)) return false;
1317
+ normalized = normalized.replace(/^(?:npx|bunx)(?:\s+--no-install)?\s+/u, "").replace(/^(?:pnpm|yarn)\s+(?:exec|dlx)\s+/u, "").replace(/^node\s+scripts\/dynamic-node-options\.mjs\s+/u, "").replace(/^(?:\.\/)?node_modules\/\.bin\//u, "");
1318
+ switch (runner) {
1319
+ case "vitest": {
1320
+ if (!/^vitest\b/.test(normalized)) return false;
1321
+ const rest = normalized.replace(/^vitest(?:\s+run)?\b/, "");
1322
+ return hasOnlySafeScopedOptions(rest, "vitest");
1323
+ }
1324
+ case "jest": {
1325
+ if (!/^jest\b/.test(normalized)) return false;
1326
+ return hasOnlySafeScopedOptions(normalized.replace(/^jest\b/, ""), "jest");
1327
+ }
1328
+ case "mocha": {
1329
+ if (!/^mocha\b/.test(normalized)) return false;
1330
+ return hasOnlySafeScopedOptions(normalized.replace(/^mocha\b/, ""), "mocha");
1331
+ }
1332
+ case "ava": {
1333
+ if (!/^ava\b/.test(normalized)) return false;
1334
+ return hasOnlySafeScopedOptions(normalized.replace(/^ava\b/, ""), "ava");
1335
+ }
1336
+ case "node-test": {
1337
+ const tokens = splitCommand(normalized);
1338
+ if (tokens[0] !== "node") return false;
1339
+ const testIdx = tokens.findIndex((token, index) => index > 0 && token === "--test");
1340
+ if (testIdx < 0) return false;
1341
+ const before = tokens.slice(1, testIdx).join(" ");
1342
+ const after = tokens.slice(testIdx + 1).join(" ");
1343
+ return hasOnlySafeScopedOptions(before, "node-test") && hasOnlySafeScopedOptions(after, "node-test");
1344
+ }
1345
+ default:
1346
+ return false;
1347
+ }
1348
+ }
1349
+ function isScopedFileCompatibleNodeCommand(command, runner, worktreePath) {
1350
+ const normalized = command.trim();
1351
+ if (!normalized) return false;
1352
+ if (/\b(?:npm|pnpm|yarn|bun)\s+run\s+test:(?:smoke|fast|changed)\b/.test(normalized)) {
1353
+ return false;
1354
+ }
1355
+ if (/\b(?:npm|pnpm|yarn|bun)\s+test:(?:smoke|fast|changed)\b/.test(normalized)) {
1356
+ return false;
1357
+ }
1358
+ if (/^(?:npm|pnpm|yarn|bun)\b/.test(normalized)) {
1359
+ const scriptName = extractPackageManagerScriptName(normalized);
1360
+ if (!scriptName) return false;
1361
+ if (scriptName !== "test" && scriptName !== "test:unit") return false;
1362
+ const scriptBody = readPackageScriptBody(worktreePath, scriptName);
1363
+ if (!scriptBody) return false;
1364
+ const forwardedArgs = packageManagerForwardedArgs(normalized);
1365
+ if (forwardedArgs.length > 0 && !(forwardedArgs.length === 1 && forwardedArgs[0] === "--")) {
1366
+ return false;
1367
+ }
1368
+ return isSimpleScopedNodeRunnerInvocation(scriptBody, runner);
1369
+ }
1370
+ return isSimpleScopedNodeRunnerInvocation(normalized, runner);
1371
+ }
1372
+ function selectNodeScopedResolverCommand(worktreePath, runner) {
1373
+ if (!NODE_SCOPED_RUNNERS.has(runner)) return void 0;
1374
+ const commands = detectProjectCapabilities(worktreePath).verification.test;
1375
+ return commands.find((command) => {
1376
+ if (!isNodeVerificationCommand(command)) return false;
1377
+ return isScopedFileCompatibleNodeCommand(command, runner, worktreePath);
1378
+ });
1379
+ }
1380
+ function selectNodeSuiteResolverCommand(worktreePath) {
1381
+ return detectProjectCapabilities(worktreePath).verification.test.find(isNodeVerificationCommand);
1382
+ }
1383
+ function isNodeVerificationCommand(command) {
1384
+ const { language } = describeVerificationCommand(command);
1385
+ return language === "node" || language === "unknown" || commandMatchesLanguage(command, "javascript") || commandMatchesLanguage(command, "typescript");
1386
+ }
1387
+ function formatScopedDisplay(cmd, args) {
1388
+ const bare = /* @__PURE__ */ new Set([
1389
+ "npx",
1390
+ "npm",
1391
+ "pnpm",
1392
+ "yarn",
1393
+ "bun",
1394
+ "node",
1395
+ "run",
1396
+ "test",
1397
+ "vitest",
1398
+ "jest",
1399
+ "mocha",
1400
+ "ava",
1401
+ "--",
1402
+ "--no-install",
1403
+ "--reporter=verbose",
1404
+ "--verbose",
1405
+ "--test"
1406
+ ]);
1407
+ const formatArg = (part) => {
1408
+ if (bare.has(part) || part.startsWith("--") && !part.includes("/")) return part;
1409
+ if (part.includes("/") || part.includes(".") || /\s/.test(part)) return `"${part}"`;
1410
+ return part;
1411
+ };
1412
+ return [cmd, ...args].map((part, index) => index === 0 ? part : formatArg(part)).join(" ");
1413
+ }
1414
+ function appendScopedFilesToCommand(command, testFiles) {
1415
+ const tokens = splitCommand(command);
1416
+ const cmd = tokens[0] ?? command;
1417
+ const baseArgs = tokens.slice(1);
1418
+ if (cmd === "yarn") {
1419
+ const args2 = [...baseArgs, ...testFiles];
1420
+ return { cmd, args: args2, display: formatScopedDisplay(cmd, args2) };
1421
+ }
1422
+ if (cmd === "npm" || cmd === "pnpm" || cmd === "bun") {
1423
+ if (baseArgs.includes("--")) {
1424
+ const args3 = [...baseArgs, ...testFiles];
1425
+ return { cmd, args: args3, display: formatScopedDisplay(cmd, args3) };
1426
+ }
1427
+ const args2 = [...baseArgs, "--", ...testFiles];
1428
+ return { cmd, args: args2, display: formatScopedDisplay(cmd, args2) };
1429
+ }
1430
+ const args = [...baseArgs, ...testFiles];
1431
+ return { cmd, args, display: formatScopedDisplay(cmd, args) };
1432
+ }
1433
+ function resolveScopedNodeTestInvocation(runner, testFiles, worktreePath) {
1434
+ if (runner === "vitest" && hasPoeticVitestHarness(worktreePath)) {
1435
+ const args2 = [
1436
+ "scripts/dynamic-node-options.mjs",
1437
+ "vitest",
1438
+ "run",
1439
+ ...testFiles,
1440
+ "--reporter=verbose"
1441
+ ];
1442
+ return { cmd: "node", args: args2, display: formatScopedDisplay("node", args2), scope: "scoped" };
1443
+ }
1444
+ const resolverCommand = selectNodeScopedResolverCommand(worktreePath, runner);
1445
+ if (resolverCommand) {
1446
+ return { ...appendScopedFilesToCommand(resolverCommand, testFiles), scope: "scoped" };
1447
+ }
1448
+ const suiteCommand = selectNodeSuiteResolverCommand(worktreePath);
1449
+ if (!suiteCommand) return void 0;
1450
+ const [cmd, ...args] = splitCommand(suiteCommand);
1451
+ if (!cmd) return void 0;
1452
+ return { cmd, args, display: suiteCommand, scope: "full" };
1453
+ }
1454
+ function detectTestRunner(worktreePath) {
1455
+ try {
1456
+ const capabilities = detectProjectCapabilities(worktreePath);
1457
+ const isNodeTarget = hasProjectLanguage(capabilities, "javascript") || hasProjectLanguage(capabilities, "typescript");
1458
+ if (isNodeTarget) {
1459
+ const pkgJsonPath = join(worktreePath, "package.json");
1460
+ if (existsSync2(pkgJsonPath)) {
1461
+ const pkgJsonContent = readFileSync(pkgJsonPath, "utf-8");
1462
+ const pkgJson = JSON.parse(pkgJsonContent);
1463
+ const allDeps = {
1464
+ ...pkgJson.dependencies,
1465
+ ...pkgJson.devDependencies
1466
+ };
1467
+ if (allDeps.vitest) {
1468
+ return "vitest";
1469
+ }
1470
+ if (allDeps.jest || allDeps["@types/jest"]) {
1471
+ return "jest";
1472
+ }
1473
+ if (allDeps.mocha) {
1474
+ return "mocha";
1475
+ }
1476
+ if (allDeps.ava) {
1477
+ return "ava";
1478
+ }
1479
+ const scripts = pkgJson.scripts ?? {};
1480
+ const testScript = typeof scripts.test === "string" ? scripts.test : "";
1481
+ if (/\bnode\s+(?:--[^\s]+\s+)*--test(?=\s|$)/.test(testScript)) {
1482
+ return "node-test";
1483
+ }
1484
+ }
1485
+ }
1486
+ if (hasProjectLanguage(capabilities, "python")) {
1487
+ return detectPythonUnittestCommand(capabilities) !== void 0 ? "unittest" : "pytest";
1488
+ }
1489
+ if (hasProjectLanguage(capabilities, "go")) return "go";
1490
+ if (hasProjectLanguage(capabilities, "rust")) return "cargo";
1491
+ if (capabilities.manifests.pomXml) return "maven";
1492
+ if (capabilities.manifests.gradle) return "gradle";
1493
+ if (detectPowerShellTestCommand(worktreePath)) return "powershell";
1494
+ return null;
1495
+ } catch {
1496
+ return null;
1497
+ }
1498
+ }
1499
+ function resolveArtifactMetricRunner(command, fallback) {
1500
+ return isPythonStdlibUnittestCommand(command) ? "unittest" : fallback;
1501
+ }
1502
+ function detectPythonUnittestCommand(capabilities) {
1503
+ const primary = capabilities.verification.test.find(
1504
+ (command) => describeVerificationCommand(command).language === "python"
1505
+ );
1506
+ if (primary === void 0) return void 0;
1507
+ return isPythonStdlibUnittestCommand(primary) ? primary : void 0;
1508
+ }
1509
+ function detectPowerShellTestCommand(worktreePath) {
1510
+ return detectProjectCapabilities(worktreePath).verification.test.find(
1511
+ (command) => /^(?:pwsh|powershell)(?:\.exe)?\b.*\bInvoke-Pester\b/i.test(command)
1512
+ );
1513
+ }
1514
+ function commandMatchesLanguage(command, language) {
1515
+ const normalized = command.trim();
1516
+ const descriptor = describeVerificationCommand(normalized);
1517
+ if (descriptor.language !== "unknown") {
1518
+ if (descriptor.kind !== "test") return false;
1519
+ switch (descriptor.language) {
1520
+ case "node":
1521
+ return language === "javascript" || language === "typescript";
1522
+ case "jvm":
1523
+ return language === "java" || language === "kotlin";
1524
+ case "native":
1525
+ return language === "c" || language === "cpp";
1526
+ default:
1527
+ return descriptor.language === language;
1528
+ }
1529
+ }
1530
+ switch (language) {
1531
+ case "javascript":
1532
+ case "typescript":
1533
+ return /^(?:npm|pnpm|yarn|bun)\b.*\btest\b|^bun\s+test\b/.test(normalized);
1534
+ case "python":
1535
+ return /\b(?:pytest|tox)\b/.test(normalized);
1536
+ case "go":
1537
+ return /^go\s+test\b/.test(normalized);
1538
+ case "rust":
1539
+ return /^cargo\s+test\b/.test(normalized);
1540
+ case "java":
1541
+ case "kotlin":
1542
+ return /\b(?:gradle|mvn|mvnw|gradlew)\b.*\btest\b/.test(normalized);
1543
+ case "dotnet":
1544
+ return /^dotnet\s+test\b/.test(normalized);
1545
+ case "swift":
1546
+ return /^swift\s+test\b/.test(normalized);
1547
+ case "dart":
1548
+ return /^(?:dart|flutter)\s+test\b/.test(normalized);
1549
+ case "ruby":
1550
+ return /\b(?:rspec|rake\s+test)\b/.test(normalized);
1551
+ case "php":
1552
+ return /\b(?:phpunit|composer\s+exec\s+--\s+phpunit)\b/.test(normalized);
1553
+ case "c":
1554
+ case "cpp":
1555
+ return /^(?:ctest|meson\s+test|make\s+(?:check|test))\b/.test(normalized);
1556
+ case "r":
1557
+ return /^R\s+CMD\s+check\b/.test(normalized);
1558
+ case "sql":
1559
+ return /^dbt\s+test\b/.test(normalized);
1560
+ case "powershell":
1561
+ return /^(?:pwsh|powershell)(?:\.exe)?\b.*\bInvoke-Pester\b/i.test(normalized);
1562
+ default:
1563
+ return false;
1564
+ }
1565
+ }
1566
+ function selectCapabilityTestCommandsForChanges(worktreePath, changedFiles) {
1567
+ const changedLanguages = changedProjectLanguages(changedFiles);
1568
+ if (changedLanguages.size === 0) {
1569
+ return detectProjectCapabilities(worktreePath).verification.test.slice(0, 1);
1570
+ }
1571
+ return selectCapabilityTestCommandsForLanguages(worktreePath, changedLanguages);
1572
+ }
1573
+ function selectCapabilityTestCommandsForLanguages(worktreePath, changedLanguages) {
1574
+ const capabilities = detectProjectCapabilities(worktreePath);
1575
+ if (capabilities.verification.test.length === 0) return [];
1576
+ if (changedLanguages.size === 0) return [];
1577
+ const selected = [];
1578
+ for (const language of changedLanguages) {
1579
+ const command = capabilities.verification.test.find(
1580
+ (candidate) => commandMatchesLanguage(candidate, language)
1581
+ );
1582
+ if (command) selected.push(command);
1583
+ }
1584
+ const unique = Array.from(new Set(selected));
1585
+ const uncovered = [...changedLanguages].filter(
1586
+ (language) => !unique.some((command) => commandMatchesLanguage(command, language))
1587
+ );
1588
+ if (uncovered.length > 0) return [];
1589
+ return unique;
1590
+ }
1591
+ function changedProjectLanguages(changedFiles) {
1592
+ const languages = /* @__PURE__ */ new Set();
1593
+ for (const file of changedFiles) {
1594
+ const inferred = languageForProjectPath(file);
1595
+ const language = inferred && inferred !== "unknown" ? inferred : languageForProjectConfigPath(file);
1596
+ if (language && language !== "unknown" && language !== "docs") languages.add(language);
1597
+ }
1598
+ return languages;
1599
+ }
1600
+ function languageForProjectConfigPath(filePath) {
1601
+ const normalized = filePath.replace(/\\/g, "/").toLowerCase();
1602
+ const base = normalized.split("/").pop() ?? normalized;
1603
+ if (base === "package.json" || base.startsWith("tsconfig")) return "typescript";
1604
+ if (base === "pyproject.toml" || base === "poetry.lock" || base === "pipfile" || base === "pipfile.lock" || base.startsWith("requirements") || base === "pytest.ini" || base === "tox.ini") {
1605
+ return "python";
1606
+ }
1607
+ if (base === "go.mod" || base === "go.sum") return "go";
1608
+ if (base === "cargo.toml" || base === "cargo.lock") return "rust";
1609
+ if (base === "pom.xml" || base.startsWith("build.gradle") || base.startsWith("settings.gradle")) {
1610
+ return "java";
1611
+ }
1612
+ if (/\.(?:csproj|fsproj|vbproj)$/.test(base) || base.endsWith(".sln")) return "dotnet";
1613
+ if (base === "package.swift") return "swift";
1614
+ if (base === "pubspec.yaml") return "dart";
1615
+ if (base === "gemfile" || base === "rakefile" || base.endsWith(".gemspec")) return "ruby";
1616
+ if (base === "composer.json" || base === "composer.lock") return "php";
1617
+ if (base === "cmakelists.txt" || base === "cmakepresets.json" || base === "meson.build") {
1618
+ return "cpp";
1619
+ }
1620
+ if (base === "pesterconfiguration.ps1") return "powershell";
1621
+ if (base === "description" || base === "renv.lock" || base.endsWith(".rproj")) return "r";
1622
+ if (base === "dbt_project.yml" || base === "dbt_project.yaml") return "sql";
1623
+ return null;
1624
+ }
1625
+ function getChangedTestFiles(diff) {
1626
+ const testFiles = /* @__PURE__ */ new Set();
1627
+ const diffHeaderPattern = /^\+\+\+ b\/(.+)$/gm;
1628
+ let match = diffHeaderPattern.exec(diff);
1629
+ while (match !== null) {
1630
+ const filePath = match[1];
1631
+ if (filePath && isTestFile(filePath)) {
1632
+ testFiles.add(filePath);
1633
+ }
1634
+ match = diffHeaderPattern.exec(diff);
1635
+ }
1636
+ return Array.from(testFiles);
1637
+ }
1638
+ function selectTestFilesForTouchedMode(worktreePath, changedFilesMeta, changedTestFiles) {
1639
+ const selectedFiles = new Set(changedTestFiles);
1640
+ const riskExpandedFiles = /* @__PURE__ */ new Set();
1641
+ for (const file of changedFilesMeta) {
1642
+ for (const mappedTest of getRiskExpandedTestFiles(worktreePath, file.path, file.category)) {
1643
+ riskExpandedFiles.add(mappedTest);
1644
+ selectedFiles.add(mappedTest);
1645
+ }
1646
+ }
1647
+ const files = Array.from(selectedFiles);
1648
+ if (files.length === 0) {
1649
+ return { files: [], scope: "none" };
1650
+ }
1651
+ if (riskExpandedFiles.size > 0) {
1652
+ return { files, scope: "targeted" };
1653
+ }
1654
+ return { files, scope: "touched" };
1655
+ }
1656
+ function selectTestFilesForAffectedMode(worktreePath, changedFilesMeta, changedTestFiles) {
1657
+ const touchedSelection = selectTestFilesForTouchedMode(
1658
+ worktreePath,
1659
+ changedFilesMeta,
1660
+ changedTestFiles
1661
+ );
1662
+ const selectedFiles = new Set(touchedSelection.files);
1663
+ const reverseImportMatches = findAffectedImportingTests(worktreePath, changedFilesMeta);
1664
+ for (const testFile of reverseImportMatches) {
1665
+ selectedFiles.add(testFile);
1666
+ }
1667
+ const files = Array.from(selectedFiles).sort();
1668
+ if (files.length === 0) {
1669
+ return { files: [], scope: "none" };
1670
+ }
1671
+ if (reverseImportMatches.length > 0) {
1672
+ return { files, scope: "affected" };
1673
+ }
1674
+ return { files, scope: touchedSelection.scope };
1675
+ }
1676
+ function shouldRunFullSuiteForUnmappedSourceChange(runner, changedFilesMeta) {
1677
+ if (!runner || runner === "vitest" || runner === "jest") {
1678
+ return false;
1679
+ }
1680
+ return changedFilesMeta.some((file) => file.category === "source" && !isTestFile(file.path));
1681
+ }
1682
+ function splitCommand(command) {
1683
+ const args = [];
1684
+ let current = "";
1685
+ let quote = null;
1686
+ let escaping = false;
1687
+ for (const char of command.trim()) {
1688
+ if (escaping) {
1689
+ current += char;
1690
+ escaping = false;
1691
+ continue;
1692
+ }
1693
+ if (char === "\\") {
1694
+ escaping = true;
1695
+ continue;
1696
+ }
1697
+ if (quote) {
1698
+ if (char === quote) {
1699
+ quote = null;
1700
+ } else {
1701
+ current += char;
1702
+ }
1703
+ continue;
1704
+ }
1705
+ if (char === '"' || char === "'") {
1706
+ quote = char;
1707
+ continue;
1708
+ }
1709
+ if (/\s/.test(char)) {
1710
+ if (current.length > 0) {
1711
+ args.push(current);
1712
+ current = "";
1713
+ }
1714
+ continue;
1715
+ }
1716
+ current += char;
1717
+ }
1718
+ if (escaping) current += "\\";
1719
+ if (current.length > 0) args.push(current);
1720
+ return args;
1721
+ }
1722
+ function findAffectedImportingTests(worktreePath, changedFilesMeta) {
1723
+ const capabilities = detectProjectCapabilities(worktreePath);
1724
+ const isJsTsTarget = hasProjectLanguage(capabilities, "javascript") || hasProjectLanguage(capabilities, "typescript");
1725
+ if (!isJsTsTarget) {
1726
+ return [];
1727
+ }
1728
+ const changedSourceFiles = new Set(
1729
+ changedFilesMeta.filter((file) => file.category === "source" && !isTestFile(file.path)).map((file) => normalizeRepoPath(file.path))
1730
+ );
1731
+ if (changedSourceFiles.size === 0) {
1732
+ return [];
1733
+ }
1734
+ const affectedTests = /* @__PURE__ */ new Set();
1735
+ for (const testFile of listRepoTestFiles(worktreePath)) {
1736
+ const resolvedImports = resolveDirectRepoImportsForTest(testFile, worktreePath);
1737
+ if (resolvedImports.some((importedPath) => changedSourceFiles.has(importedPath))) {
1738
+ affectedTests.add(testFile);
1739
+ }
1740
+ }
1741
+ return Array.from(affectedTests).sort();
1742
+ }
1743
+ function listRepoTestFiles(worktreePath) {
1744
+ const discovered = /* @__PURE__ */ new Set();
1745
+ for (const root of TEST_DISCOVERY_ROOTS) {
1746
+ const absoluteRoot = join(worktreePath, root);
1747
+ if (!existsSync2(absoluteRoot)) {
1748
+ continue;
1749
+ }
1750
+ walkTestFiles(absoluteRoot, worktreePath, discovered);
1751
+ }
1752
+ return Array.from(discovered).sort();
1753
+ }
1754
+ function walkTestFiles(currentPath, worktreePath, discovered) {
1755
+ let entries;
1756
+ try {
1757
+ entries = readdirSync(currentPath, { withFileTypes: true });
1758
+ } catch {
1759
+ return;
1760
+ }
1761
+ for (const entry of entries) {
1762
+ if (entry.isDirectory()) {
1763
+ if (SKIPPED_TEST_DISCOVERY_DIRS.has(entry.name)) {
1764
+ continue;
1765
+ }
1766
+ walkTestFiles(join(currentPath, entry.name), worktreePath, discovered);
1767
+ continue;
1768
+ }
1769
+ if (!entry.isFile()) {
1770
+ continue;
1771
+ }
1772
+ const repoRelative = normalizeRepoPath(relative(worktreePath, join(currentPath, entry.name)));
1773
+ if (isTestFile(repoRelative)) {
1774
+ discovered.add(repoRelative);
1775
+ }
1776
+ }
1777
+ }
1778
+ function resolveDirectRepoImportsForTest(testFile, worktreePath) {
1779
+ const absolutePath = join(worktreePath, testFile);
1780
+ let content;
1781
+ try {
1782
+ content = readFileSync(absolutePath, "utf8");
1783
+ } catch {
1784
+ return [];
1785
+ }
1786
+ const imports = /* @__PURE__ */ new Set();
1787
+ const addMatches = (pattern, captureIndex) => {
1788
+ let match = pattern.exec(content);
1789
+ while (match !== null) {
1790
+ const specifier = match[captureIndex]?.trim();
1791
+ if (specifier) {
1792
+ imports.add(specifier);
1793
+ }
1794
+ match = pattern.exec(content);
1795
+ }
1796
+ };
1797
+ addMatches(/\b(?:from|import)\s+['"]([^'"]+)['"]/g, 1);
1798
+ addMatches(/\brequire\(\s*['"]([^'"]+)['"]\s*\)/g, 1);
1799
+ addMatches(/\bimport\(\s*['"]([^'"]+)['"]\s*\)/g, 1);
1800
+ const resolvedImports = /* @__PURE__ */ new Set();
1801
+ for (const specifier of imports) {
1802
+ const resolvedImport = resolveRelativeRepoImport(testFile, specifier, worktreePath);
1803
+ if (resolvedImport) {
1804
+ resolvedImports.add(resolvedImport);
1805
+ }
1806
+ }
1807
+ return Array.from(resolvedImports);
1808
+ }
1809
+ function resolveRelativeRepoImport(importerPath, specifier, worktreePath) {
1810
+ if (!specifier.startsWith(".")) {
1811
+ return null;
1812
+ }
1813
+ const baseTarget = resolve(worktreePath, dirname(importerPath), specifier);
1814
+ for (const candidate of buildImportResolutionCandidates(baseTarget)) {
1815
+ if (!existsSync2(candidate)) {
1816
+ continue;
1817
+ }
1818
+ const repoRelative = normalizeRepoPath(relative(worktreePath, candidate));
1819
+ if (repoRelative.startsWith("..")) {
1820
+ continue;
1821
+ }
1822
+ return repoRelative;
1823
+ }
1824
+ return null;
1825
+ }
1826
+ function buildImportResolutionCandidates(baseTarget) {
1827
+ const candidates = /* @__PURE__ */ new Set();
1828
+ const addCandidate = (candidate) => {
1829
+ candidates.add(candidate);
1830
+ };
1831
+ addCandidate(baseTarget);
1832
+ const baseExtension = extname(baseTarget);
1833
+ if (baseExtension) {
1834
+ if (JS_LIKE_EXTENSIONS.has(baseExtension)) {
1835
+ const stem = baseTarget.slice(0, -baseExtension.length);
1836
+ for (const sourceExtension of SOURCE_FILE_EXTENSIONS) {
1837
+ addCandidate(`${stem}${sourceExtension}`);
1838
+ }
1839
+ }
1840
+ } else {
1841
+ for (const extension of SOURCE_FILE_EXTENSIONS) {
1842
+ addCandidate(`${baseTarget}${extension}`);
1843
+ addCandidate(join(baseTarget, `index${extension}`));
1844
+ }
1845
+ }
1846
+ return Array.from(candidates);
1847
+ }
1848
+ function normalizeRepoPath(filePath) {
1849
+ return filePath.split(sep).join("/");
1850
+ }
1851
+ function getRiskExpandedTestFiles(worktreePath, filePath, category) {
1852
+ if (!hasPoeticVitestHarness(worktreePath)) {
1853
+ return [];
1854
+ }
1855
+ if (filePath === "schemas/judge-scoring.schema.json") {
1856
+ return ["tests/unit/core/config/judge-scoring-schema.test.ts"];
1857
+ }
1858
+ if (category === "config" || category === "lockfile") {
1859
+ if (filePath === ".poetic/config/providers.yaml") {
1860
+ return ["src/core/providers/model-update/__tests__/pricing/passthrough-resolver.test.ts"];
1861
+ }
1862
+ }
1863
+ return [];
1864
+ }
1865
+ function isTestFile(filePath) {
1866
+ if (DEFAULT_CONFIG.testFilePatterns.some((pattern) => pattern.test(filePath))) return true;
1867
+ const base = pathPosix.basename(filePath.replace(/\\/g, "/"));
1868
+ return isProjectTestPath(base);
1869
+ }
1870
+ async function executeTests(runner, testFiles, worktreePath, abortSignal, scopedNodeInvocation) {
1871
+ if (!runner) {
1872
+ return {
1873
+ status: "error",
1874
+ testsRun: 0,
1875
+ testsPassed: 0,
1876
+ testsFailed: 0,
1877
+ metricsMeasured: false,
1878
+ duration: 0,
1879
+ exitCode: 1,
1880
+ outputTail: "",
1881
+ failingTests: []
1882
+ };
1883
+ }
1884
+ const startTime = Date.now();
1885
+ if (runner === "powershell") {
1886
+ const command = detectPowerShellTestCommand(worktreePath) ?? "pwsh -NoProfile -Command Invoke-Pester";
1887
+ const result = await runVerificationCommand(command, {
1888
+ cwd: worktreePath,
1889
+ timeoutMs: DEFAULT_CONFIG.timeout,
1890
+ abortSignal
1891
+ });
1892
+ const output = String(result.all ?? result.stdout ?? result.stderr ?? "");
1893
+ const { exitCode } = resolveVerificationExitCode(command, result);
1894
+ const metrics = parseTestOutput(runner, output);
1895
+ const duration = Date.now() - startTime;
1896
+ const inferredStatus = exitCode === 0 ? inferSuccessStatusFromMetrics(metrics) : "failed";
1897
+ return {
1898
+ status: exitCode === 0 && !metrics.metricsMeasured && inferredStatus !== "failed" ? "unavailable" : inferredStatus,
1899
+ testsRun: metrics.testsRun,
1900
+ testsPassed: metrics.testsPassed,
1901
+ testsFailed: metrics.testsFailed,
1902
+ metricsMeasured: metrics.metricsMeasured,
1903
+ duration,
1904
+ exitCode,
1905
+ outputTail: truncateToByteLimit(tailLines(output, 200), 1e5),
1906
+ failingTests: exitCode === 0 ? [] : extractGenericFailures(output)
1907
+ };
1908
+ }
1909
+ const execaCommand = runner === "vitest" || runner === "jest" || runner === "mocha" || runner === "ava" || runner === "node-test" ? scopedNodeInvocation : runner === "unittest" ? (
1910
+ // `python -m unittest discover` takes a start DIRECTORY; appending test
1911
+ // file paths makes it abort with "Start directory is not importable"
1912
+ // (verified on CPython 3.14). So the resolved command runs UNSCOPED,
1913
+ // like the maven/gradle full-suite runners; the caller reports honest
1914
+ // `full` scope rather than claiming the touched file was executed.
1915
+ (() => {
1916
+ const capabilities = detectProjectCapabilities(worktreePath);
1917
+ const [cmd, ...args] = splitCommand(
1918
+ detectPythonUnittestCommand(capabilities) ?? capabilities.verification.test[0] ?? "python3 -m unittest discover"
1919
+ );
1920
+ return { cmd: cmd ?? "python3", args };
1921
+ })()
1922
+ ) : runner === "pytest" ? (() => {
1923
+ const [cmd, ...baseArgs] = splitCommand(
1924
+ detectProjectCapabilities(worktreePath).verification.test[0] ?? "pytest"
1925
+ );
1926
+ return {
1927
+ cmd: cmd ?? "pytest",
1928
+ args: [...baseArgs, ...testFiles]
1929
+ };
1930
+ })() : runner === "go" || runner === "cargo" ? (
1931
+ // Resolver-first (same contract as maven/gradle/pytest below):
1932
+ // honor the target's OWN declared test command (Makefile
1933
+ // `test:` target, poetic.config `verification.test` override)
1934
+ // instead of a hardcoded default. The cargo `--locked`
1935
+ // fallback matches the resolver's lockfile-safe policy
1936
+ // (capabilities.ts) — never mutate the target's Cargo.lock. [B6]
1937
+ (() => {
1938
+ const fallback = runner === "go" ? "go test ./..." : "cargo test --locked";
1939
+ const [cmd, ...args] = splitCommand(
1940
+ selectRunnerLanguageResolverCommand(
1941
+ detectProjectCapabilities(worktreePath).verification.test,
1942
+ runner
1943
+ ) ?? fallback
1944
+ );
1945
+ return { cmd: cmd ?? fallback.split(" ")[0], args };
1946
+ })()
1947
+ ) : runner === "maven" || runner === "gradle" ? (() => {
1948
+ const fallback = runner === "maven" ? "mvn test" : "gradle test";
1949
+ const [cmd, ...args] = splitCommand(
1950
+ selectRunnerLanguageResolverCommand(
1951
+ detectProjectCapabilities(worktreePath).verification.test,
1952
+ runner
1953
+ ) ?? fallback
1954
+ );
1955
+ return { cmd: cmd ?? fallback.split(" ")[0], args };
1956
+ })() : { cmd: "gradle", args: ["test"] };
1957
+ if (!execaCommand) {
1958
+ return {
1959
+ status: "error",
1960
+ testsRun: 0,
1961
+ testsPassed: 0,
1962
+ testsFailed: 0,
1963
+ metricsMeasured: false,
1964
+ duration: Date.now() - startTime,
1965
+ exitCode: 1,
1966
+ outputTail: "No safely scoped or declared project test command is available.",
1967
+ failingTests: []
1968
+ };
1969
+ }
1970
+ try {
1971
+ const result = await execa(execaCommand.cmd, execaCommand.args, {
1972
+ cwd: worktreePath,
1973
+ stdio: "pipe",
1974
+ all: true,
1975
+ reject: false,
1976
+ timeout: DEFAULT_CONFIG.timeout,
1977
+ env: createVerificationTestEnv(),
1978
+ extendEnv: false,
1979
+ cancelSignal: abortSignal
1980
+ });
1981
+ const output = String(result.all ?? "");
1982
+ const commandDisplay = `${execaCommand.cmd} ${execaCommand.args.join(" ")}`.trim();
1983
+ const { exitCode } = resolveVerificationExitCode(commandDisplay, result);
1984
+ const duration = Date.now() - startTime;
1985
+ const outputTail = truncateToByteLimit(tailLines(output, 200), 1e5);
1986
+ if (exitCode === 0 && detectZeroCollectedTests(
1987
+ runner === "maven" ? "mvn test" : runner === "gradle" ? "gradle test" : commandDisplay,
1988
+ output
1989
+ )) {
1990
+ return {
1991
+ status: "unavailable",
1992
+ testsRun: 0,
1993
+ testsPassed: 0,
1994
+ testsFailed: 0,
1995
+ metricsMeasured: false,
1996
+ duration,
1997
+ exitCode,
1998
+ outputTail,
1999
+ failingTests: []
2000
+ };
2001
+ }
2002
+ const metrics = parseTestOutput(runner, output);
2003
+ const failingTests = runner === "vitest" ? extractFailingTestsFromVitestOutput(output) : extractGenericFailures(output);
2004
+ if (exitCode === 124) {
2005
+ return {
2006
+ status: "timeout",
2007
+ testsRun: metrics.testsRun,
2008
+ testsPassed: metrics.testsPassed,
2009
+ testsFailed: metrics.testsFailed,
2010
+ metricsMeasured: metrics.metricsMeasured,
2011
+ duration,
2012
+ exitCode,
2013
+ outputTail,
2014
+ failingTests
2015
+ };
2016
+ }
2017
+ if (exitCode !== 0) {
2018
+ return {
2019
+ status: metrics.testsRun > 0 ? "failed" : "error",
2020
+ testsRun: metrics.testsRun,
2021
+ testsPassed: metrics.testsPassed,
2022
+ testsFailed: metrics.testsFailed,
2023
+ metricsMeasured: metrics.metricsMeasured,
2024
+ duration,
2025
+ exitCode,
2026
+ outputTail,
2027
+ failingTests
2028
+ };
2029
+ }
2030
+ const inferredStatus = inferSuccessStatusForRunner(runner, metrics);
2031
+ return {
2032
+ status: !metrics.metricsMeasured && inferredStatus !== "failed" ? "unavailable" : inferredStatus,
2033
+ testsRun: metrics.testsRun,
2034
+ testsPassed: metrics.testsPassed,
2035
+ testsFailed: metrics.testsFailed,
2036
+ metricsMeasured: metrics.metricsMeasured,
2037
+ duration,
2038
+ exitCode,
2039
+ outputTail,
2040
+ failingTests
2041
+ };
2042
+ } catch (error) {
2043
+ const err = error;
2044
+ const duration = Date.now() - startTime;
2045
+ const output = String(err?.all ?? err?.stdout ?? err?.stderr ?? err?.message ?? "");
2046
+ const isAborted = err?.name === "AbortError" || err?.code === "ABORT_ERR" || err?.code === "ERR_ABORTED";
2047
+ const isTimedOut = Boolean(err?.timedOut) || err?.killed && err?.signal === "SIGTERM";
2048
+ if (isAborted || isTimedOut) {
2049
+ return {
2050
+ status: "timeout",
2051
+ testsRun: 0,
2052
+ testsPassed: 0,
2053
+ testsFailed: 0,
2054
+ metricsMeasured: false,
2055
+ duration,
2056
+ exitCode: 124,
2057
+ outputTail: truncateToByteLimit(tailLines(output, 200), 1e5),
2058
+ failingTests: []
2059
+ };
2060
+ }
2061
+ const metrics = parseTestOutput(runner, output);
2062
+ const failingTests = runner === "vitest" ? extractFailingTestsFromVitestOutput(output) : extractGenericFailures(output);
2063
+ const isNotFound = err?.code === "ENOENT" || /\b(?:ENOENT|command not found)\b/i.test(output);
2064
+ const exitCode = isNotFound ? 127 : typeof err.status === "number" ? err.status : 1;
2065
+ return {
2066
+ status: metrics.testsRun > 0 ? "failed" : "error",
2067
+ testsRun: metrics.testsRun,
2068
+ testsPassed: metrics.testsPassed,
2069
+ testsFailed: metrics.testsFailed,
2070
+ metricsMeasured: metrics.metricsMeasured,
2071
+ duration,
2072
+ exitCode,
2073
+ outputTail: truncateToByteLimit(tailLines(output, 200), 1e5),
2074
+ failingTests
2075
+ };
2076
+ }
2077
+ }
2078
+ async function getChangedFilesSinceRef(worktreePath, baseRef) {
2079
+ if (!baseRef) return [];
2080
+ const result = await execa("git", ["diff", "--name-only", baseRef, "--"], {
2081
+ cwd: worktreePath,
2082
+ stdio: "pipe",
2083
+ reject: false
2084
+ });
2085
+ return String(result.stdout ?? "").split(/\r?\n/).map((line) => line.trim()).filter(Boolean).sort();
2086
+ }
2087
+ function shellDisplayArg(value) {
2088
+ return /[\s"'\\]/.test(value) ? JSON.stringify(value) : value;
2089
+ }
2090
+ async function runVitestPlanStep(worktreePath, step, options) {
2091
+ const start = Date.now();
2092
+ const command = `node scripts/dynamic-node-options.mjs vitest run ${step.displayArgs} --reporter=verbose`;
2093
+ try {
2094
+ const result = await execa(
2095
+ "node",
2096
+ ["scripts/dynamic-node-options.mjs", "vitest", "run", ...step.args, "--reporter=verbose"],
2097
+ {
2098
+ cwd: worktreePath,
2099
+ stdio: "pipe",
2100
+ all: true,
2101
+ reject: false,
2102
+ timeout: options.timeoutMs,
2103
+ env: createVerificationTestEnv(),
2104
+ extendEnv: false
2105
+ }
2106
+ );
2107
+ const durationMs = Date.now() - start;
2108
+ const { exitCode } = resolveVerificationExitCode(command, result);
2109
+ const all = String(result.all ?? "");
2110
+ const outputTail = truncateToByteLimit(tailLines(all, options.tailLines), 1e5);
2111
+ const failingTests = exitCode === 0 ? [] : extractFailingTestsFromVitestOutput(all);
2112
+ if (exitCode === 1 && /No test files found/i.test(all)) {
2113
+ return {
2114
+ command,
2115
+ exitCode: -1,
2116
+ durationMs,
2117
+ outputTail,
2118
+ status: "unavailable",
2119
+ skipReason: "no-matching-tests",
2120
+ failingTests: [],
2121
+ language: "node"
2122
+ };
2123
+ }
2124
+ const exitZeroFailure = exitCode === 0 ? detectExitZeroVerifyFailure(command, all) : void 0;
2125
+ if (exitZeroFailure) {
2126
+ return {
2127
+ command,
2128
+ exitCode: 1,
2129
+ durationMs,
2130
+ outputTail: truncateToByteLimit(
2131
+ [outputTail, exitZeroFailure.message].filter(Boolean).join("\n"),
2132
+ 1e5
2133
+ ),
2134
+ status: "failed",
2135
+ failingTests: [exitZeroFailure.message],
2136
+ language: "node"
2137
+ };
2138
+ }
2139
+ if (exitCode === 0) {
2140
+ return {
2141
+ command,
2142
+ exitCode,
2143
+ durationMs,
2144
+ outputTail,
2145
+ status: "passed",
2146
+ failingTests,
2147
+ language: "node"
2148
+ };
2149
+ }
2150
+ if (exitCode === 124) {
2151
+ return {
2152
+ command,
2153
+ exitCode,
2154
+ durationMs,
2155
+ outputTail,
2156
+ status: "timeout",
2157
+ failingTests,
2158
+ language: "node"
2159
+ };
2160
+ }
2161
+ return {
2162
+ command,
2163
+ exitCode,
2164
+ durationMs,
2165
+ outputTail,
2166
+ status: "failed",
2167
+ failingTests,
2168
+ language: "node"
2169
+ };
2170
+ } catch (error) {
2171
+ const durationMs = Date.now() - start;
2172
+ const message = error instanceof Error ? error.message : String(error);
2173
+ return {
2174
+ command,
2175
+ exitCode: 1,
2176
+ durationMs,
2177
+ outputTail: truncateToByteLimit(tailLines(message, options.tailLines), 1e5),
2178
+ status: "error",
2179
+ failingTests: [],
2180
+ language: "node"
2181
+ };
2182
+ }
2183
+ }
2184
+ async function runExternalVitestPlanStep(worktreePath, step, options) {
2185
+ const start = Date.now();
2186
+ const invocation = buildExternalVitestRunInvocation(step.args);
2187
+ const command = invocation.display;
2188
+ try {
2189
+ const result = await execa(invocation.cmd, invocation.args, {
2190
+ cwd: worktreePath,
2191
+ stdio: "pipe",
2192
+ all: true,
2193
+ reject: false,
2194
+ timeout: options.timeoutMs,
2195
+ env: createVerificationTestEnv(),
2196
+ extendEnv: false
2197
+ });
2198
+ const durationMs = Date.now() - start;
2199
+ const { exitCode } = resolveVerificationExitCode(command, result);
2200
+ const all = String(result.all ?? "");
2201
+ const outputTail = truncateToByteLimit(tailLines(all, options.tailLines), 1e5);
2202
+ const failingTests = exitCode === 0 ? [] : extractFailingTestsFromVitestOutput(all);
2203
+ if (exitCode === 1 && /No test files found/i.test(all)) {
2204
+ return {
2205
+ command,
2206
+ exitCode: -1,
2207
+ durationMs,
2208
+ outputTail,
2209
+ status: "unavailable",
2210
+ skipReason: "no-matching-tests",
2211
+ failingTests: [],
2212
+ language: "node"
2213
+ };
2214
+ }
2215
+ const unavailableSignal = detectVerificationToolUnavailable(command, all);
2216
+ if (unavailableSignal) {
2217
+ return {
2218
+ command,
2219
+ exitCode,
2220
+ durationMs,
2221
+ outputTail: truncateToByteLimit(
2222
+ [outputTail, unavailableSignal.message].filter(Boolean).join("\n"),
2223
+ 1e5
2224
+ ),
2225
+ status: "unavailable",
2226
+ failingTests: [],
2227
+ language: "node"
2228
+ };
2229
+ }
2230
+ const exitZeroFailure = exitCode === 0 ? detectExitZeroVerifyFailure(command, all) : void 0;
2231
+ if (exitZeroFailure) {
2232
+ return {
2233
+ command,
2234
+ exitCode: 1,
2235
+ durationMs,
2236
+ outputTail: truncateToByteLimit(
2237
+ [outputTail, exitZeroFailure.message].filter(Boolean).join("\n"),
2238
+ 1e5
2239
+ ),
2240
+ status: "failed",
2241
+ failingTests: [exitZeroFailure.message],
2242
+ language: "node"
2243
+ };
2244
+ }
2245
+ if (exitCode === 0) {
2246
+ return {
2247
+ command,
2248
+ exitCode,
2249
+ durationMs,
2250
+ outputTail,
2251
+ status: "passed",
2252
+ failingTests,
2253
+ language: "node"
2254
+ };
2255
+ }
2256
+ if (exitCode === 124) {
2257
+ return {
2258
+ command,
2259
+ exitCode,
2260
+ durationMs,
2261
+ outputTail,
2262
+ status: "timeout",
2263
+ failingTests,
2264
+ language: "node"
2265
+ };
2266
+ }
2267
+ return {
2268
+ command,
2269
+ exitCode,
2270
+ durationMs,
2271
+ outputTail,
2272
+ status: "failed",
2273
+ failingTests,
2274
+ language: "node"
2275
+ };
2276
+ } catch (error) {
2277
+ const durationMs = Date.now() - start;
2278
+ const message = error instanceof Error ? error.message : String(error);
2279
+ return {
2280
+ command,
2281
+ exitCode: 1,
2282
+ durationMs,
2283
+ outputTail: truncateToByteLimit(tailLines(message, options.tailLines), 1e5),
2284
+ status: "error",
2285
+ failingTests: [],
2286
+ language: "node"
2287
+ };
2288
+ }
2289
+ }
2290
+ async function runCapabilityTestCommand(worktreePath, capabilityCommand, options) {
2291
+ const language = describeVerificationCommand(capabilityCommand).language;
2292
+ try {
2293
+ const result = await runVerificationCommand(capabilityCommand, {
2294
+ cwd: worktreePath,
2295
+ timeoutMs: options.timeoutMs,
2296
+ abortSignal: options.abortSignal
2297
+ });
2298
+ const durationMs = Date.now() - options.start;
2299
+ const { exitCode } = resolveVerificationExitCode(capabilityCommand, result);
2300
+ const all = String(result.all ?? "");
2301
+ const outputTail = truncateToByteLimit(tailLines(all, options.tailLines), 1e5);
2302
+ const failingTests = exitCode === 0 ? [] : extractGenericFailures(all);
2303
+ const exitZeroFailure = exitCode === 0 ? detectExitZeroVerifyFailure(capabilityCommand, all) : void 0;
2304
+ if (exitZeroFailure) {
2305
+ return {
2306
+ command: capabilityCommand,
2307
+ language,
2308
+ exitCode: 1,
2309
+ durationMs,
2310
+ outputTail: truncateToByteLimit(
2311
+ [outputTail, exitZeroFailure.message].filter(Boolean).join("\n"),
2312
+ 1e5
2313
+ ),
2314
+ status: "failed",
2315
+ failingTests: [exitZeroFailure.message]
2316
+ };
2317
+ }
2318
+ if (exitCode === 0 && detectZeroCollectedTests(capabilityCommand, all)) {
2319
+ return {
2320
+ command: capabilityCommand,
2321
+ language,
2322
+ exitCode,
2323
+ durationMs,
2324
+ outputTail,
2325
+ status: "unavailable",
2326
+ failingTests: []
2327
+ };
2328
+ }
2329
+ if (exitCode === 0) {
2330
+ return {
2331
+ command: capabilityCommand,
2332
+ language,
2333
+ exitCode,
2334
+ durationMs,
2335
+ outputTail,
2336
+ status: "passed",
2337
+ failingTests
2338
+ };
2339
+ }
2340
+ if (exitCode === 124) {
2341
+ return {
2342
+ command: capabilityCommand,
2343
+ language,
2344
+ exitCode,
2345
+ durationMs,
2346
+ outputTail,
2347
+ status: "timeout",
2348
+ failingTests
2349
+ };
2350
+ }
2351
+ if (detectVerificationToolUnavailable(capabilityCommand, all) !== void 0) {
2352
+ return {
2353
+ command: capabilityCommand,
2354
+ language,
2355
+ exitCode,
2356
+ durationMs,
2357
+ outputTail,
2358
+ status: "unavailable",
2359
+ failingTests: []
2360
+ };
2361
+ }
2362
+ if (exitCode === 5 && isPythonStdlibUnittestCommand(capabilityCommand) && detectZeroCollectedTests(capabilityCommand, all)) {
2363
+ return {
2364
+ command: capabilityCommand,
2365
+ language,
2366
+ exitCode,
2367
+ durationMs,
2368
+ outputTail,
2369
+ status: "unavailable",
2370
+ failingTests: []
2371
+ };
2372
+ }
2373
+ return {
2374
+ command: capabilityCommand,
2375
+ language,
2376
+ exitCode,
2377
+ durationMs,
2378
+ outputTail,
2379
+ status: "failed",
2380
+ failingTests
2381
+ };
2382
+ } catch (error) {
2383
+ const durationMs = Date.now() - options.start;
2384
+ const message = error instanceof Error ? error.message : String(error);
2385
+ return {
2386
+ command: capabilityCommand,
2387
+ language,
2388
+ exitCode: 1,
2389
+ durationMs,
2390
+ outputTail: truncateToByteLimit(tailLines(message, options.tailLines), 1e5),
2391
+ status: "error",
2392
+ failingTests: []
2393
+ };
2394
+ }
2395
+ }
2396
+ async function runCapabilityTestCommandWithFallback(worktreePath, capabilityCommand, fallbackCommands, options) {
2397
+ let result = await runCapabilityTestCommand(worktreePath, capabilityCommand, options);
2398
+ const scopedFallbacks = selectFallbacksForCommand(capabilityCommand, fallbackCommands);
2399
+ for (const fallbackCommand of scopedFallbacks) {
2400
+ if (result.status !== "unavailable" || options.abortSignal?.aborted) break;
2401
+ let fallbackOptions = options;
2402
+ if (options.timeoutMs !== void 0) {
2403
+ const remainingMs = Math.max(0, options.timeoutMs - (Date.now() - options.start));
2404
+ if (remainingMs <= 0) {
2405
+ return {
2406
+ command: result.command,
2407
+ language: result.language,
2408
+ exitCode: 124,
2409
+ durationMs: Date.now() - options.start,
2410
+ outputTail: truncateToByteLimit(
2411
+ [result.outputTail, "Fallback skipped: per-step timeout budget exhausted."].filter(Boolean).join("\n"),
2412
+ 1e5
2413
+ ),
2414
+ status: "timeout",
2415
+ failingTests: []
2416
+ };
2417
+ }
2418
+ fallbackOptions = { ...options, timeoutMs: remainingMs };
2419
+ }
2420
+ result = await runCapabilityTestCommand(worktreePath, fallbackCommand, fallbackOptions);
2421
+ }
2422
+ return result;
2423
+ }
2424
+ function combineVitestPlanResults(results) {
2425
+ if (results.length === 0) {
2426
+ return {
2427
+ command: "",
2428
+ exitCode: 130,
2429
+ durationMs: 0,
2430
+ outputTail: "Verification plan completed no commands.",
2431
+ status: "error",
2432
+ failingTests: []
2433
+ };
2434
+ }
2435
+ if (results.length === 1) return results[0];
2436
+ const representative = results.find((result) => result.status === "failed") ?? results.find((result) => result.status === "error") ?? results.find((result) => result.status === "timeout") ?? results.find((result) => result.status === "unavailable") ?? results.find((result) => result.status !== "passed") ?? results[0];
2437
+ const exitCode = representative.exitCode ?? 0;
2438
+ const status = representative.status ?? "passed";
2439
+ const languages = new Set(results.map((result) => result.language).filter(Boolean));
2440
+ const outputTail = truncateToByteLimit(
2441
+ results.map((result) => [`$ ${result.command}`, result.outputTail].filter(Boolean).join("\n")).join("\n\n"),
2442
+ 1e5
2443
+ );
2444
+ return {
2445
+ // Full ordered audit provenance of every executed plan-step command.
2446
+ command: results.map((result) => result.command).filter(Boolean).join("\n"),
2447
+ exitCode,
2448
+ durationMs: results.reduce((sum, result) => sum + result.durationMs, 0),
2449
+ outputTail,
2450
+ status,
2451
+ failingTests: Array.from(new Set(results.flatMap((result) => result.failingTests))),
2452
+ // Preserve language only when every step agrees; otherwise leave unset so
2453
+ // consumers do not re-tag multi-language output under one language.
2454
+ language: languages.size === 1 ? results[0]?.language : void 0
2455
+ };
2456
+ }
2457
+ async function runDeterministicTestGateWithArtifacts(worktreePath, options) {
2458
+ const start = Date.now();
2459
+ const timeoutMs = options.timeoutMs;
2460
+ const maxTailLines = options.tailLines ?? 200;
2461
+ if (options.command && options.command.trim().length > 0) {
2462
+ const fallbackCommands = detectProjectCapabilities(worktreePath).verification.testFallback ?? [];
2463
+ return runCapabilityTestCommandWithFallback(worktreePath, options.command, fallbackCommands, {
2464
+ timeoutMs,
2465
+ tailLines: maxTailLines,
2466
+ start
2467
+ });
2468
+ }
2469
+ const hasHarness = hasPoeticVitestHarness(worktreePath);
2470
+ let changedFiles = [];
2471
+ let changedTestFiles = [];
2472
+ try {
2473
+ changedFiles = await getChangedFilesSinceRef(worktreePath, options.baseRef);
2474
+ changedTestFiles = hasHarness ? changedFiles.filter(isTestFile) : [];
2475
+ } catch {
2476
+ changedFiles = [];
2477
+ changedTestFiles = [];
2478
+ }
2479
+ const changedArgs = options.baseRef ? ["--changed", options.baseRef] : ["--changed"];
2480
+ const changedDisplayArgs = options.baseRef ? `--changed ${options.baseRef}` : "--changed";
2481
+ const hasNonTestChanges = changedFiles.some((file) => !isTestFile(file));
2482
+ const skippedAffectedGraphReason = changedTestFiles.length > 0 && hasNonTestChanges ? `Skipped Vitest affected graph: touched tests already ran; skipped broad --changed sweep for ${changedFiles.length} changed files.` : void 0;
2483
+ const planSteps = changedTestFiles.length > 0 ? [
2484
+ {
2485
+ args: changedTestFiles,
2486
+ displayArgs: changedTestFiles.map(shellDisplayArg).join(" ")
2487
+ }
2488
+ ] : [{ args: changedArgs, displayArgs: changedDisplayArgs }];
2489
+ const command = planSteps.map(
2490
+ (step) => hasHarness ? `node scripts/dynamic-node-options.mjs vitest run ${step.displayArgs} --reporter=verbose` : buildExternalVitestRunInvocation(step.args).display
2491
+ ).join(" && ");
2492
+ if (!hasHarness) {
2493
+ const capabilityCommands = selectCapabilityTestCommandsForChanges(worktreePath, changedFiles);
2494
+ if (capabilityCommands.length > 0) {
2495
+ const fallbackCommands = detectProjectCapabilities(worktreePath).verification.testFallback ?? [];
2496
+ const results2 = [];
2497
+ for (const capabilityCommand of capabilityCommands) {
2498
+ const result = await runCapabilityTestCommandWithFallback(
2499
+ worktreePath,
2500
+ capabilityCommand,
2501
+ fallbackCommands,
2502
+ { timeoutMs, tailLines: maxTailLines, start }
2503
+ );
2504
+ results2.push(result);
2505
+ if (result.status !== "passed") break;
2506
+ }
2507
+ return combineVitestPlanResults(results2);
2508
+ }
2509
+ if (changedProjectLanguages(changedFiles).size > 0) {
2510
+ return {
2511
+ command,
2512
+ exitCode: -1,
2513
+ durationMs: Date.now() - start,
2514
+ outputTail: "Skipped deterministic test gate: no matching project test command detected.",
2515
+ status: "unavailable",
2516
+ skipReason: "no-project-test-command",
2517
+ failingTests: []
2518
+ };
2519
+ }
2520
+ if (detectTestRunner(worktreePath) === "vitest") {
2521
+ const results2 = [];
2522
+ for (const step of planSteps) {
2523
+ const result = await runExternalVitestPlanStep(worktreePath, step, {
2524
+ timeoutMs,
2525
+ tailLines: maxTailLines
2526
+ });
2527
+ results2.push(result);
2528
+ if (result.status !== "passed") break;
2529
+ }
2530
+ return combineVitestPlanResults(results2);
2531
+ }
2532
+ const outputTail = "Skipped Vitest gate: no project test command detected.";
2533
+ return {
2534
+ command,
2535
+ exitCode: -1,
2536
+ durationMs: Date.now() - start,
2537
+ outputTail,
2538
+ status: "unavailable",
2539
+ skipReason: "no-project-test-command",
2540
+ failingTests: [],
2541
+ language: "node"
2542
+ };
2543
+ }
2544
+ const results = [];
2545
+ const changedLanguages = changedProjectLanguages(changedFiles);
2546
+ const shouldRunVitest = changedLanguages.size === 0 || changedLanguages.has("javascript") || changedLanguages.has("typescript");
2547
+ const hasNonNodeChangedLanguage = [...changedLanguages].some(
2548
+ (language) => language !== "javascript" && language !== "typescript" && language !== "node"
2549
+ );
2550
+ for (const step of planSteps) {
2551
+ if (!shouldRunVitest) break;
2552
+ const result = await runVitestPlanStep(worktreePath, step, {
2553
+ timeoutMs,
2554
+ tailLines: maxTailLines
2555
+ });
2556
+ results.push(result);
2557
+ if (result.status !== "passed") break;
2558
+ }
2559
+ if (results.every((result) => result.status === "passed")) {
2560
+ const nonNodeLanguages = new Set(
2561
+ [...changedLanguages].filter(
2562
+ (language) => language !== "javascript" && language !== "typescript" && language !== "node"
2563
+ )
2564
+ );
2565
+ const nonNodeCommands = selectCapabilityTestCommandsForLanguages(
2566
+ worktreePath,
2567
+ nonNodeLanguages
2568
+ );
2569
+ if (hasNonNodeChangedLanguage && nonNodeCommands.length === 0) {
2570
+ return {
2571
+ command,
2572
+ exitCode: -1,
2573
+ durationMs: Date.now() - start,
2574
+ outputTail: "Skipped deterministic test gate: no matching project test command detected.",
2575
+ status: "unavailable",
2576
+ skipReason: "no-project-test-command",
2577
+ failingTests: []
2578
+ };
2579
+ }
2580
+ const fallbackCommands = detectProjectCapabilities(worktreePath).verification.testFallback ?? [];
2581
+ for (const capabilityCommand of nonNodeCommands) {
2582
+ const result = await runCapabilityTestCommandWithFallback(
2583
+ worktreePath,
2584
+ capabilityCommand,
2585
+ fallbackCommands,
2586
+ { timeoutMs, tailLines: maxTailLines, start }
2587
+ );
2588
+ results.push(result);
2589
+ if (result.status !== "passed") break;
2590
+ }
2591
+ }
2592
+ if (results.length === 0) {
2593
+ return {
2594
+ command,
2595
+ exitCode: -1,
2596
+ durationMs: Date.now() - start,
2597
+ outputTail: "Skipped deterministic test gate: no matching project test command detected.",
2598
+ status: "unavailable",
2599
+ skipReason: "no-project-test-command",
2600
+ failingTests: [],
2601
+ language: "node"
2602
+ };
2603
+ }
2604
+ const combined = combineVitestPlanResults(results);
2605
+ if (skippedAffectedGraphReason) {
2606
+ combined.outputTail = truncateToByteLimit(
2607
+ [combined.outputTail, skippedAffectedGraphReason].filter(Boolean).join("\n\n"),
2608
+ 1e5
2609
+ );
2610
+ }
2611
+ return combined;
2612
+ }
2613
+ function buildTestCommand(runner, testFiles, worktreePath) {
2614
+ const filesArg = testFiles.map((f) => `"${f}"`).join(" ");
2615
+ const root = worktreePath ?? "";
2616
+ switch (runner) {
2617
+ case "vitest":
2618
+ case "jest":
2619
+ case "mocha":
2620
+ case "ava":
2621
+ case "node-test":
2622
+ return resolveScopedNodeTestInvocation(runner, testFiles, root)?.display ?? "";
2623
+ case "pytest":
2624
+ return `pytest ${filesArg}`.trim();
2625
+ case "unittest":
2626
+ return detectPythonUnittestCommand(detectProjectCapabilities(root)) ?? "python3 -m unittest discover";
2627
+ case "go":
2628
+ return selectRunnerLanguageResolverCommand(
2629
+ detectProjectCapabilities(root).verification.test,
2630
+ "go"
2631
+ ) ?? "go test ./...";
2632
+ case "cargo":
2633
+ return selectRunnerLanguageResolverCommand(
2634
+ detectProjectCapabilities(root).verification.test,
2635
+ "cargo"
2636
+ ) ?? "cargo test --locked";
2637
+ case "maven":
2638
+ return selectRunnerLanguageResolverCommand(
2639
+ detectProjectCapabilities(root).verification.test,
2640
+ "maven"
2641
+ ) ?? "mvn test";
2642
+ case "gradle":
2643
+ return selectRunnerLanguageResolverCommand(
2644
+ detectProjectCapabilities(root).verification.test,
2645
+ "gradle"
2646
+ ) ?? "gradle test";
2647
+ case "powershell":
2648
+ return "pwsh -NoProfile -Command Invoke-Pester";
2649
+ default:
2650
+ throw new Error(`Unknown test runner: ${runner}`);
2651
+ }
2652
+ }
2653
+ function parseTestOutput(runner, output) {
2654
+ const fallback = {
2655
+ testsRun: 0,
2656
+ testsPassed: 0,
2657
+ testsFailed: 0,
2658
+ metricsMeasured: false
2659
+ };
2660
+ if (!output) {
2661
+ return fallback;
2662
+ }
2663
+ try {
2664
+ if (runner === "vitest") {
2665
+ return asMeasuredMetrics(parseVitestOutput(output));
2666
+ } else if (runner === "jest") {
2667
+ return asMeasuredMetrics(parseJestOutput(output));
2668
+ } else if (runner === "mocha" || runner === "ava") {
2669
+ return asMeasuredMetrics(parseMochaStyleOutput(output));
2670
+ } else if (runner === "pytest") {
2671
+ return asMeasuredMetrics(parsePytestOutput(output));
2672
+ } else if (runner === "unittest") {
2673
+ return asMeasuredMetrics(parseUnittestOutput(output));
2674
+ } else if (
2675
+ // node:test emits TAP or (Node 24 default) spec; the generic parser
2676
+ // reads both the TAP plan/trailer and the spec tests/pass/fail footer.
2677
+ runner === "node-test" || runner === "go" || runner === "cargo" || runner === "maven" || runner === "gradle" || runner === "powershell" || runner === "generic"
2678
+ ) {
2679
+ return parseGenericPassFailOutput(output);
2680
+ }
2681
+ } catch {
2682
+ return fallback;
2683
+ }
2684
+ return fallback;
2685
+ }
2686
+ function extractGenericFailures(output) {
2687
+ return output.split(/\r?\n/).filter((line) => /\b(fail|failed|error)\b/i.test(line)).map((line) => line.trim()).filter(Boolean).slice(0, 20);
2688
+ }
2689
+ function parseVitestOutput(output) {
2690
+ const testMatch = output.match(/Tests\s+(.+?)(?:\n|$)/);
2691
+ if (testMatch) {
2692
+ const summary = testMatch[1] ?? "";
2693
+ const passed = parseInt(summary.match(/(\d+)\s+passed/)?.[1] || "0", 10);
2694
+ const failed = parseInt(summary.match(/(\d+)\s+failed/)?.[1] || "0", 10);
2695
+ return {
2696
+ testsRun: passed + failed,
2697
+ testsPassed: passed,
2698
+ testsFailed: failed
2699
+ };
2700
+ }
2701
+ return { testsRun: 0, testsPassed: 0, testsFailed: 0 };
2702
+ }
2703
+ function parseJestOutput(output) {
2704
+ const testMatch = output.match(/Tests:\s+(?:(\d+)\s+failed,\s+)?(\d+)\s+passed,\s+(\d+)\s+total/);
2705
+ if (testMatch) {
2706
+ const failed = parseInt(testMatch[1] || "0", 10);
2707
+ const passed = parseInt(testMatch[2] || "0", 10);
2708
+ const total = parseInt(testMatch[3] || "0", 10);
2709
+ return {
2710
+ testsRun: total,
2711
+ testsPassed: passed,
2712
+ testsFailed: failed
2713
+ };
2714
+ }
2715
+ return { testsRun: 0, testsPassed: 0, testsFailed: 0 };
2716
+ }
2717
+ function parseMochaStyleOutput(output) {
2718
+ const mochaPassing = output.match(/^\s*(\d+)\s+passing\b/m);
2719
+ const mochaFailing = output.match(/^\s*(\d+)\s+failing\b/m);
2720
+ if (mochaPassing || mochaFailing) {
2721
+ const passed = Number(mochaPassing?.[1] ?? 0);
2722
+ const failed = Number(mochaFailing?.[1] ?? 0);
2723
+ return { testsRun: passed + failed, testsPassed: passed, testsFailed: failed };
2724
+ }
2725
+ const avaPassed = output.match(/^\s*(\d+)\s+tests?\s+passed\b/m);
2726
+ const avaFailed = output.match(/^\s*(\d+)\s+tests?\s+failed\b/m);
2727
+ if (avaPassed || avaFailed) {
2728
+ const passed = Number(avaPassed?.[1] ?? 0);
2729
+ const failed = Number(avaFailed?.[1] ?? 0);
2730
+ return { testsRun: passed + failed, testsPassed: passed, testsFailed: failed };
2731
+ }
2732
+ const tap = parseTapSummary(output);
2733
+ if (tap) return tap;
2734
+ return { testsRun: 0, testsPassed: 0, testsFailed: 0 };
2735
+ }
2736
+ function parseTapSummary(output) {
2737
+ const tapTests = Number(output.match(/^#\s+tests\s+(\d+)\s*$/im)?.[1] ?? NaN);
2738
+ if (Number.isFinite(tapTests)) {
2739
+ const tapPassed = Number(output.match(/^#\s+pass\s+(\d+)\s*$/im)?.[1] ?? 0);
2740
+ const tapFailed = Number(output.match(/^#\s+fail\s+(\d+)\s*$/im)?.[1] ?? 0);
2741
+ const tapCancelled = Number(output.match(/^#\s+cancelled\s+(\d+)\s*$/im)?.[1] ?? 0);
2742
+ return {
2743
+ testsRun: tapTests,
2744
+ testsPassed: tapPassed,
2745
+ testsFailed: tapFailed + tapCancelled
2746
+ };
2747
+ }
2748
+ const resultLines = output.split(/\r?\n/).map((line) => line.trim()).filter((line) => /^(?:not\s+ok|ok)\s+\d+\b/i.test(line));
2749
+ if (resultLines.length > 0) {
2750
+ const failed = resultLines.filter((line) => /^not\s+ok\b/i.test(line)).length;
2751
+ const passed = resultLines.length - failed;
2752
+ return { testsRun: resultLines.length, testsPassed: passed, testsFailed: failed };
2753
+ }
2754
+ return void 0;
2755
+ }
2756
+ function parseUnittestOutput(output) {
2757
+ const sumMatches = (pattern) => {
2758
+ let total = 0;
2759
+ for (const match of output.matchAll(pattern)) {
2760
+ total += Number(match[1] ?? 0);
2761
+ }
2762
+ return total;
2763
+ };
2764
+ const testsRun = sumMatches(/^[ \t]*Ran[ \t]+(\d+)[ \t]+tests?\b/gim);
2765
+ if (testsRun === 0) {
2766
+ return { testsRun: 0, testsPassed: 0, testsFailed: 0 };
2767
+ }
2768
+ const outcomeLines = Array.from(
2769
+ output.matchAll(/^[ \t]*(?:OK|FAILED)\b[ \t]*(?:\(([^)]*)\))?[ \t]*$/gim)
2770
+ ).map((match) => match[1] ?? "").join(", ");
2771
+ const countIn = (pattern) => {
2772
+ let total = 0;
2773
+ for (const match of outcomeLines.matchAll(pattern)) {
2774
+ total += Number(match[1] ?? 0);
2775
+ }
2776
+ return total;
2777
+ };
2778
+ const failures = countIn(/\bfailures=(\d+)/gi);
2779
+ const errors = countIn(/\berrors=(\d+)/gi);
2780
+ const unexpectedSuccesses = countIn(/\bunexpected\s+successes=(\d+)/gi);
2781
+ const skipped = countIn(/\bskipped=(\d+)/gi);
2782
+ const testsFailed = failures + errors + unexpectedSuccesses;
2783
+ const testsPassed = Math.max(0, testsRun - testsFailed - skipped);
2784
+ return { testsRun, testsPassed, testsFailed };
2785
+ }
2786
+ function parsePytestOutput(output) {
2787
+ const summary = output.match(/=+\s*(.+?)\s*=+\s*$/m)?.[1] ?? output;
2788
+ const passed = Number(summary.match(/(\d+)\s+passed/)?.[1] ?? 0);
2789
+ const failed = Number(summary.match(/(\d+)\s+failed/)?.[1] ?? 0);
2790
+ const errors = Number(summary.match(/(\d+)\s+error/)?.[1] ?? 0);
2791
+ return {
2792
+ testsRun: passed + failed + errors,
2793
+ testsPassed: passed,
2794
+ testsFailed: failed + errors
2795
+ };
2796
+ }
2797
+ function parseNodeSpecSummary(output) {
2798
+ const cleaned = stripAnsiSequences(output);
2799
+ const count = (label) => {
2800
+ const match = cleaned.match(
2801
+ new RegExp(String.raw`^\s*(?:\u2139\s+)?${label}\s+(\d+)\s*$`, "im")
2802
+ )?.[1];
2803
+ return match === void 0 ? void 0 : Number(match);
2804
+ };
2805
+ const tests = count("tests");
2806
+ const pass = count("pass");
2807
+ const fail = count("fail");
2808
+ if (tests === void 0 || pass === void 0 || fail === void 0) {
2809
+ return void 0;
2810
+ }
2811
+ if (!Number.isFinite(tests) || !Number.isFinite(pass) || !Number.isFinite(fail)) {
2812
+ return void 0;
2813
+ }
2814
+ const cancelled = count("cancelled") ?? 0;
2815
+ const skipped = count("skipped") ?? 0;
2816
+ const todo = count("todo") ?? 0;
2817
+ const testsFailed = fail + cancelled;
2818
+ const accounted = pass + fail + cancelled + skipped + todo;
2819
+ return {
2820
+ testsRun: tests,
2821
+ testsPassed: pass,
2822
+ testsFailed,
2823
+ metricsMeasured: tests > 0 && accounted === tests
2824
+ };
2825
+ }
2826
+ function parseGenericPassFailOutput(output) {
2827
+ const tap = parseTapSummary(output);
2828
+ if (tap) {
2829
+ return { ...tap, metricsMeasured: tap.testsRun > 0 };
2830
+ }
2831
+ const spec = parseNodeSpecSummary(output);
2832
+ if (spec) {
2833
+ return spec;
2834
+ }
2835
+ const pester = output.match(
2836
+ /Tests\s+Passed:\s*(\d+)\s*,\s*Failed:\s*(\d+)\s*,\s*Skipped:\s*(\d+)/i
2837
+ );
2838
+ if (pester) {
2839
+ const passed = Number(pester[1] ?? 0);
2840
+ const failed = Number(pester[2] ?? 0);
2841
+ const skipped = Number(pester[3] ?? 0);
2842
+ return {
2843
+ testsRun: passed + failed + skipped,
2844
+ testsPassed: passed,
2845
+ testsFailed: failed,
2846
+ metricsMeasured: passed + failed + skipped > 0
2847
+ };
2848
+ }
2849
+ const surefireMatches = Array.from(
2850
+ output.matchAll(
2851
+ /^\s*(?:\[INFO\]\s*)?Tests run:\s*(\d+),\s*Failures:\s*(\d+),\s*Errors:\s*(\d+)(?:,\s*Skipped:\s*(\d+))?/gim
2852
+ )
2853
+ );
2854
+ if (surefireMatches.length > 0) {
2855
+ let testsRun = 0;
2856
+ let testsFailed = 0;
2857
+ let skipped = 0;
2858
+ for (const match of surefireMatches) {
2859
+ testsRun += Number(match[1] ?? 0);
2860
+ testsFailed += Number(match[2] ?? 0) + Number(match[3] ?? 0);
2861
+ skipped += Number(match[4] ?? 0);
2862
+ }
2863
+ return {
2864
+ testsRun,
2865
+ testsPassed: Math.max(0, testsRun - testsFailed - skipped),
2866
+ testsFailed,
2867
+ metricsMeasured: testsRun > 0
2868
+ };
2869
+ }
2870
+ const gradleCompleted = output.match(/(\d+)\s+tests?\s+completed\b/i);
2871
+ if (gradleCompleted) {
2872
+ const testsRun = Number(gradleCompleted[1] ?? 0);
2873
+ const failedMatch = output.match(/(\d+)\s+failed\b/i);
2874
+ const testsFailed = Number(failedMatch?.[1] ?? 0);
2875
+ return {
2876
+ testsRun,
2877
+ testsPassed: Math.max(0, testsRun - testsFailed),
2878
+ testsFailed,
2879
+ metricsMeasured: testsRun > 0
2880
+ };
2881
+ }
2882
+ const failureZeroStripped = output.replace(/\b(?:failures?|failed|errors?):\s*0\b/gi, "").replace(/\b0\s+(?:failures?|failed|errors?)\b/gi, "").replace(/\u2139\s+fail\s+0\b/gi, "").replace(/\bfail\s+0\b/gi, "");
2883
+ if (/\b(fail|failed|error)\b/i.test(failureZeroStripped)) {
2884
+ return { testsRun: 1, testsPassed: 0, testsFailed: 1, metricsMeasured: false };
2885
+ }
2886
+ const successProse = /\b(ok|pass|passed|test result: ok|BUILD SUCCESS|BUILD SUCCESSFUL)\b/i.test(
2887
+ output
2888
+ );
2889
+ return {
2890
+ testsRun: 0,
2891
+ testsPassed: 0,
2892
+ testsFailed: 0,
2893
+ metricsMeasured: false,
2894
+ successProse
2895
+ };
2896
+ }
2897
+
2898
+ export {
2899
+ runLintOnDiffWithArtifacts,
2900
+ hasPoeticVitestHarness,
2901
+ runTestGate,
2902
+ runDeterministicTestGateWithArtifacts
2903
+ };
2904
+ //# sourceMappingURL=chunk-3ZPQLGV7.js.map