@unbrained/pm-cli 2026.7.15 → 2026.7.17

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 (508) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +23 -2
  3. package/CONTRIBUTING.md +2 -2
  4. package/dist/cli/bootstrap-args.d.ts +2 -115
  5. package/dist/cli/bootstrap-args.js +4 -831
  6. package/dist/cli/bootstrap-args.js.map +1 -1
  7. package/dist/cli/commands/eval.d.ts +4 -64
  8. package/dist/cli/commands/eval.js +4 -153
  9. package/dist/cli/commands/eval.js.map +1 -1
  10. package/dist/cli/commands/linked-test-entry.d.ts +6 -6
  11. package/dist/cli/commands/linked-test-entry.js +4 -65
  12. package/dist/cli/commands/linked-test-entry.js.map +1 -1
  13. package/dist/cli/commands/linked-test-parsers.d.ts +3 -45
  14. package/dist/cli/commands/linked-test-parsers.js +4 -516
  15. package/dist/cli/commands/linked-test-parsers.js.map +1 -1
  16. package/dist/cli/commands/list.d.ts +3 -210
  17. package/dist/cli/commands/list.js +4 -1068
  18. package/dist/cli/commands/list.js.map +1 -1
  19. package/dist/cli/commands/search.d.ts +3 -464
  20. package/dist/cli/commands/search.js +4 -2236
  21. package/dist/cli/commands/search.js.map +1 -1
  22. package/dist/cli/commands/stats.d.ts +6 -66
  23. package/dist/cli/commands/stats.js +4 -157
  24. package/dist/cli/commands/stats.js.map +1 -1
  25. package/dist/cli/commands/telemetry.d.ts +6 -14
  26. package/dist/cli/commands/telemetry.js +4 -349
  27. package/dist/cli/commands/telemetry.js.map +1 -1
  28. package/dist/cli/commands/test-all.d.ts +6 -95
  29. package/dist/cli/commands/test-all.js +4 -439
  30. package/dist/cli/commands/test-all.js.map +1 -1
  31. package/dist/cli/commands/test-runs.d.ts +6 -92
  32. package/dist/cli/commands/test-runs.js +4 -189
  33. package/dist/cli/commands/test-runs.js.map +1 -1
  34. package/dist/cli/commands/test.d.ts +6 -244
  35. package/dist/cli/commands/test.js +4 -1780
  36. package/dist/cli/commands/test.js.map +1 -1
  37. package/dist/cli/commands/update-many.d.ts +15 -29
  38. package/dist/cli/commands/update-many.js +355 -259
  39. package/dist/cli/commands/update-many.js.map +1 -1
  40. package/dist/cli/main.js +140 -133
  41. package/dist/cli/main.js.map +1 -1
  42. package/dist/cli/search-refresh.js +4 -9
  43. package/dist/cli/search-refresh.js.map +1 -1
  44. package/dist/cli/shared-parsers.d.ts +6 -9
  45. package/dist/cli/shared-parsers.js +4 -37
  46. package/dist/cli/shared-parsers.js.map +1 -1
  47. package/dist/cli/telemetry-flush.js +4 -4
  48. package/dist/cli/telemetry-flush.js.map +1 -1
  49. package/dist/cli-bundle/bundle-manifest.json +341 -341
  50. package/dist/cli-bundle/chunks/{append-OJQFUQ4T.js → append-5YF3TO7I.js} +5 -5
  51. package/dist/cli-bundle/chunks/append-JHO5K6RP.js +11 -0
  52. package/dist/cli-bundle/chunks/{chunk-WT3ZEOGH.js → chunk-23TCGBRK.js} +16 -7
  53. package/dist/cli-bundle/chunks/{chunk-WT3ZEOGH.js.map → chunk-23TCGBRK.js.map} +1 -1
  54. package/dist/cli-bundle/chunks/{chunk-BCOFWYW4.js → chunk-2BX74BAS.js} +3 -3
  55. package/dist/cli-bundle/chunks/{chunk-APRVSW2O.js → chunk-2CXL335K.js} +3 -3
  56. package/dist/cli-bundle/chunks/{chunk-KG44YSKD.js → chunk-2FUOXSRN.js} +4 -4
  57. package/dist/cli-bundle/chunks/{chunk-HDH3JUGG.js → chunk-2IPNL3DR.js} +3 -3
  58. package/dist/cli-bundle/chunks/{chunk-J6364LFM.js → chunk-2MPMKJF2.js} +9 -18
  59. package/dist/cli-bundle/chunks/{chunk-J6364LFM.js.map → chunk-2MPMKJF2.js.map} +1 -1
  60. package/dist/cli-bundle/chunks/{chunk-GM5QHQU6.js → chunk-2XOSFSTH.js} +5 -5
  61. package/dist/cli-bundle/chunks/{chunk-K3WII2ME.js → chunk-37DRDP2B.js} +5 -5
  62. package/dist/cli-bundle/chunks/{chunk-2WSE6PO2.js → chunk-37V5MXAU.js} +4 -4
  63. package/dist/cli-bundle/chunks/{chunk-UWQHLMEB.js → chunk-3D4YVTNG.js} +8 -8
  64. package/dist/cli-bundle/chunks/{chunk-PMOSXADO.js → chunk-47HXN6RX.js} +3 -3
  65. package/dist/cli-bundle/chunks/{chunk-6CFNAVTF.js → chunk-5HGZKQUL.js} +4 -4
  66. package/dist/cli-bundle/chunks/{chunk-2IFFUZLC.js → chunk-5UKQLQM2.js} +2 -2
  67. package/dist/cli-bundle/chunks/{chunk-DM4H7FP4.js → chunk-633PKXLT.js} +3 -3
  68. package/dist/cli-bundle/chunks/{chunk-XSJUSQAE.js → chunk-646MQXFW.js} +2 -2
  69. package/dist/cli-bundle/chunks/{chunk-ZI6VQWQ7.js → chunk-66MKH7SZ.js} +4 -4
  70. package/dist/cli-bundle/chunks/{chunk-S6MQESFR.js → chunk-67RO3H4N.js} +4 -4
  71. package/dist/cli-bundle/chunks/{chunk-34L5OT3Y.js → chunk-6DYOZS6C.js} +2 -2
  72. package/dist/cli-bundle/chunks/{chunk-RRM5JYJC.js → chunk-6O44IN44.js} +2 -2
  73. package/dist/cli-bundle/chunks/{chunk-ONG5V5CI.js → chunk-6XAZB6SE.js} +97 -69
  74. package/dist/cli-bundle/chunks/chunk-6XAZB6SE.js.map +1 -0
  75. package/dist/cli-bundle/chunks/{chunk-PENXZX3U.js → chunk-74FKFFXO.js} +2 -2
  76. package/dist/cli-bundle/chunks/{chunk-LPYWLWDS.js → chunk-7CTQ7WW5.js} +37 -37
  77. package/dist/cli-bundle/chunks/chunk-7CTQ7WW5.js.map +1 -0
  78. package/dist/cli-bundle/chunks/{chunk-HO4KXD6I.js → chunk-7H5NNCJ5.js} +4 -4
  79. package/dist/cli-bundle/chunks/{chunk-XXXF6PAQ.js → chunk-7LTCLTRG.js} +69 -61
  80. package/dist/cli-bundle/chunks/chunk-7LTCLTRG.js.map +7 -0
  81. package/dist/cli-bundle/chunks/{chunk-TQSZFPIS.js → chunk-AFGKSHAM.js} +4 -4
  82. package/dist/cli-bundle/chunks/{chunk-JXQUXVMI.js → chunk-AFSV5HBB.js} +77 -7
  83. package/dist/cli-bundle/chunks/{chunk-JXQUXVMI.js.map → chunk-AFSV5HBB.js.map} +1 -1
  84. package/dist/cli-bundle/chunks/{chunk-6N2VXVTQ.js → chunk-ARGDWQ4J.js} +2 -2
  85. package/dist/cli-bundle/chunks/{chunk-3U7ZR6M4.js → chunk-B57RJHBZ.js} +4 -4
  86. package/dist/cli-bundle/chunks/{chunk-7B67ZL4N.js → chunk-B6SH2YNN.js} +75 -5
  87. package/dist/cli-bundle/chunks/{chunk-7B67ZL4N.js.map → chunk-B6SH2YNN.js.map} +1 -1
  88. package/dist/cli-bundle/chunks/{chunk-YCQET3OT.js → chunk-BAP7G3N2.js} +2 -2
  89. package/dist/cli-bundle/chunks/{chunk-QKXHFPYM.js → chunk-BIRYX32V.js} +3 -3
  90. package/dist/cli-bundle/chunks/{chunk-RMLWNPH2.js → chunk-BVLOMU6O.js} +2 -2
  91. package/dist/cli-bundle/chunks/{chunk-YBLZ2VE7.js → chunk-CFSUNEL7.js} +320 -239
  92. package/dist/cli-bundle/chunks/chunk-CFSUNEL7.js.map +7 -0
  93. package/dist/cli-bundle/chunks/{chunk-2VPAVL7O.js → chunk-CKX4WOPC.js} +2 -2
  94. package/dist/cli-bundle/chunks/{chunk-TKOVBP6C.js → chunk-D52ZN3BF.js} +2 -2
  95. package/dist/cli-bundle/chunks/{chunk-KPMKHGEA.js → chunk-D53RTYVI.js} +4 -4
  96. package/dist/cli-bundle/chunks/{chunk-ODALILG3.js → chunk-D5XHO4Q7.js} +2 -2
  97. package/dist/cli-bundle/chunks/{chunk-E2OJMKML.js → chunk-DCC2AQBD.js} +18 -9
  98. package/dist/cli-bundle/chunks/{chunk-E2OJMKML.js.map → chunk-DCC2AQBD.js.map} +1 -1
  99. package/dist/cli-bundle/chunks/{chunk-YAQEBNY7.js → chunk-DDFGYUCQ.js} +4 -4
  100. package/dist/cli-bundle/chunks/{chunk-EAB64KLB.js → chunk-DG2EQRIH.js} +4 -4
  101. package/dist/cli-bundle/chunks/{chunk-IG3SWA4A.js → chunk-EHJFUOXL.js} +3 -3
  102. package/dist/cli-bundle/chunks/{chunk-ONREO4ST.js → chunk-EY7ZE3TG.js} +3 -3
  103. package/dist/cli-bundle/chunks/{chunk-EJEXHTY5.js → chunk-FHOBCGQO.js} +2 -2
  104. package/dist/cli-bundle/chunks/{chunk-H3EIEWGR.js → chunk-FL4D53ND.js} +2 -2
  105. package/dist/cli-bundle/chunks/{chunk-WUJQK4YV.js → chunk-FVNWHUME.js} +4 -4
  106. package/dist/cli-bundle/chunks/{chunk-INU6DKT5.js → chunk-FXFCFL73.js} +5 -5
  107. package/dist/cli-bundle/chunks/{chunk-QEHQ2GVG.js → chunk-FY4RLHSC.js} +2 -2
  108. package/dist/cli-bundle/chunks/{chunk-EACOH7AU.js → chunk-FZGM3PNA.js} +8 -8
  109. package/dist/cli-bundle/chunks/{chunk-FNSPG7MU.js → chunk-G6KM4YKY.js} +7 -7
  110. package/dist/cli-bundle/chunks/{chunk-AHVTB5I5.js → chunk-G6MYGULG.js} +4 -4
  111. package/dist/cli-bundle/chunks/{chunk-TSMHDIW4.js → chunk-GLZKZON6.js} +2 -2
  112. package/dist/cli-bundle/chunks/{chunk-2JKGO6QX.js → chunk-H5IOT54C.js} +4 -4
  113. package/dist/cli-bundle/chunks/{chunk-5ZSLZLDN.js → chunk-HF63SBLC.js} +585 -456
  114. package/dist/cli-bundle/chunks/chunk-HF63SBLC.js.map +1 -0
  115. package/dist/cli-bundle/chunks/{chunk-SELVXEZK.js → chunk-HO4DLBNK.js} +2 -2
  116. package/dist/cli-bundle/chunks/{chunk-3CLU2XZO.js → chunk-HSYV4ZYT.js} +4 -4
  117. package/dist/cli-bundle/chunks/{chunk-EH2OPHBI.js → chunk-HTXXXF45.js} +23 -19
  118. package/dist/cli-bundle/chunks/chunk-HTXXXF45.js.map +1 -0
  119. package/dist/cli-bundle/chunks/{chunk-CRVF2JDM.js → chunk-HXVHBERL.js} +8 -8
  120. package/dist/cli-bundle/chunks/{chunk-NU3IMIEA.js → chunk-I7DIDUSP.js} +2 -2
  121. package/dist/cli-bundle/chunks/{chunk-2NCIPMQP.js → chunk-I7GY4X6Y.js} +2 -2
  122. package/dist/cli-bundle/chunks/{chunk-JYFOV7FC.js → chunk-IE5KRAKN.js} +4 -4
  123. package/dist/cli-bundle/chunks/{chunk-UY2ACEMF.js → chunk-ILVOOAT4.js} +5 -5
  124. package/dist/cli-bundle/chunks/{chunk-GOSLKLFE.js → chunk-KH6QAHME.js} +3 -3
  125. package/dist/cli-bundle/chunks/{chunk-J6EY5V4N.js → chunk-KOEZCHRF.js} +9 -9
  126. package/dist/cli-bundle/chunks/{chunk-QKECXBBG.js → chunk-KX62NMZC.js} +3 -3
  127. package/dist/cli-bundle/chunks/{chunk-QKECXBBG.js.map → chunk-KX62NMZC.js.map} +1 -1
  128. package/dist/cli-bundle/chunks/{chunk-WQPUU7XD.js → chunk-L337QKWJ.js} +5 -5
  129. package/dist/cli-bundle/chunks/{chunk-LSG2U345.js → chunk-L6FVNR7X.js} +5 -5
  130. package/dist/cli-bundle/chunks/{chunk-ILX33QXL.js → chunk-LLODAQMP.js} +706 -532
  131. package/dist/cli-bundle/chunks/chunk-LLODAQMP.js.map +7 -0
  132. package/dist/cli-bundle/chunks/{chunk-FMBNM2EN.js → chunk-LSOWTLEM.js} +2 -2
  133. package/dist/cli-bundle/chunks/{chunk-4223PVZT.js → chunk-M7MVOKVV.js} +3 -3
  134. package/dist/cli-bundle/chunks/chunk-MNV226E4.js +834 -0
  135. package/dist/cli-bundle/chunks/chunk-MNV226E4.js.map +1 -0
  136. package/dist/cli-bundle/chunks/{chunk-UMOPHQSU.js → chunk-MR4SHYR4.js} +41 -19
  137. package/dist/cli-bundle/chunks/chunk-MR4SHYR4.js.map +7 -0
  138. package/dist/cli-bundle/chunks/{chunk-BKVG6XOA.js → chunk-MSGETE6I.js} +4 -4
  139. package/dist/cli-bundle/chunks/{chunk-3WM75PWC.js → chunk-N33FD2UI.js} +3 -3
  140. package/dist/cli-bundle/chunks/{chunk-UFXU44HV.js → chunk-N7I2DGLP.js} +4 -4
  141. package/dist/cli-bundle/chunks/{chunk-3S5QVM5H.js → chunk-NCAFUBJX.js} +13 -13
  142. package/dist/cli-bundle/chunks/chunk-NCAFUBJX.js.map +1 -0
  143. package/dist/cli-bundle/chunks/{chunk-6S3YSUYG.js → chunk-NNANAWFH.js} +3 -3
  144. package/dist/cli-bundle/chunks/{chunk-IJIICKVW.js → chunk-NTRQLE2R.js} +2 -2
  145. package/dist/cli-bundle/chunks/{chunk-SDQLJWBO.js → chunk-NVZ6NVHJ.js} +4 -4
  146. package/dist/cli-bundle/chunks/{chunk-H2Z3FYXQ.js → chunk-OWP6QFBV.js} +4 -4
  147. package/dist/cli-bundle/chunks/{chunk-Q7A43DS4.js → chunk-P22HGFFI.js} +2 -2
  148. package/dist/cli-bundle/chunks/{chunk-NLDFBC6J.js → chunk-P56LKFQX.js} +2 -2
  149. package/dist/cli-bundle/chunks/{chunk-NVPZIJVR.js → chunk-PT7MCCGD.js} +2 -2
  150. package/dist/cli-bundle/chunks/{chunk-P74IZQ7A.js → chunk-QKVVV6QO.js} +7 -7
  151. package/dist/cli-bundle/chunks/{chunk-5JLUII3O.js → chunk-QNUAZYGW.js} +321 -240
  152. package/dist/cli-bundle/chunks/chunk-QNUAZYGW.js.map +1 -0
  153. package/dist/cli-bundle/chunks/{chunk-QIPLHNP7.js → chunk-QWBKN3QC.js} +5 -5
  154. package/dist/cli-bundle/chunks/{chunk-7PIWCHTW.js → chunk-R5XTTZSJ.js} +5 -5
  155. package/dist/cli-bundle/chunks/{chunk-JOUQZENX.js → chunk-RC4UOUXA.js} +3 -3
  156. package/dist/cli-bundle/chunks/{chunk-BEP7WJA2.js → chunk-RGMWJLXF.js} +4 -4
  157. package/dist/cli-bundle/chunks/{chunk-NP22ERDF.js → chunk-RTBX3C4C.js} +3 -3
  158. package/dist/cli-bundle/chunks/{chunk-HYB5AZ63.js → chunk-S46R2M3W.js} +117 -71
  159. package/dist/cli-bundle/chunks/chunk-S46R2M3W.js.map +7 -0
  160. package/dist/cli-bundle/chunks/{chunk-H5APFTHZ.js → chunk-S6FF7VW6.js} +18 -18
  161. package/dist/cli-bundle/chunks/chunk-S6FF7VW6.js.map +7 -0
  162. package/dist/cli-bundle/chunks/{chunk-UXONS674.js → chunk-SIJV365F.js} +54 -55
  163. package/dist/cli-bundle/chunks/chunk-SIJV365F.js.map +1 -0
  164. package/dist/cli-bundle/chunks/{chunk-7Z4LKRS4.js → chunk-SPFZV2GR.js} +9 -9
  165. package/dist/cli-bundle/chunks/{chunk-ULTHRDBP.js → chunk-TM5CIO3F.js} +3 -3
  166. package/dist/cli-bundle/chunks/{chunk-4XQ3BDV4.js → chunk-V3VBXQQV.js} +36 -36
  167. package/dist/cli-bundle/chunks/chunk-V3VBXQQV.js.map +7 -0
  168. package/dist/cli-bundle/chunks/{chunk-YAROI3PD.js → chunk-V7MP6YTN.js} +7 -7
  169. package/dist/cli-bundle/chunks/{chunk-OW4JWD5M.js → chunk-VAHZIPWS.js} +4 -4
  170. package/dist/cli-bundle/chunks/{chunk-DYH63FX7.js → chunk-VE6ZSTQW.js} +4 -4
  171. package/dist/cli-bundle/chunks/{chunk-3AUGG2DP.js → chunk-W5E2UUSH.js} +3 -3
  172. package/dist/cli-bundle/chunks/{chunk-BSEQUTQP.js → chunk-WACRQ26A.js} +2 -2
  173. package/dist/cli-bundle/chunks/{chunk-BSEQUTQP.js.map → chunk-WACRQ26A.js.map} +1 -1
  174. package/dist/cli-bundle/chunks/{chunk-UOHFKBUV.js → chunk-WL3SS45P.js} +3 -3
  175. package/dist/cli-bundle/chunks/{chunk-QKJGPFAF.js → chunk-WU3KAN6A.js} +3 -3
  176. package/dist/cli-bundle/chunks/{chunk-IA5FKNII.js → chunk-X2MGQMZO.js} +2 -2
  177. package/dist/cli-bundle/chunks/{chunk-TD3LVC7D.js → chunk-X5YCTFKT.js} +3 -3
  178. package/dist/cli-bundle/chunks/{chunk-B7PE22W6.js → chunk-XC2HEEOV.js} +4 -4
  179. package/dist/cli-bundle/chunks/{chunk-J5AOEGDC.js → chunk-XNPMDSQQ.js} +8 -8
  180. package/dist/cli-bundle/chunks/{chunk-K2X6U4UA.js → chunk-XXLXJL7V.js} +4 -4
  181. package/dist/cli-bundle/chunks/chunk-XYJK6GIQ.js +851 -0
  182. package/dist/cli-bundle/chunks/chunk-XYJK6GIQ.js.map +7 -0
  183. package/dist/cli-bundle/chunks/{chunk-RLCHOOHC.js → chunk-YJSURTBB.js} +2 -2
  184. package/dist/cli-bundle/chunks/{chunk-PGY23YTC.js → chunk-YKFHF37B.js} +3 -3
  185. package/dist/cli-bundle/chunks/{chunk-JFTKLTEF.js → chunk-YQCWK2MB.js} +4 -4
  186. package/dist/cli-bundle/chunks/{chunk-EYLCSJAI.js → chunk-YQEZWI3R.js} +2 -2
  187. package/dist/cli-bundle/chunks/close-BEP7MHF3.js +12 -0
  188. package/dist/cli-bundle/chunks/{close-CWODTPKG.js → close-Y6QFUJQN.js} +5 -5
  189. package/dist/cli-bundle/chunks/{close-many-CQFUY7MR.js → close-many-JJFW7KTT.js} +14 -14
  190. package/dist/cli-bundle/chunks/close-many-QJ6FKJUE.js +23 -0
  191. package/dist/cli-bundle/chunks/comments-2AOZQ5D2.js +13 -0
  192. package/dist/cli-bundle/chunks/{comments-WGLHR7LB.js → comments-TMHMALA5.js} +7 -7
  193. package/dist/cli-bundle/chunks/{copy-LXVDXH7B.js → copy-FWQA5OU4.js} +4 -4
  194. package/dist/cli-bundle/chunks/copy-N3LCQBMC.js +9 -0
  195. package/dist/cli-bundle/chunks/{create-LBVCYMEG.js → create-AQ5SIGZC.js} +9 -9
  196. package/dist/cli-bundle/chunks/{create-J5U6ND4K.js → create-KOGQ3JKD.js} +9 -9
  197. package/dist/cli-bundle/chunks/delete-6G3MBZ6S.js +10 -0
  198. package/dist/cli-bundle/chunks/{delete-PMJBNY5G.js → delete-YYYFOSEA.js} +4 -4
  199. package/dist/cli-bundle/chunks/{deps-OA26IS25.js → deps-5NC4IZH7.js} +5 -5
  200. package/dist/cli-bundle/chunks/{deps-JZ7TMVCB.js → deps-EVTOQMKW.js} +5 -5
  201. package/dist/cli-bundle/chunks/{docs-FEWB2DQB.js → docs-53NUGMIQ.js} +6 -6
  202. package/dist/cli-bundle/chunks/docs-OWRGDMNY.js +14 -0
  203. package/dist/cli-bundle/chunks/{files-EFIWKFTM.js → files-3PXGXYDB.js} +6 -6
  204. package/dist/cli-bundle/chunks/{files-6YFBJRBG.js → files-EGLKHD7O.js} +6 -6
  205. package/dist/cli-bundle/chunks/focus-KZLIA6WS.js +10 -0
  206. package/dist/cli-bundle/chunks/{focus-4QJR7FOQ.js → focus-SRPASFTN.js} +5 -5
  207. package/dist/cli-bundle/chunks/{history-compact-CKRPDTJN.js → history-compact-G4DULDCX.js} +6 -6
  208. package/dist/cli-bundle/chunks/history-compact-HHIUOMZ7.js +16 -0
  209. package/dist/cli-bundle/chunks/{history-redact-BB3TGDAE.js → history-redact-IUSJ6X3E.js} +4 -4
  210. package/dist/cli-bundle/chunks/{history-redact-D225BHOZ.js → history-redact-THHGRQXV.js} +4 -4
  211. package/dist/cli-bundle/chunks/history-repair-KG7SWXI6.js +16 -0
  212. package/dist/cli-bundle/chunks/{history-repair-RQXKQHL4.js → history-repair-LUQWRS7X.js} +6 -6
  213. package/dist/cli-bundle/chunks/{learnings-JLNLCOL5.js → learnings-2MRNBFJF.js} +7 -7
  214. package/dist/cli-bundle/chunks/learnings-ZVHSALJY.js +13 -0
  215. package/dist/cli-bundle/chunks/{notes-GB47XXQQ.js → notes-73JWKWUD.js} +7 -7
  216. package/dist/cli-bundle/chunks/notes-BAKUL5DJ.js +13 -0
  217. package/dist/cli-bundle/chunks/{plan-VDCJ2PCN.js → plan-AZPMCG37.js} +10 -10
  218. package/dist/cli-bundle/chunks/plan-LEAGLPGP.js +24 -0
  219. package/dist/cli-bundle/chunks/{profile-IVXQEL3D.js → profile-AGUKS52S.js} +9 -9
  220. package/dist/cli-bundle/chunks/{profile-FAU7NZML.js → profile-U2B6Y7GE.js} +9 -9
  221. package/dist/cli-bundle/chunks/{register-list-query-UL4UKBBN.js → register-list-query-A5KRJ5J2.js} +16 -16
  222. package/dist/cli-bundle/chunks/{register-list-query-DKA3EH5D.js → register-list-query-NEYP3TXO.js} +16 -16
  223. package/dist/cli-bundle/chunks/{register-mutation-RBBJ52DK.js → register-mutation-6LOPBAHC.js} +29 -29
  224. package/dist/cli-bundle/chunks/{register-mutation-ARFHRW55.js → register-mutation-GCZOALNJ.js} +29 -29
  225. package/dist/cli-bundle/chunks/{register-operations-ZIBBRSED.js → register-operations-6ZZIF27A.js} +35 -35
  226. package/dist/cli-bundle/chunks/{register-operations-ZUJ5JWPE.js → register-operations-REDIAEGI.js} +35 -35
  227. package/dist/cli-bundle/chunks/{register-setup-TDCGWIOS.js → register-setup-BHPMN5SK.js} +15 -15
  228. package/dist/cli-bundle/chunks/{register-setup-BCVLFEYS.js → register-setup-J3JS2ZVT.js} +15 -15
  229. package/dist/cli-bundle/chunks/{restore-25DLT2Q2.js → restore-E3PRGDN3.js} +6 -6
  230. package/dist/cli-bundle/chunks/restore-KIUYTAEJ.js +14 -0
  231. package/dist/cli-bundle/chunks/{schema-FNU3WE4O.js → schema-5JNFQFUW.js} +6 -6
  232. package/dist/cli-bundle/chunks/{schema-NBCM3RAD.js → schema-TMIW4XZC.js} +6 -6
  233. package/dist/cli-bundle/chunks/update-PQQHLYCC.js +21 -0
  234. package/dist/cli-bundle/chunks/{update-XHSIAIXE.js → update-SA6AG23P.js} +12 -12
  235. package/dist/cli-bundle/chunks/update-many-RQVTFJPD.js +36 -0
  236. package/dist/cli-bundle/chunks/update-many-TV3L3KBX.js +32 -0
  237. package/dist/cli-bundle/main.js +153 -855
  238. package/dist/cli-bundle/main.js.map +4 -4
  239. package/dist/cli-bundle/sdk-runtime.js +54 -54
  240. package/dist/cli-bundle/sdk-testing.js +6 -6
  241. package/dist/cli-bundle/sdk.js +195 -59
  242. package/dist/cli-bundle/sdk.js.map +3 -3
  243. package/dist/core/extensions/item-fields.js +2 -2
  244. package/dist/core/extensions/item-fields.js.map +1 -1
  245. package/dist/sdk/cli-bootstrap.d.ts +122 -0
  246. package/dist/sdk/cli-bootstrap.js +879 -0
  247. package/dist/sdk/cli-bootstrap.js.map +1 -0
  248. package/dist/sdk/eval.d.ts +66 -0
  249. package/dist/sdk/eval.js +186 -0
  250. package/dist/sdk/eval.js.map +1 -0
  251. package/dist/sdk/index.d.ts +16 -4
  252. package/dist/sdk/index.js +18 -6
  253. package/dist/sdk/index.js.map +1 -1
  254. package/dist/{cli/commands → sdk/query}/item-filter-options.d.ts +1 -1
  255. package/dist/{cli/commands → sdk/query}/item-filter-options.js +3 -3
  256. package/dist/sdk/query/item-filter-options.js.map +1 -0
  257. package/dist/sdk/query/list.d.ts +254 -0
  258. package/dist/sdk/query/list.js +1073 -0
  259. package/dist/sdk/query/list.js.map +1 -0
  260. package/dist/sdk/query/parsers.d.ts +9 -0
  261. package/dist/sdk/query/parsers.js +45 -0
  262. package/dist/sdk/query/parsers.js.map +1 -0
  263. package/dist/{cli/commands → sdk/query}/search-pagination.js +4 -4
  264. package/dist/sdk/query/search-pagination.js.map +1 -0
  265. package/dist/{cli/commands → sdk/query}/search-rendering.js +3 -3
  266. package/dist/sdk/query/search-rendering.js.map +1 -0
  267. package/dist/sdk/query/search.d.ts +469 -0
  268. package/dist/sdk/query/search.js +2247 -0
  269. package/dist/sdk/query/search.js.map +1 -0
  270. package/dist/sdk/runtime.d.ts +7 -7
  271. package/dist/sdk/runtime.js +13 -7
  272. package/dist/sdk/runtime.js.map +1 -1
  273. package/dist/sdk/search-refresh-worker.d.ts +2 -0
  274. package/dist/sdk/search-refresh-worker.js +19 -0
  275. package/dist/sdk/search-refresh-worker.js.map +1 -0
  276. package/dist/sdk/stats.d.ts +66 -0
  277. package/dist/sdk/stats.js +151 -0
  278. package/dist/sdk/stats.js.map +1 -0
  279. package/dist/sdk/telemetry-flush.d.ts +2 -0
  280. package/dist/sdk/telemetry-flush.js +14 -0
  281. package/dist/sdk/telemetry-flush.js.map +1 -0
  282. package/dist/sdk/telemetry.d.ts +14 -0
  283. package/dist/sdk/telemetry.js +398 -0
  284. package/dist/sdk/telemetry.js.map +1 -0
  285. package/dist/sdk/test/batch.d.ts +94 -0
  286. package/dist/sdk/test/batch.js +492 -0
  287. package/dist/sdk/test/batch.js.map +1 -0
  288. package/dist/sdk/test/entry.d.ts +6 -0
  289. package/dist/sdk/test/entry.js +74 -0
  290. package/dist/sdk/test/entry.js.map +1 -0
  291. package/dist/sdk/test/execution.d.ts +282 -0
  292. package/dist/sdk/test/execution.js +1817 -0
  293. package/dist/sdk/test/execution.js.map +1 -0
  294. package/dist/sdk/test/parsers.d.ts +48 -0
  295. package/dist/sdk/test/parsers.js +522 -0
  296. package/dist/sdk/test/parsers.js.map +1 -0
  297. package/dist/sdk/test/runs.d.ts +92 -0
  298. package/dist/sdk/test/runs.js +195 -0
  299. package/dist/sdk/test/runs.js.map +1 -0
  300. package/docs/SDK.md +122 -0
  301. package/docs/SDK_PRIMITIVE_INVENTORY.md +5 -3
  302. package/docs/examples/sdk-custom-tool/README.md +27 -0
  303. package/docs/examples/sdk-custom-tool/package.json +13 -0
  304. package/docs/examples/sdk-custom-tool/src/cli.ts +36 -0
  305. package/docs/examples/sdk-custom-tool/src/entry.ts +15 -0
  306. package/docs/examples/sdk-custom-tool/src/index.ts +223 -0
  307. package/marketplace.json +2 -2
  308. package/package.json +4 -4
  309. package/packages/pm-beads/package.json +1 -1
  310. package/packages/pm-calendar/package.json +1 -1
  311. package/packages/pm-command-kit/package.json +1 -1
  312. package/packages/pm-governance-audit/extensions/governance-audit/comments-audit.ts +77 -57
  313. package/packages/pm-governance-audit/extensions/governance-audit/dedupe-audit.ts +202 -194
  314. package/packages/pm-governance-audit/extensions/governance-audit/dedupe-merge.ts +227 -153
  315. package/packages/pm-governance-audit/extensions/governance-audit/normalize.ts +169 -125
  316. package/packages/pm-governance-audit/extensions/governance-audit/runtime-utils.ts +130 -81
  317. package/packages/pm-governance-audit/extensions/governance-audit/sdk.ts +53 -4
  318. package/packages/pm-governance-audit/package.json +1 -1
  319. package/packages/pm-guide-shell/package.json +1 -1
  320. package/packages/pm-kanban/package.json +1 -1
  321. package/packages/pm-lifecycle-hooks/package.json +1 -1
  322. package/packages/pm-linked-test-adapters/package.json +1 -1
  323. package/packages/pm-search-advanced/package.json +1 -1
  324. package/packages/pm-templates/package.json +1 -1
  325. package/packages/pm-todos/package.json +1 -1
  326. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  327. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  328. package/dist/cli/commands/item-filter-options.js.map +0 -1
  329. package/dist/cli/commands/search-pagination.js.map +0 -1
  330. package/dist/cli/commands/search-rendering.js.map +0 -1
  331. package/dist/cli-bundle/chunks/append-UZVHUO74.js +0 -11
  332. package/dist/cli-bundle/chunks/chunk-3S5QVM5H.js.map +0 -1
  333. package/dist/cli-bundle/chunks/chunk-4XQ3BDV4.js.map +0 -7
  334. package/dist/cli-bundle/chunks/chunk-5JLUII3O.js.map +0 -1
  335. package/dist/cli-bundle/chunks/chunk-5ZSLZLDN.js.map +0 -1
  336. package/dist/cli-bundle/chunks/chunk-EH2OPHBI.js.map +0 -1
  337. package/dist/cli-bundle/chunks/chunk-H5APFTHZ.js.map +0 -7
  338. package/dist/cli-bundle/chunks/chunk-HYB5AZ63.js.map +0 -7
  339. package/dist/cli-bundle/chunks/chunk-ILX33QXL.js.map +0 -7
  340. package/dist/cli-bundle/chunks/chunk-LPYWLWDS.js.map +0 -1
  341. package/dist/cli-bundle/chunks/chunk-ONG5V5CI.js.map +0 -1
  342. package/dist/cli-bundle/chunks/chunk-UMOPHQSU.js.map +0 -7
  343. package/dist/cli-bundle/chunks/chunk-UXONS674.js.map +0 -1
  344. package/dist/cli-bundle/chunks/chunk-XXXF6PAQ.js.map +0 -7
  345. package/dist/cli-bundle/chunks/chunk-YBLZ2VE7.js.map +0 -7
  346. package/dist/cli-bundle/chunks/chunk-YXSHIAUJ.js +0 -58
  347. package/dist/cli-bundle/chunks/chunk-YXSHIAUJ.js.map +0 -1
  348. package/dist/cli-bundle/chunks/chunk-ZKRZY773.js +0 -68
  349. package/dist/cli-bundle/chunks/chunk-ZKRZY773.js.map +0 -7
  350. package/dist/cli-bundle/chunks/close-W6LI2PKM.js +0 -12
  351. package/dist/cli-bundle/chunks/close-many-DLDDVSH5.js +0 -23
  352. package/dist/cli-bundle/chunks/comments-E3TNTK24.js +0 -13
  353. package/dist/cli-bundle/chunks/copy-Q5ZJPUKR.js +0 -9
  354. package/dist/cli-bundle/chunks/delete-WNHB3LYW.js +0 -10
  355. package/dist/cli-bundle/chunks/docs-HA2AIDBB.js +0 -14
  356. package/dist/cli-bundle/chunks/focus-POIW5LTJ.js +0 -10
  357. package/dist/cli-bundle/chunks/history-compact-FWG2C7FZ.js +0 -16
  358. package/dist/cli-bundle/chunks/history-repair-6GEAM7HE.js +0 -16
  359. package/dist/cli-bundle/chunks/learnings-RSNLSWDC.js +0 -13
  360. package/dist/cli-bundle/chunks/notes-2WDH6DXU.js +0 -13
  361. package/dist/cli-bundle/chunks/plan-DOVI2VMW.js +0 -24
  362. package/dist/cli-bundle/chunks/restore-YPMVUUEX.js +0 -14
  363. package/dist/cli-bundle/chunks/update-WWBYOPXO.js +0 -21
  364. package/dist/cli-bundle/chunks/update-many-OUGIU5SF.js +0 -32
  365. package/dist/cli-bundle/chunks/update-many-TA7NGQBO.js +0 -36
  366. /package/dist/cli-bundle/chunks/{append-OJQFUQ4T.js.map → append-5YF3TO7I.js.map} +0 -0
  367. /package/dist/cli-bundle/chunks/{append-UZVHUO74.js.map → append-JHO5K6RP.js.map} +0 -0
  368. /package/dist/cli-bundle/chunks/{chunk-BCOFWYW4.js.map → chunk-2BX74BAS.js.map} +0 -0
  369. /package/dist/cli-bundle/chunks/{chunk-APRVSW2O.js.map → chunk-2CXL335K.js.map} +0 -0
  370. /package/dist/cli-bundle/chunks/{chunk-KG44YSKD.js.map → chunk-2FUOXSRN.js.map} +0 -0
  371. /package/dist/cli-bundle/chunks/{chunk-HDH3JUGG.js.map → chunk-2IPNL3DR.js.map} +0 -0
  372. /package/dist/cli-bundle/chunks/{chunk-GM5QHQU6.js.map → chunk-2XOSFSTH.js.map} +0 -0
  373. /package/dist/cli-bundle/chunks/{chunk-K3WII2ME.js.map → chunk-37DRDP2B.js.map} +0 -0
  374. /package/dist/cli-bundle/chunks/{chunk-2WSE6PO2.js.map → chunk-37V5MXAU.js.map} +0 -0
  375. /package/dist/cli-bundle/chunks/{chunk-UWQHLMEB.js.map → chunk-3D4YVTNG.js.map} +0 -0
  376. /package/dist/cli-bundle/chunks/{chunk-PMOSXADO.js.map → chunk-47HXN6RX.js.map} +0 -0
  377. /package/dist/cli-bundle/chunks/{chunk-6CFNAVTF.js.map → chunk-5HGZKQUL.js.map} +0 -0
  378. /package/dist/cli-bundle/chunks/{chunk-2IFFUZLC.js.map → chunk-5UKQLQM2.js.map} +0 -0
  379. /package/dist/cli-bundle/chunks/{chunk-DM4H7FP4.js.map → chunk-633PKXLT.js.map} +0 -0
  380. /package/dist/cli-bundle/chunks/{chunk-XSJUSQAE.js.map → chunk-646MQXFW.js.map} +0 -0
  381. /package/dist/cli-bundle/chunks/{chunk-ZI6VQWQ7.js.map → chunk-66MKH7SZ.js.map} +0 -0
  382. /package/dist/cli-bundle/chunks/{chunk-S6MQESFR.js.map → chunk-67RO3H4N.js.map} +0 -0
  383. /package/dist/cli-bundle/chunks/{chunk-34L5OT3Y.js.map → chunk-6DYOZS6C.js.map} +0 -0
  384. /package/dist/cli-bundle/chunks/{chunk-RRM5JYJC.js.map → chunk-6O44IN44.js.map} +0 -0
  385. /package/dist/cli-bundle/chunks/{chunk-PENXZX3U.js.map → chunk-74FKFFXO.js.map} +0 -0
  386. /package/dist/cli-bundle/chunks/{chunk-HO4KXD6I.js.map → chunk-7H5NNCJ5.js.map} +0 -0
  387. /package/dist/cli-bundle/chunks/{chunk-TQSZFPIS.js.map → chunk-AFGKSHAM.js.map} +0 -0
  388. /package/dist/cli-bundle/chunks/{chunk-6N2VXVTQ.js.map → chunk-ARGDWQ4J.js.map} +0 -0
  389. /package/dist/cli-bundle/chunks/{chunk-3U7ZR6M4.js.map → chunk-B57RJHBZ.js.map} +0 -0
  390. /package/dist/cli-bundle/chunks/{chunk-YCQET3OT.js.map → chunk-BAP7G3N2.js.map} +0 -0
  391. /package/dist/cli-bundle/chunks/{chunk-QKXHFPYM.js.map → chunk-BIRYX32V.js.map} +0 -0
  392. /package/dist/cli-bundle/chunks/{chunk-RMLWNPH2.js.map → chunk-BVLOMU6O.js.map} +0 -0
  393. /package/dist/cli-bundle/chunks/{chunk-2VPAVL7O.js.map → chunk-CKX4WOPC.js.map} +0 -0
  394. /package/dist/cli-bundle/chunks/{chunk-TKOVBP6C.js.map → chunk-D52ZN3BF.js.map} +0 -0
  395. /package/dist/cli-bundle/chunks/{chunk-KPMKHGEA.js.map → chunk-D53RTYVI.js.map} +0 -0
  396. /package/dist/cli-bundle/chunks/{chunk-ODALILG3.js.map → chunk-D5XHO4Q7.js.map} +0 -0
  397. /package/dist/cli-bundle/chunks/{chunk-YAQEBNY7.js.map → chunk-DDFGYUCQ.js.map} +0 -0
  398. /package/dist/cli-bundle/chunks/{chunk-EAB64KLB.js.map → chunk-DG2EQRIH.js.map} +0 -0
  399. /package/dist/cli-bundle/chunks/{chunk-IG3SWA4A.js.map → chunk-EHJFUOXL.js.map} +0 -0
  400. /package/dist/cli-bundle/chunks/{chunk-ONREO4ST.js.map → chunk-EY7ZE3TG.js.map} +0 -0
  401. /package/dist/cli-bundle/chunks/{chunk-EJEXHTY5.js.map → chunk-FHOBCGQO.js.map} +0 -0
  402. /package/dist/cli-bundle/chunks/{chunk-H3EIEWGR.js.map → chunk-FL4D53ND.js.map} +0 -0
  403. /package/dist/cli-bundle/chunks/{chunk-WUJQK4YV.js.map → chunk-FVNWHUME.js.map} +0 -0
  404. /package/dist/cli-bundle/chunks/{chunk-INU6DKT5.js.map → chunk-FXFCFL73.js.map} +0 -0
  405. /package/dist/cli-bundle/chunks/{chunk-QEHQ2GVG.js.map → chunk-FY4RLHSC.js.map} +0 -0
  406. /package/dist/cli-bundle/chunks/{chunk-EACOH7AU.js.map → chunk-FZGM3PNA.js.map} +0 -0
  407. /package/dist/cli-bundle/chunks/{chunk-FNSPG7MU.js.map → chunk-G6KM4YKY.js.map} +0 -0
  408. /package/dist/cli-bundle/chunks/{chunk-AHVTB5I5.js.map → chunk-G6MYGULG.js.map} +0 -0
  409. /package/dist/cli-bundle/chunks/{chunk-TSMHDIW4.js.map → chunk-GLZKZON6.js.map} +0 -0
  410. /package/dist/cli-bundle/chunks/{chunk-2JKGO6QX.js.map → chunk-H5IOT54C.js.map} +0 -0
  411. /package/dist/cli-bundle/chunks/{chunk-SELVXEZK.js.map → chunk-HO4DLBNK.js.map} +0 -0
  412. /package/dist/cli-bundle/chunks/{chunk-3CLU2XZO.js.map → chunk-HSYV4ZYT.js.map} +0 -0
  413. /package/dist/cli-bundle/chunks/{chunk-CRVF2JDM.js.map → chunk-HXVHBERL.js.map} +0 -0
  414. /package/dist/cli-bundle/chunks/{chunk-NU3IMIEA.js.map → chunk-I7DIDUSP.js.map} +0 -0
  415. /package/dist/cli-bundle/chunks/{chunk-2NCIPMQP.js.map → chunk-I7GY4X6Y.js.map} +0 -0
  416. /package/dist/cli-bundle/chunks/{chunk-JYFOV7FC.js.map → chunk-IE5KRAKN.js.map} +0 -0
  417. /package/dist/cli-bundle/chunks/{chunk-UY2ACEMF.js.map → chunk-ILVOOAT4.js.map} +0 -0
  418. /package/dist/cli-bundle/chunks/{chunk-GOSLKLFE.js.map → chunk-KH6QAHME.js.map} +0 -0
  419. /package/dist/cli-bundle/chunks/{chunk-J6EY5V4N.js.map → chunk-KOEZCHRF.js.map} +0 -0
  420. /package/dist/cli-bundle/chunks/{chunk-WQPUU7XD.js.map → chunk-L337QKWJ.js.map} +0 -0
  421. /package/dist/cli-bundle/chunks/{chunk-LSG2U345.js.map → chunk-L6FVNR7X.js.map} +0 -0
  422. /package/dist/cli-bundle/chunks/{chunk-FMBNM2EN.js.map → chunk-LSOWTLEM.js.map} +0 -0
  423. /package/dist/cli-bundle/chunks/{chunk-4223PVZT.js.map → chunk-M7MVOKVV.js.map} +0 -0
  424. /package/dist/cli-bundle/chunks/{chunk-BKVG6XOA.js.map → chunk-MSGETE6I.js.map} +0 -0
  425. /package/dist/cli-bundle/chunks/{chunk-3WM75PWC.js.map → chunk-N33FD2UI.js.map} +0 -0
  426. /package/dist/cli-bundle/chunks/{chunk-UFXU44HV.js.map → chunk-N7I2DGLP.js.map} +0 -0
  427. /package/dist/cli-bundle/chunks/{chunk-6S3YSUYG.js.map → chunk-NNANAWFH.js.map} +0 -0
  428. /package/dist/cli-bundle/chunks/{chunk-IJIICKVW.js.map → chunk-NTRQLE2R.js.map} +0 -0
  429. /package/dist/cli-bundle/chunks/{chunk-SDQLJWBO.js.map → chunk-NVZ6NVHJ.js.map} +0 -0
  430. /package/dist/cli-bundle/chunks/{chunk-H2Z3FYXQ.js.map → chunk-OWP6QFBV.js.map} +0 -0
  431. /package/dist/cli-bundle/chunks/{chunk-Q7A43DS4.js.map → chunk-P22HGFFI.js.map} +0 -0
  432. /package/dist/cli-bundle/chunks/{chunk-NLDFBC6J.js.map → chunk-P56LKFQX.js.map} +0 -0
  433. /package/dist/cli-bundle/chunks/{chunk-NVPZIJVR.js.map → chunk-PT7MCCGD.js.map} +0 -0
  434. /package/dist/cli-bundle/chunks/{chunk-P74IZQ7A.js.map → chunk-QKVVV6QO.js.map} +0 -0
  435. /package/dist/cli-bundle/chunks/{chunk-QIPLHNP7.js.map → chunk-QWBKN3QC.js.map} +0 -0
  436. /package/dist/cli-bundle/chunks/{chunk-7PIWCHTW.js.map → chunk-R5XTTZSJ.js.map} +0 -0
  437. /package/dist/cli-bundle/chunks/{chunk-JOUQZENX.js.map → chunk-RC4UOUXA.js.map} +0 -0
  438. /package/dist/cli-bundle/chunks/{chunk-BEP7WJA2.js.map → chunk-RGMWJLXF.js.map} +0 -0
  439. /package/dist/cli-bundle/chunks/{chunk-NP22ERDF.js.map → chunk-RTBX3C4C.js.map} +0 -0
  440. /package/dist/cli-bundle/chunks/{chunk-7Z4LKRS4.js.map → chunk-SPFZV2GR.js.map} +0 -0
  441. /package/dist/cli-bundle/chunks/{chunk-ULTHRDBP.js.map → chunk-TM5CIO3F.js.map} +0 -0
  442. /package/dist/cli-bundle/chunks/{chunk-YAROI3PD.js.map → chunk-V7MP6YTN.js.map} +0 -0
  443. /package/dist/cli-bundle/chunks/{chunk-OW4JWD5M.js.map → chunk-VAHZIPWS.js.map} +0 -0
  444. /package/dist/cli-bundle/chunks/{chunk-DYH63FX7.js.map → chunk-VE6ZSTQW.js.map} +0 -0
  445. /package/dist/cli-bundle/chunks/{chunk-3AUGG2DP.js.map → chunk-W5E2UUSH.js.map} +0 -0
  446. /package/dist/cli-bundle/chunks/{chunk-UOHFKBUV.js.map → chunk-WL3SS45P.js.map} +0 -0
  447. /package/dist/cli-bundle/chunks/{chunk-QKJGPFAF.js.map → chunk-WU3KAN6A.js.map} +0 -0
  448. /package/dist/cli-bundle/chunks/{chunk-IA5FKNII.js.map → chunk-X2MGQMZO.js.map} +0 -0
  449. /package/dist/cli-bundle/chunks/{chunk-TD3LVC7D.js.map → chunk-X5YCTFKT.js.map} +0 -0
  450. /package/dist/cli-bundle/chunks/{chunk-B7PE22W6.js.map → chunk-XC2HEEOV.js.map} +0 -0
  451. /package/dist/cli-bundle/chunks/{chunk-J5AOEGDC.js.map → chunk-XNPMDSQQ.js.map} +0 -0
  452. /package/dist/cli-bundle/chunks/{chunk-K2X6U4UA.js.map → chunk-XXLXJL7V.js.map} +0 -0
  453. /package/dist/cli-bundle/chunks/{chunk-RLCHOOHC.js.map → chunk-YJSURTBB.js.map} +0 -0
  454. /package/dist/cli-bundle/chunks/{chunk-PGY23YTC.js.map → chunk-YKFHF37B.js.map} +0 -0
  455. /package/dist/cli-bundle/chunks/{chunk-JFTKLTEF.js.map → chunk-YQCWK2MB.js.map} +0 -0
  456. /package/dist/cli-bundle/chunks/{chunk-EYLCSJAI.js.map → chunk-YQEZWI3R.js.map} +0 -0
  457. /package/dist/cli-bundle/chunks/{close-W6LI2PKM.js.map → close-BEP7MHF3.js.map} +0 -0
  458. /package/dist/cli-bundle/chunks/{close-CWODTPKG.js.map → close-Y6QFUJQN.js.map} +0 -0
  459. /package/dist/cli-bundle/chunks/{close-many-CQFUY7MR.js.map → close-many-JJFW7KTT.js.map} +0 -0
  460. /package/dist/cli-bundle/chunks/{close-many-DLDDVSH5.js.map → close-many-QJ6FKJUE.js.map} +0 -0
  461. /package/dist/cli-bundle/chunks/{comments-E3TNTK24.js.map → comments-2AOZQ5D2.js.map} +0 -0
  462. /package/dist/cli-bundle/chunks/{comments-WGLHR7LB.js.map → comments-TMHMALA5.js.map} +0 -0
  463. /package/dist/cli-bundle/chunks/{copy-LXVDXH7B.js.map → copy-FWQA5OU4.js.map} +0 -0
  464. /package/dist/cli-bundle/chunks/{copy-Q5ZJPUKR.js.map → copy-N3LCQBMC.js.map} +0 -0
  465. /package/dist/cli-bundle/chunks/{create-LBVCYMEG.js.map → create-AQ5SIGZC.js.map} +0 -0
  466. /package/dist/cli-bundle/chunks/{create-J5U6ND4K.js.map → create-KOGQ3JKD.js.map} +0 -0
  467. /package/dist/cli-bundle/chunks/{delete-WNHB3LYW.js.map → delete-6G3MBZ6S.js.map} +0 -0
  468. /package/dist/cli-bundle/chunks/{delete-PMJBNY5G.js.map → delete-YYYFOSEA.js.map} +0 -0
  469. /package/dist/cli-bundle/chunks/{deps-OA26IS25.js.map → deps-5NC4IZH7.js.map} +0 -0
  470. /package/dist/cli-bundle/chunks/{deps-JZ7TMVCB.js.map → deps-EVTOQMKW.js.map} +0 -0
  471. /package/dist/cli-bundle/chunks/{docs-FEWB2DQB.js.map → docs-53NUGMIQ.js.map} +0 -0
  472. /package/dist/cli-bundle/chunks/{docs-HA2AIDBB.js.map → docs-OWRGDMNY.js.map} +0 -0
  473. /package/dist/cli-bundle/chunks/{files-EFIWKFTM.js.map → files-3PXGXYDB.js.map} +0 -0
  474. /package/dist/cli-bundle/chunks/{files-6YFBJRBG.js.map → files-EGLKHD7O.js.map} +0 -0
  475. /package/dist/cli-bundle/chunks/{focus-POIW5LTJ.js.map → focus-KZLIA6WS.js.map} +0 -0
  476. /package/dist/cli-bundle/chunks/{focus-4QJR7FOQ.js.map → focus-SRPASFTN.js.map} +0 -0
  477. /package/dist/cli-bundle/chunks/{history-compact-CKRPDTJN.js.map → history-compact-G4DULDCX.js.map} +0 -0
  478. /package/dist/cli-bundle/chunks/{history-compact-FWG2C7FZ.js.map → history-compact-HHIUOMZ7.js.map} +0 -0
  479. /package/dist/cli-bundle/chunks/{history-redact-BB3TGDAE.js.map → history-redact-IUSJ6X3E.js.map} +0 -0
  480. /package/dist/cli-bundle/chunks/{history-redact-D225BHOZ.js.map → history-redact-THHGRQXV.js.map} +0 -0
  481. /package/dist/cli-bundle/chunks/{history-repair-6GEAM7HE.js.map → history-repair-KG7SWXI6.js.map} +0 -0
  482. /package/dist/cli-bundle/chunks/{history-repair-RQXKQHL4.js.map → history-repair-LUQWRS7X.js.map} +0 -0
  483. /package/dist/cli-bundle/chunks/{learnings-JLNLCOL5.js.map → learnings-2MRNBFJF.js.map} +0 -0
  484. /package/dist/cli-bundle/chunks/{learnings-RSNLSWDC.js.map → learnings-ZVHSALJY.js.map} +0 -0
  485. /package/dist/cli-bundle/chunks/{notes-GB47XXQQ.js.map → notes-73JWKWUD.js.map} +0 -0
  486. /package/dist/cli-bundle/chunks/{notes-2WDH6DXU.js.map → notes-BAKUL5DJ.js.map} +0 -0
  487. /package/dist/cli-bundle/chunks/{plan-VDCJ2PCN.js.map → plan-AZPMCG37.js.map} +0 -0
  488. /package/dist/cli-bundle/chunks/{plan-DOVI2VMW.js.map → plan-LEAGLPGP.js.map} +0 -0
  489. /package/dist/cli-bundle/chunks/{profile-IVXQEL3D.js.map → profile-AGUKS52S.js.map} +0 -0
  490. /package/dist/cli-bundle/chunks/{profile-FAU7NZML.js.map → profile-U2B6Y7GE.js.map} +0 -0
  491. /package/dist/cli-bundle/chunks/{register-list-query-UL4UKBBN.js.map → register-list-query-A5KRJ5J2.js.map} +0 -0
  492. /package/dist/cli-bundle/chunks/{register-list-query-DKA3EH5D.js.map → register-list-query-NEYP3TXO.js.map} +0 -0
  493. /package/dist/cli-bundle/chunks/{register-mutation-RBBJ52DK.js.map → register-mutation-6LOPBAHC.js.map} +0 -0
  494. /package/dist/cli-bundle/chunks/{register-mutation-ARFHRW55.js.map → register-mutation-GCZOALNJ.js.map} +0 -0
  495. /package/dist/cli-bundle/chunks/{register-operations-ZIBBRSED.js.map → register-operations-6ZZIF27A.js.map} +0 -0
  496. /package/dist/cli-bundle/chunks/{register-operations-ZUJ5JWPE.js.map → register-operations-REDIAEGI.js.map} +0 -0
  497. /package/dist/cli-bundle/chunks/{register-setup-TDCGWIOS.js.map → register-setup-BHPMN5SK.js.map} +0 -0
  498. /package/dist/cli-bundle/chunks/{register-setup-BCVLFEYS.js.map → register-setup-J3JS2ZVT.js.map} +0 -0
  499. /package/dist/cli-bundle/chunks/{restore-25DLT2Q2.js.map → restore-E3PRGDN3.js.map} +0 -0
  500. /package/dist/cli-bundle/chunks/{restore-YPMVUUEX.js.map → restore-KIUYTAEJ.js.map} +0 -0
  501. /package/dist/cli-bundle/chunks/{schema-FNU3WE4O.js.map → schema-5JNFQFUW.js.map} +0 -0
  502. /package/dist/cli-bundle/chunks/{schema-NBCM3RAD.js.map → schema-TMIW4XZC.js.map} +0 -0
  503. /package/dist/cli-bundle/chunks/{update-WWBYOPXO.js.map → update-PQQHLYCC.js.map} +0 -0
  504. /package/dist/cli-bundle/chunks/{update-XHSIAIXE.js.map → update-SA6AG23P.js.map} +0 -0
  505. /package/dist/cli-bundle/chunks/{update-many-TA7NGQBO.js.map → update-many-RQVTFJPD.js.map} +0 -0
  506. /package/dist/cli-bundle/chunks/{update-many-OUGIU5SF.js.map → update-many-TV3L3KBX.js.map} +0 -0
  507. /package/dist/{cli/commands → sdk/query}/search-pagination.d.ts +0 -0
  508. /package/dist/{cli/commands → sdk/query}/search-rendering.d.ts +0 -0
@@ -1,1786 +1,10 @@
1
1
  /**
2
2
  * @module cli/commands/test
3
3
  *
4
- * Implements the pm test command surface and its agent-facing runtime behavior.
4
+ * Compatibility export for SDK-owned linked-test execution primitives.
5
5
  */
6
6
 
7
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="1f9bc440-299f-5f61-be67-cad0c40f56a7")}catch(e){}}();
8
- import { spawn } from "node:child_process";
9
- import { cp, mkdir, mkdtemp, readdir, rm } from "node:fs/promises";
10
- import { tmpdir } from "node:os";
11
- import path from "node:path";
12
- import { getActiveExtensionRegistrations } from "../../core/extensions/index.js";
13
- import { pathExists } from "../../core/fs/fs-utils.js";
14
- import { resolveItemTypeRegistry } from "../../core/item/type-registry.js";
15
- import { createStdinTokenResolver, parseCsvKv, parseOptionalNumber, } from "../../core/item/parse.js";
16
- import { EXIT_CODE } from "../../core/shared/constants.js";
17
- import { PmCliError } from "../../core/shared/errors.js";
18
- import { stableValueEquals } from "../../core/shared/serialization.js";
19
- import { nowIso } from "../../core/shared/time.js";
20
- import { locateItem, mutateItem, readLocatedItem, } from "../../core/store/item-store.js";
21
- import { getSettingsPath, ITEM_FILE_EXTENSIONS, resolveGlobalPmRoot, resolvePmRoot, } from "../../core/store/paths.js";
22
- import { readSettings } from "../../core/store/settings.js";
23
- import { appendTrackedTestRunSummary } from "../../core/test/item-test-run-tracking.js";
24
- import { runInit } from "./init.js";
25
- import { looksLikeStructuredLinkedTestEntry, normalizeStructuredLinkedTestEntry, } from "./linked-test-entry.js";
26
- import { LINKED_TEST_PM_CONTEXT_MODE_VALUES as PM_CONTEXT_MODE_VALUES, LINKED_TEST_PROTECTED_ENV_KEYS, parseLinkedTestAssertionEqualsMap, parseLinkedTestAssertionGteMap, parseLinkedTestBoolean as parseLinkedTestBooleanValue, parseLinkedTestContextMode as parseLinkedTestContextModeValue, parseLinkedTestEnvClear as parseLinkedTestEnvClearValue, parseLinkedTestEnvSet as parseLinkedTestEnvSetValue, parseLinkedTestJsonEntries, parseLinkedTestMinLines, parseLinkedTestRegexList, parseLinkedTestStringList, } from "./linked-test-parsers.js";
27
- import { parseOnlyIndexValue, resolveLinkedTestRunSelection, } from "../../core/test/run-selectors.js";
28
- import { SCOPE_VALUES } from "../../types/index.js";
29
- const TEST_OUTPUT_MAX_BUFFER_BYTES = 20 * 1024 * 1024;
30
- const DEFAULT_LINKED_TEST_TIMEOUT_FORCE_KILL_DELAY_MS = 3000;
31
- const DEFAULT_LINKED_TEST_HEARTBEAT_INTERVAL_MS = 10000;
32
- const DEFAULT_LINKED_TEST_PIPE_CLOSE_GRACE_MS = 5000;
33
- const MAX_LINKED_TEST_COMMAND_LABEL_LENGTH = 120;
34
- const LINKED_TEST_TRACKER_DIRS_TO_SKIP = new Set([
35
- "locks",
36
- "extensions",
37
- "runtime",
38
- ]);
39
- const LINKED_TEST_ITEM_COUNT_DIRS_TO_SKIP = new Set([
40
- "history",
41
- "index",
42
- "search",
43
- "extensions",
44
- "locks",
45
- "runtime",
46
- ]);
47
- const LINKED_TEST_INFRA_COLLISION_PATTERNS = [
48
- /eaddrinuse/i,
49
- /address already in use/i,
50
- /port\s+\d+\s+is already in use/i,
51
- /web server[^.\n]*already running/i,
52
- /failed to listen on/i,
53
- ];
54
- const PM_TRACKER_READ_SUBCOMMANDS = new Set([
55
- "activity",
56
- "calendar",
57
- "context",
58
- "ctx",
59
- "deps",
60
- "get",
61
- "health",
62
- "history",
63
- "list",
64
- "list-all",
65
- "list-blocked",
66
- "list-canceled",
67
- "list-closed",
68
- "list-draft",
69
- "list-in-progress",
70
- "list-open",
71
- "search",
72
- "stats",
73
- "test-all",
74
- "validate",
75
- ]);
76
- function readPositiveIntegerEnv(name, fallback) {
77
- const raw = process.env[name];
78
- if (typeof raw !== "string" || raw.trim().length === 0) {
79
- return fallback;
80
- }
81
- const parsed = Number.parseInt(raw, 10);
82
- if (!Number.isFinite(parsed) || parsed <= 0) {
83
- return fallback;
84
- }
85
- return parsed;
86
- }
87
- function linkedTestTimeoutForceKillDelayMs() {
88
- return readPositiveIntegerEnv("PM_LINKED_TEST_TIMEOUT_FORCE_KILL_DELAY_MS", DEFAULT_LINKED_TEST_TIMEOUT_FORCE_KILL_DELAY_MS);
89
- }
90
- function linkedTestHeartbeatIntervalMs() {
91
- return readPositiveIntegerEnv("PM_LINKED_TEST_HEARTBEAT_INTERVAL_MS", DEFAULT_LINKED_TEST_HEARTBEAT_INTERVAL_MS);
92
- }
93
- function linkedTestPipeCloseGraceMs() {
94
- return readPositiveIntegerEnv("PM_LINKED_TEST_PIPE_CLOSE_GRACE_MS", DEFAULT_LINKED_TEST_PIPE_CLOSE_GRACE_MS);
95
- }
96
- function resolveAuthor(candidate, fallback) {
97
- const resolved = candidate ?? process.env.PM_AUTHOR ?? fallback;
98
- const trimmed = resolved.trim();
99
- return trimmed || "unknown";
100
- }
101
- function resolveTrackedRunId(kind) {
102
- const fromEnv = process.env.PM_BACKGROUND_TEST_RUN_ID?.trim();
103
- if (fromEnv && fromEnv.length > 0) {
104
- return fromEnv;
105
- }
106
- return `${kind}-local-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
107
- }
108
- function summarizeRunResultStatuses(results) {
109
- let passed = 0;
110
- let failed = 0;
111
- let skipped = 0;
112
- for (const entry of results) {
113
- if (entry.status === "passed") {
114
- passed += 1;
115
- continue;
116
- }
117
- if (entry.status === "failed") {
118
- failed += 1;
119
- continue;
120
- }
121
- skipped += 1;
122
- }
123
- return { passed, failed, skipped };
124
- }
125
- /** Implements summarize context preflight for the public runtime surface of this module. */
126
- export function summarizeContextPreflight(runResults) {
127
- let checkedPmCommands = 0;
128
- let trackerReadCommands = 0;
129
- let mismatches = 0;
130
- let autoRemediated = 0;
131
- for (const result of runResults) {
132
- const context = result.execution_context;
133
- if (!context || context.is_pm_command !== true) {
134
- continue;
135
- }
136
- checkedPmCommands += 1;
137
- if (context.is_pm_tracker_read_command === true) {
138
- trackerReadCommands += 1;
139
- }
140
- if (context.mismatch_detected === true) {
141
- mismatches += 1;
142
- }
143
- if (context.auto_pm_context_applied === true) {
144
- autoRemediated += 1;
145
- }
146
- }
147
- return {
148
- checked_pm_commands: checkedPmCommands,
149
- tracker_read_commands: trackerReadCommands,
150
- mismatches,
151
- auto_remediated: autoRemediated,
152
- };
153
- }
154
- function ensureScope(raw) {
155
- const value = (raw ?? "project");
156
- if (!SCOPE_VALUES.includes(value)) {
157
- throw new PmCliError(`Invalid scope "${raw}"`, EXIT_CODE.USAGE);
158
- }
159
- return value;
160
- }
161
- function parsePmContextMode(raw) {
162
- if (!raw) {
163
- return "schema";
164
- }
165
- const normalized = raw.trim().toLowerCase();
166
- if (PM_CONTEXT_MODE_VALUES.includes(normalized)) {
167
- return normalized;
168
- }
169
- throw new PmCliError(`Invalid --pm-context value "${raw}". Expected one of: ${PM_CONTEXT_MODE_VALUES.join(", ")}`, EXIT_CODE.USAGE);
170
- }
171
- function resolveLinkedTestRequestedContextMode(linkedTest, runLevelMode, overrideLinkedPmContext) {
172
- if (overrideLinkedPmContext) {
173
- return runLevelMode;
174
- }
175
- if (typeof linkedTest.pm_context_mode !== "string" ||
176
- linkedTest.pm_context_mode.trim().length === 0) {
177
- return runLevelMode;
178
- }
179
- return parsePmContextMode(linkedTest.pm_context_mode);
180
- }
181
- function resolveLinkedTestEffectiveContextMode(requestedMode, isPmTrackerReadCommand) {
182
- if (requestedMode === "auto") {
183
- return isPmTrackerReadCommand ? "tracker" : "schema";
184
- }
185
- return requestedMode;
186
- }
187
- /* c8 ignore start -- assertion-shape truthiness combinations are covered by linked-test integration suites */
188
- function hasLinkedTestAssertions(linkedTest) {
189
- return ((linkedTest.assert_stdout_contains?.length ?? 0) > 0 ||
190
- (linkedTest.assert_stdout_regex?.length ?? 0) > 0 ||
191
- (linkedTest.assert_stderr_contains?.length ?? 0) > 0 ||
192
- (linkedTest.assert_stderr_regex?.length ?? 0) > 0 ||
193
- typeof linkedTest.assert_stdout_min_lines === "number" ||
194
- Object.keys(linkedTest.assert_json_field_equals ?? {}).length > 0 ||
195
- Object.keys(linkedTest.assert_json_field_gte ?? {}).length > 0);
196
- }
197
- /* c8 ignore stop */
198
- /* c8 ignore start -- pm-context mismatch hint combinations are validated by tracker/schema integration runs */
199
- function buildPmContextMismatchHint(params) {
200
- const { executionContext, runLevelPmContextMode, linkedOverridePmContextMode, } = params;
201
- if (!executionContext.is_pm_tracker_read_command ||
202
- !executionContext.mismatch_detected) {
203
- return "";
204
- }
205
- if (runLevelPmContextMode === "tracker" &&
206
- linkedOverridePmContextMode === "schema") {
207
- return (" Linked test metadata pm_context_mode=schema overrides run-level --pm-context tracker." +
208
- " Set pm_context_mode=tracker (or auto) on the linked test, or remove the override, to run against seeded tracker data.");
209
- }
210
- if (executionContext.pm_context_mode === "schema") {
211
- return (" Use --auto-pm-context to route PM tracker-read linked commands through seeded tracker data automatically." +
212
- " Alternatively, use --pm-context tracker for the whole run.");
213
- }
214
- return "";
215
- }
216
- /* c8 ignore stop */
217
- function mergeEnvSetDirectives(entries, optionName) {
218
- const merged = {};
219
- if (!entries) {
220
- return merged;
221
- }
222
- for (const entry of entries) {
223
- const parsed = parseLinkedTestEnvSetValue(entry, optionName);
224
- if (!parsed) {
225
- continue;
226
- }
227
- for (const [key, value] of Object.entries(parsed)) {
228
- merged[key] = value;
229
- }
230
- }
231
- return merged;
232
- }
233
- function mergeEnvClearDirectives(entries, optionName) {
234
- if (!entries) {
235
- return [];
236
- }
237
- const values = [];
238
- for (const entry of entries) {
239
- const parsed = parseLinkedTestEnvClearValue(entry, optionName);
240
- if (parsed) {
241
- values.push(...parsed);
242
- }
243
- }
244
- return [...new Set(values)];
245
- }
246
- // Linked-test command detection helpers + constants live in a sibling leaf
247
- // module to keep this command file under the per-file LOC budget. Re-exported
248
- // here so no consumer outside this file changes.
249
- import { BUN_GLOBAL_FLAGS_WITH_VALUE, NPM_GLOBAL_FLAGS_WITH_VALUE, PNPM_GLOBAL_FLAGS_WITH_VALUE, SCRIPT_RUN_FLAGS_WITH_VALUE, SCRIPT_RUN_SUBCOMMANDS, YARN_GLOBAL_FLAGS_WITH_VALUE, firstPmSubcommand, extractPmInvocationArgsFromSegment, isPmCliPackageToken, isPmCliScriptToken, isPmExecutableToken, parseLauncherSubcommand, parseNpmExecCommand, parseNpxCommand, parsePnpmDlxCommand, resolvePmSubcommandContext, splitNormalizedCommandSegments, stripLeadingEnvAssignments, } from "../../sdk/test/linked-command-detection.js";
250
- export { extractReferencedPmItemIdsFromCommand } from "../../sdk/test/linked-command-detection.js";
251
- function commandInvokesPmCli(command) {
252
- const normalizedCommand = normalizeCommandForValidation(command);
253
- return splitNormalizedCommandSegments(normalizedCommand).some((segment) => extractPmInvocationArgsFromSegment(segment) !== null);
254
- }
255
- function commandInvokesPmTrackerReadCommand(command) {
256
- const normalizedCommand = normalizeCommandForValidation(command);
257
- return splitNormalizedCommandSegments(normalizedCommand).some((segment) => {
258
- const invocationArgs = extractPmInvocationArgsFromSegment(segment);
259
- if (!invocationArgs) {
260
- return false;
261
- }
262
- const context = resolvePmSubcommandContext(invocationArgs);
263
- if (!context) {
264
- return false;
265
- }
266
- return PM_TRACKER_READ_SUBCOMMANDS.has(context.subcommand);
267
- });
268
- }
269
- function resolveDirectRunnerSubcommand(parsed) {
270
- if (!parsed) {
271
- return undefined;
272
- }
273
- if (!SCRIPT_RUN_SUBCOMMANDS.has(parsed.subcommand)) {
274
- return parsed.subcommand;
275
- }
276
- return parseLauncherSubcommand(parsed.args, SCRIPT_RUN_FLAGS_WITH_VALUE)
277
- ?.subcommand;
278
- }
279
- function firstDirectTestRunnerSubcommand(executable, args) {
280
- if (executable === "npx" || executable === "bunx") {
281
- return parseNpxCommand(args)?.command;
282
- }
283
- if (executable === "pnpm") {
284
- return resolveDirectRunnerSubcommand(parseLauncherSubcommand(args, PNPM_GLOBAL_FLAGS_WITH_VALUE));
285
- }
286
- if (executable === "npm") {
287
- return resolveDirectRunnerSubcommand(parseLauncherSubcommand(args, NPM_GLOBAL_FLAGS_WITH_VALUE));
288
- }
289
- if (executable === "yarn") {
290
- return resolveDirectRunnerSubcommand(parseLauncherSubcommand(args, YARN_GLOBAL_FLAGS_WITH_VALUE));
291
- }
292
- if (executable === "bun") {
293
- return resolveDirectRunnerSubcommand(parseLauncherSubcommand(args, BUN_GLOBAL_FLAGS_WITH_VALUE));
294
- }
295
- return undefined;
296
- }
297
- function isDirectTestRunnerSubcommand(token) {
298
- if (!token) {
299
- return false;
300
- }
301
- return token === "vitest" || token === "test" || token.startsWith("test:");
302
- }
303
- function parsedLauncherInvokesRecursiveTestAll(parsed) {
304
- if (!parsed) {
305
- return false;
306
- }
307
- if (!isPmExecutableToken(parsed.command) &&
308
- !isPmCliPackageToken(parsed.command)) {
309
- return false;
310
- }
311
- return firstPmSubcommand(parsed.args) === "test-all";
312
- }
313
- function segmentInvokesRecursiveTestAll(segment) {
314
- const rawTokens = segment.split(" ").filter((token) => token.length > 0);
315
- const tokens = stripLeadingEnvAssignments(rawTokens);
316
- if (tokens.length === 0) {
317
- return false;
318
- }
319
- const [executable, ...args] = tokens;
320
- if (isPmExecutableToken(executable) || isPmCliScriptToken(executable)) {
321
- return firstPmSubcommand(args) === "test-all";
322
- }
323
- if (executable === "node" && args.length > 0 && isPmCliScriptToken(args[0])) {
324
- return firstPmSubcommand(args.slice(1)) === "test-all";
325
- }
326
- if (executable === "npx" || executable === "bunx") {
327
- return parsedLauncherInvokesRecursiveTestAll(parseNpxCommand(args));
328
- }
329
- if (executable === "pnpm") {
330
- return parsedLauncherInvokesRecursiveTestAll(parsePnpmDlxCommand(args));
331
- }
332
- if (executable === "npm") {
333
- return parsedLauncherInvokesRecursiveTestAll(parseNpmExecCommand(args));
334
- }
335
- return false;
336
- }
337
- function invokesRecursiveTestAllCommand(command) {
338
- const normalized = normalizeCommandForValidation(command);
339
- return splitNormalizedCommandSegments(normalized).some((segment) => segmentInvokesRecursiveTestAll(segment));
340
- }
341
- function assertNoRecursiveTestAllCommand(command) {
342
- if (!invokesRecursiveTestAllCommand(command))
343
- return;
344
- throw new PmCliError('Linked test commands must not invoke "pm test-all"; this creates recursive orchestration.', EXIT_CODE.USAGE);
345
- }
346
- function normalizeCommandForValidation(command) {
347
- return command
348
- .trim()
349
- .replaceAll("\\", "/")
350
- .replaceAll('"', "")
351
- .replaceAll("'", "")
352
- .replaceAll(/\s+/g, " ")
353
- .toLowerCase();
354
- }
355
- function commandUsesSandboxRunner(normalizedCommand) {
356
- return (normalizedCommand.includes("node scripts/run-tests.mjs ") ||
357
- normalizedCommand.endsWith("node scripts/run-tests.mjs") ||
358
- normalizedCommand.includes("node ./scripts/run-tests.mjs ") ||
359
- normalizedCommand.endsWith("node ./scripts/run-tests.mjs"));
360
- }
361
- function segmentHasExplicitSandboxEnv(normalizedSegment) {
362
- const hasExplicitPmPath = /\bpm_path\s*=/.test(normalizedSegment) ||
363
- /\$env:pm_path\s*=/.test(normalizedSegment);
364
- const hasExplicitPmGlobalPath = /\bpm_global_path\s*=/.test(normalizedSegment) ||
365
- /\$env:pm_global_path\s*=/.test(normalizedSegment);
366
- return hasExplicitPmPath && hasExplicitPmGlobalPath;
367
- }
368
- function segmentInvokesUnsafeDirectTestRunner(normalizedSegment) {
369
- const rawTokens = normalizedSegment
370
- .split(" ")
371
- .filter((token) => token.length > 0);
372
- const tokens = stripLeadingEnvAssignments(rawTokens);
373
- if (tokens.length === 0) {
374
- return false;
375
- }
376
- const [executable, ...args] = tokens;
377
- if (executable === "vitest" ||
378
- executable.endsWith("/vitest") ||
379
- executable.endsWith("/vitest.mjs")) {
380
- return true;
381
- }
382
- if (executable === "node") {
383
- return nodeArgsInvokeUnsafeDirectTestRunner(args);
384
- }
385
- return packageManagerInvokesUnsafeDirectTestRunner(executable, args);
386
- }
387
- function nodeArgsInvokeUnsafeDirectTestRunner(args) {
388
- return (args.includes("--test") ||
389
- args.some((arg) => arg === "vitest" ||
390
- arg === "vitest.mjs" ||
391
- arg.endsWith("/vitest") ||
392
- arg.endsWith("/vitest.mjs")));
393
- }
394
- function packageManagerInvokesUnsafeDirectTestRunner(executable, args) {
395
- if (executable === "npx" || executable === "bunx") {
396
- return isDirectTestRunnerSubcommand(parseNpxCommand(args)?.command);
397
- }
398
- if (executable === "pnpm" || executable === "npm") {
399
- return (isDirectTestRunnerSubcommand((executable === "pnpm"
400
- ? parsePnpmDlxCommand(args)
401
- : parseNpmExecCommand(args))?.command) || firstDirectTestRunnerSubcommand(executable, args) === "vitest");
402
- }
403
- return ((executable === "yarn" || executable === "bun") &&
404
- firstDirectTestRunnerSubcommand(executable, args) === "vitest");
405
- }
406
- function assertSandboxSafeTestRunnerCommand(command) {
407
- const normalized = normalizeCommandForValidation(command);
408
- const segments = splitNormalizedCommandSegments(normalized);
409
- const hasUnsafeDirectRunnerSegment = segments.some((segment) => !commandUsesSandboxRunner(segment) &&
410
- segmentInvokesUnsafeDirectTestRunner(segment) &&
411
- !segmentHasExplicitSandboxEnv(segment));
412
- if (!hasUnsafeDirectRunnerSegment) {
413
- return;
414
- }
415
- throw new PmCliError('Linked test runner commands must be sandbox-safe: use "node scripts/run-tests.mjs <test|coverage>", use a package-manager script such as "pnpm test", or include PM_PATH=... PM_GLOBAL_PATH=... INLINE in the command string (exporting them in your shell environment is not checked). Example: "PM_PATH=/tmp/pm-x PM_GLOBAL_PATH=/tmp/pm-x-g vitest run".', EXIT_CODE.USAGE);
416
- }
417
- function getRuntimeSafetySkipReason(command) {
418
- if (!invokesRecursiveTestAllCommand(command))
419
- return undefined;
420
- return 'Linked test command skipped: Linked test commands must not invoke "pm test-all"; this creates recursive orchestration.';
421
- }
422
- function parseAddEntries(raw) {
423
- if (!raw)
424
- return [];
425
- return raw.map(parseAddEntry);
426
- }
427
- function parseAddEntry(entry) {
428
- const trimmed = entry.trim();
429
- const kv = looksLikeStructuredLinkedTestEntry(trimmed)
430
- ? normalizeStructuredLinkedTestEntry(parseCsvKv(entry, "--add"), "--add")
431
- : { command: trimmed };
432
- const command = trimLinkedTestEntryField(kv.command);
433
- if (!command) {
434
- throw new PmCliError("--add requires command=<value> or a bare command (path=<value> is optional metadata)", EXIT_CODE.USAGE);
435
- }
436
- assertNoRecursiveTestAllCommand(command);
437
- assertSandboxSafeTestRunnerCommand(command);
438
- return {
439
- command,
440
- path: trimLinkedTestEntryField(kv.path),
441
- scope: ensureScope(kv.scope),
442
- timeout_seconds: parseLinkedTestTimeoutSeconds(trimLinkedTestEntryField(kv.timeout_seconds), trimLinkedTestEntryField(kv.timeout)),
443
- pm_context_mode: parseLinkedTestContextModeValue(trimLinkedTestEntryField(kv.pm_context_mode), "--add"),
444
- env_set: parseLinkedTestEnvSetValue(trimLinkedTestEntryField(kv.env_set), "--add"),
445
- env_clear: parseLinkedTestEnvClearValue(trimLinkedTestEntryField(kv.env_clear), "--add"),
446
- shared_host_safe: parseLinkedTestBooleanValue(trimLinkedTestEntryField(kv.shared_host_safe), "--add", "shared_host_safe"),
447
- assert_stdout_contains: parseLinkedTestStringList(trimLinkedTestEntryField(kv.assert_stdout_contains)),
448
- assert_stdout_regex: parseLinkedTestRegexList(trimLinkedTestEntryField(kv.assert_stdout_regex), "--add", "assert_stdout_regex"),
449
- assert_stderr_contains: parseLinkedTestStringList(trimLinkedTestEntryField(kv.assert_stderr_contains)),
450
- assert_stderr_regex: parseLinkedTestRegexList(trimLinkedTestEntryField(kv.assert_stderr_regex), "--add", "assert_stderr_regex"),
451
- assert_stdout_min_lines: parseLinkedTestMinLines(trimLinkedTestEntryField(kv.assert_stdout_min_lines), "--add"),
452
- assert_json_field_equals: parseLinkedTestAssertionEqualsMap(trimLinkedTestEntryField(kv.assert_json_field_equals), "--add"),
453
- assert_json_field_gte: parseLinkedTestAssertionGteMap(trimLinkedTestEntryField(kv.assert_json_field_gte), "--add"),
454
- note: trimLinkedTestEntryField(kv.note),
455
- };
456
- }
457
- function trimLinkedTestEntryField(value) {
458
- const trimmed = value?.trim();
459
- return trimmed && trimmed.length > 0 ? trimmed : undefined;
460
- }
461
- function parseLinkedTestTimeoutSeconds(timeoutSecondsRaw, timeoutAliasRaw) {
462
- if (timeoutSecondsRaw &&
463
- timeoutAliasRaw &&
464
- timeoutSecondsRaw !== timeoutAliasRaw) {
465
- throw new PmCliError("--add timeout and timeout_seconds must match when both are provided", EXIT_CODE.USAGE);
466
- }
467
- const timeoutRaw = timeoutSecondsRaw ?? timeoutAliasRaw;
468
- return timeoutRaw === undefined
469
- ? undefined
470
- : Math.floor(parseOptionalNumber(timeoutRaw, "timeout_seconds"));
471
- }
472
- /* c8 ignore start -- add-json validation matrix is covered by linked-test parser integration suites */
473
- function parseAddJsonEntries(raw) {
474
- if (!raw)
475
- return [];
476
- return raw.flatMap((entry) => {
477
- const parsed = parseLinkedTestJsonEntries(entry, "--add-json");
478
- for (const linkedTest of parsed) {
479
- const command = linkedTest.command;
480
- if (!command) {
481
- throw new PmCliError("--add-json requires a non-empty command string", EXIT_CODE.USAGE);
482
- }
483
- assertNoRecursiveTestAllCommand(command);
484
- assertSandboxSafeTestRunnerCommand(command);
485
- }
486
- return parsed;
487
- });
488
- }
489
- /* c8 ignore stop */
490
- function parseRemoveEntries(raw) {
491
- if (!raw)
492
- return [];
493
- return raw.map((entry) => {
494
- const trimmed = entry.trim();
495
- if (!trimmed) {
496
- throw new PmCliError("--remove requires command or path value", EXIT_CODE.USAGE);
497
- }
498
- if (trimmed.includes("=") ||
499
- /^(?:[-*+]\s+)?(?:path|command)\s*[:=]/i.test(trimmed) ||
500
- trimmed.startsWith("```")) {
501
- const kv = parseCsvKv(trimmed, "--remove");
502
- const value = kv.path ?? kv.command;
503
- if (!value?.trim()) {
504
- throw new PmCliError("--remove requires command=<value> and/or path=<value>", EXIT_CODE.USAGE);
505
- }
506
- return value.trim();
507
- }
508
- return trimmed;
509
- });
510
- }
511
- function closeLinkedTestStdin(child) {
512
- // Force EOF on child stdin so non-interactive runs do not wait on input.
513
- try {
514
- child.stdin?.end();
515
- }
516
- catch {
517
- // Child stdin can already be closed depending on command startup timing.
518
- }
519
- }
520
- function summarizeLinkedTestCommand(command) {
521
- const normalized = command.trim().replaceAll(/\s+/g, " ");
522
- if (normalized.length <= MAX_LINKED_TEST_COMMAND_LABEL_LENGTH) {
523
- return normalized;
524
- }
525
- return `${normalized.slice(0, MAX_LINKED_TEST_COMMAND_LABEL_LENGTH - 3)}...`;
526
- }
527
- function shouldEmitLinkedTestProgress(mode) {
528
- /* c8 ignore start -- reserved for future explicit "off" mode wiring. */
529
- if (mode === "off") {
530
- return false;
531
- }
532
- /* c8 ignore stop */
533
- if (mode === "always") {
534
- return true;
535
- }
536
- return process.stderr.isTTY === true;
537
- }
538
- function emitLinkedTestProgress(message) {
539
- try {
540
- process.stderr.write(`${message}\n`);
541
- }
542
- catch {
543
- // Ignore transient stderr write failures.
544
- }
545
- }
546
- function beginLinkedTestProgress(context, mode) {
547
- if (!shouldEmitLinkedTestProgress(mode)) {
548
- return null;
549
- }
550
- const commandLabel = summarizeLinkedTestCommand(context.command);
551
- const startAt = Date.now();
552
- emitLinkedTestProgress(`[pm test] linked-test ${context.index}/${context.total} start timeout_ms=${context.timeoutMs} command="${commandLabel}"`);
553
- const heartbeat = setInterval(() => {
554
- const elapsedMs = Date.now() - startAt;
555
- emitLinkedTestProgress(`[pm test] linked-test ${context.index}/${context.total} running elapsed_ms=${elapsedMs} command="${commandLabel}"`);
556
- }, linkedTestHeartbeatIntervalMs());
557
- heartbeat.unref?.();
558
- return heartbeat;
559
- }
560
- function endLinkedTestProgress(context, executionResult, startedAt, mode) {
561
- if (!shouldEmitLinkedTestProgress(mode)) {
562
- return;
563
- }
564
- const commandLabel = summarizeLinkedTestCommand(context.command);
565
- const elapsedMs = Date.now() - startedAt;
566
- const failed = executionResult.timedOut ||
567
- executionResult.maxBufferExceeded ||
568
- executionResult.exitCode !== 0;
569
- const statusLabel = failed ? "failed" : "passed";
570
- const reasonTokens = [];
571
- if (executionResult.timedOut) {
572
- reasonTokens.push("reason=timeout");
573
- }
574
- if (executionResult.maxBufferExceeded) {
575
- reasonTokens.push("reason=max_buffer");
576
- }
577
- if (executionResult.signal) {
578
- reasonTokens.push(`signal=${executionResult.signal}`);
579
- }
580
- const exitLabel = executionResult.exitCode === null
581
- ? "null"
582
- : String(executionResult.exitCode);
583
- const reasonSuffix = reasonTokens.length > 0 ? ` ${reasonTokens.join(" ")}` : "";
584
- emitLinkedTestProgress(`[pm test] linked-test ${context.index}/${context.total} end status=${statusLabel} exit_code=${exitLabel} elapsed_ms=${elapsedMs}${reasonSuffix} command="${commandLabel}"`);
585
- }
586
- /* c8 ignore start -- process-tree teardown paths are highly platform-dependent. */
587
- async function killProcessTree(pid) {
588
- if (!Number.isInteger(pid) || pid <= 0) {
589
- return;
590
- }
591
- if (process.platform === "win32") {
592
- await new Promise((resolve) => {
593
- const killer = spawn("taskkill", ["/pid", String(pid), "/T", "/F"], {
594
- stdio: "ignore",
595
- windowsHide: true,
596
- });
597
- killer.on("error", () => resolve());
598
- killer.on("close", () => resolve());
599
- });
600
- return;
601
- }
602
- try {
603
- process.kill(-pid, "SIGKILL");
604
- return;
605
- }
606
- catch {
607
- // Fall back to direct child kill when no process group is available.
608
- }
609
- try {
610
- process.kill(pid, "SIGKILL");
611
- }
612
- catch {
613
- // The process can already be gone.
614
- }
615
- }
616
- function clearLinkedTestTimers(timers) {
617
- if (timers.heartbeat) {
618
- clearInterval(timers.heartbeat);
619
- }
620
- if (timers.timedOutTimer) {
621
- clearTimeout(timers.timedOutTimer);
622
- timers.timedOutTimer = null;
623
- }
624
- if (timers.forceKillTimer) {
625
- clearTimeout(timers.forceKillTimer);
626
- timers.forceKillTimer = null;
627
- }
628
- }
629
- function createLinkedTestTerminationRequester(child, timers) {
630
- let terminationRequested = false;
631
- return async () => {
632
- if (terminationRequested) {
633
- return;
634
- }
635
- terminationRequested = true;
636
- const pid = child.pid;
637
- if (!pid || pid <= 0) {
638
- try {
639
- child.kill("SIGTERM");
640
- }
641
- catch {
642
- // Child can already be closed.
643
- }
644
- return;
645
- }
646
- if (process.platform === "win32") {
647
- await killProcessTree(pid);
648
- return;
649
- }
650
- try {
651
- process.kill(-pid, "SIGTERM");
652
- }
653
- catch {
654
- /* c8 ignore next 4 -- platform-specific process-group fallback path. */
655
- try {
656
- child.kill("SIGTERM");
657
- }
658
- catch {
659
- // Child can already be closed.
660
- }
661
- }
662
- /* c8 ignore next 3 -- exercised only when timeout escalation triggers force-kill fallback. */
663
- timers.forceKillTimer = setTimeout(() => {
664
- void killProcessTree(pid);
665
- }, linkedTestTimeoutForceKillDelayMs());
666
- timers.forceKillTimer.unref?.();
667
- };
668
- }
669
- function readLinkedTestOutputChunkText(chunk, bytes, remainingBytes) {
670
- if (remainingBytes <= 0) {
671
- return "";
672
- }
673
- if (bytes <= remainingBytes) {
674
- return typeof chunk === "string" ? chunk : chunk.toString("utf8");
675
- }
676
- const buffer = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
677
- return buffer.subarray(0, remainingBytes).toString("utf8");
678
- }
679
- function appendLinkedTestOutputChunk(state, chunk, target) {
680
- if (state.maxBufferExceeded) {
681
- return false;
682
- }
683
- const bytes = typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.byteLength;
684
- if (target === "stdout") {
685
- const remainingBytes = TEST_OUTPUT_MAX_BUFFER_BYTES - state.stdoutBytes;
686
- state.stdout += readLinkedTestOutputChunkText(chunk, bytes, remainingBytes);
687
- state.stdoutBytes += bytes;
688
- }
689
- else {
690
- const remainingBytes = TEST_OUTPUT_MAX_BUFFER_BYTES - state.stderrBytes;
691
- state.stderr += readLinkedTestOutputChunkText(chunk, bytes, remainingBytes);
692
- state.stderrBytes += bytes;
693
- }
694
- const bufferExceeded = state.stdoutBytes > TEST_OUTPUT_MAX_BUFFER_BYTES ||
695
- state.stderrBytes > TEST_OUTPUT_MAX_BUFFER_BYTES;
696
- if (!state.maxBufferExceeded && bufferExceeded) {
697
- state.maxBufferExceeded = true;
698
- return true;
699
- }
700
- return false;
701
- }
702
- function waitForLinkedTestChildClose(child) {
703
- return new Promise((resolve) => {
704
- let settled = false;
705
- let pipeCloseGraceTimer = null;
706
- const settle = (value, destroyPipes = false) => {
707
- if (settled) {
708
- return;
709
- }
710
- settled = true;
711
- if (pipeCloseGraceTimer) {
712
- clearTimeout(pipeCloseGraceTimer);
713
- pipeCloseGraceTimer = null;
714
- }
715
- if (destroyPipes) {
716
- child.stdin?.destroy();
717
- child.stdout?.destroy();
718
- child.stderr?.destroy();
719
- }
720
- resolve(value);
721
- };
722
- child.on("exit", (exitCode, exitSignal) => {
723
- if (settled) {
724
- return;
725
- }
726
- pipeCloseGraceTimer = setTimeout(() => {
727
- settle({
728
- code: exitCode,
729
- signal: exitSignal,
730
- }, true);
731
- }, linkedTestPipeCloseGraceMs());
732
- pipeCloseGraceTimer.unref?.();
733
- });
734
- child.on("close", (closeCode, closeSignal) => {
735
- settle({
736
- code: closeCode,
737
- signal: closeSignal,
738
- });
739
- });
740
- });
741
- }
742
- function createLinkedTestChild(command, env) {
743
- return spawn(command, {
744
- cwd: process.cwd(),
745
- env,
746
- shell: true,
747
- windowsHide: true,
748
- detached: process.platform !== "win32",
749
- stdio: ["pipe", "pipe", "pipe"],
750
- });
751
- }
752
- async function runLinkedTestCommand(command, timeoutMs, env, progressContext, progressMode) {
753
- const startedAt = Date.now();
754
- const child = createLinkedTestChild(command, env);
755
- closeLinkedTestStdin(child);
756
- const timers = {
757
- heartbeat: beginLinkedTestProgress(progressContext, progressMode),
758
- forceKillTimer: null,
759
- timedOutTimer: null,
760
- };
761
- const output = {
762
- stdout: "",
763
- stderr: "",
764
- stdoutBytes: 0,
765
- stderrBytes: 0,
766
- maxBufferExceeded: false,
767
- };
768
- const requestTermination = createLinkedTestTerminationRequester(child, timers);
769
- let timedOut = false;
770
- let spawnError;
771
- const appendChunk = (chunk, target) => {
772
- if (appendLinkedTestOutputChunk(output, chunk, target)) {
773
- void requestTermination();
774
- }
775
- };
776
- child.stdout?.on("data", (chunk) => appendChunk(chunk, "stdout"));
777
- child.stderr?.on("data", (chunk) => appendChunk(chunk, "stderr"));
778
- /* c8 ignore next 5 -- shell spawn error callbacks are non-deterministic across platforms. */
779
- child.on("error", (error) => {
780
- spawnError = error.message;
781
- });
782
- /* c8 ignore next 4 -- callback scheduling timing is non-deterministic under coverage instrumentation. */
783
- timers.timedOutTimer = setTimeout(() => {
784
- timedOut = true;
785
- void requestTermination();
786
- }, timeoutMs);
787
- timers.timedOutTimer.unref?.();
788
- const { code, signal } = await waitForLinkedTestChildClose(child);
789
- clearLinkedTestTimers(timers);
790
- const executionResult = {
791
- stdout: output.stdout,
792
- stderr: output.stderr,
793
- exitCode: code,
794
- signal,
795
- timedOut,
796
- maxBufferExceeded: output.maxBufferExceeded,
797
- spawnError,
798
- };
799
- endLinkedTestProgress(progressContext, executionResult, startedAt, progressMode);
800
- return executionResult;
801
- }
802
- /* c8 ignore stop */
803
- function formatLinkedTestExecutionError(result, timeoutMs) {
804
- const details = [];
805
- if (result.maxBufferExceeded) {
806
- details.push(`Linked test output exceeded maxBuffer=${TEST_OUTPUT_MAX_BUFFER_BYTES} bytes. Reduce output volume or split the command.`);
807
- }
808
- if (result.timedOut && timeoutMs > 0) {
809
- details.push(`Linked test timed out after ${timeoutMs}ms.`);
810
- }
811
- const signalMessage = result.signal
812
- ? `Linked test command terminated by signal ${result.signal}.`
813
- : undefined;
814
- const baseMessage = result.spawnError?.trim() || signalMessage || "Linked test command failed.";
815
- if (details.length === 0) {
816
- return baseMessage;
817
- }
818
- return `${baseMessage} ${details.join(" ")}`;
819
- }
820
- function hasInfraCollisionSignal(result) {
821
- const combined = [result.spawnError ?? "", result.stderr, result.stdout].join("\n");
822
- return LINKED_TEST_INFRA_COLLISION_PATTERNS.some((pattern) => pattern.test(combined));
823
- }
824
- /** Implements classify linked test failure for the public runtime surface of this module. */
825
- export function classifyLinkedTestFailure(result) {
826
- if (hasInfraCollisionSignal(result)) {
827
- return "infra_collision";
828
- }
829
- if (result.timedOut) {
830
- return "timeout";
831
- }
832
- if (result.maxBufferExceeded) {
833
- return "max_buffer";
834
- }
835
- if (result.spawnError) {
836
- return "spawn_error";
837
- }
838
- if (result.signal) {
839
- return "signal";
840
- }
841
- return "assertion_failure";
842
- }
843
- function createEmptyFailureCategoryCounts() {
844
- return {
845
- infra_collision: 0,
846
- assertion_failure: 0,
847
- empty_run: 0,
848
- timeout: 0,
849
- max_buffer: 0,
850
- spawn_error: 0,
851
- signal: 0,
852
- };
853
- }
854
- /** Implements count failure categories for the public runtime surface of this module. */
855
- export function countFailureCategories(runResults) {
856
- const counts = createEmptyFailureCategoryCounts();
857
- for (const result of runResults) {
858
- if (result.status !== "failed" || !result.failure_category) {
859
- continue;
860
- }
861
- counts[result.failure_category] += 1;
862
- }
863
- return counts;
864
- }
865
- function applyEnvDirectiveStage(env, directives) {
866
- for (const [key, value] of Object.entries(directives.env_set)) {
867
- if (LINKED_TEST_PROTECTED_ENV_KEYS.has(key.toUpperCase())) {
868
- continue;
869
- }
870
- env[key] = value;
871
- }
872
- for (const key of directives.env_clear) {
873
- if (LINKED_TEST_PROTECTED_ENV_KEYS.has(key.toUpperCase())) {
874
- continue;
875
- }
876
- delete env[key];
877
- }
878
- }
879
- function applySharedHostSafeDefaults(env) {
880
- if (env.PORT === undefined) {
881
- env.PORT = "0";
882
- }
883
- if (env.HOST === undefined) {
884
- env.HOST = "127.0.0.1";
885
- }
886
- if (env.PM_SHARED_HOST_SAFE === undefined) {
887
- env.PM_SHARED_HOST_SAFE = "1";
888
- }
889
- if (env.PLAYWRIGHT_HTML_OPEN === undefined) {
890
- env.PLAYWRIGHT_HTML_OPEN = "never";
891
- }
892
- if (env.PW_TEST_HTML_REPORT_OPEN === undefined) {
893
- env.PW_TEST_HTML_REPORT_OPEN = "never";
894
- }
895
- }
896
- function resolveEffectiveLinkedTestDirectives(runtimeDirectives, linkedTest) {
897
- const envSet = { ...runtimeDirectives.env_set, ...linkedTest.env_set };
898
- const envClear = [
899
- ...new Set([
900
- ...runtimeDirectives.env_clear,
901
- ...(linkedTest.env_clear ?? []),
902
- ]),
903
- ];
904
- const sharedHostSafe = linkedTest.shared_host_safe ?? runtimeDirectives.shared_host_safe;
905
- return {
906
- env_set: envSet,
907
- env_clear: envClear,
908
- shared_host_safe: sharedHostSafe,
909
- };
910
- }
911
- function resolveRuntimeDirectives(envSetEntries, envClearEntries, sharedHostSafe) {
912
- return {
913
- env_set: mergeEnvSetDirectives(envSetEntries, "--env-set"),
914
- env_clear: mergeEnvClearDirectives(envClearEntries, "--env-clear"),
915
- shared_host_safe: sharedHostSafe === true,
916
- };
917
- }
918
- /* c8 ignore start -- sandbox copy race/path permutations are covered by filesystem integration suites */
919
- async function copyIntoSandboxIfPresent(sourcePath, targetPath, recursive = false) {
920
- if (!(await pathExists(sourcePath))) {
921
- return;
922
- }
923
- await mkdir(path.dirname(targetPath), { recursive: true });
924
- try {
925
- if (recursive) {
926
- await cp(sourcePath, targetPath, { recursive: true, force: true });
927
- return;
928
- }
929
- await cp(sourcePath, targetPath, { force: true });
930
- }
931
- catch (error) {
932
- if (typeof error === "object" &&
933
- error !== null &&
934
- "code" in error &&
935
- error.code === "ENOENT") {
936
- return;
937
- }
938
- throw error;
939
- }
940
- }
941
- /* c8 ignore stop */
942
- async function seedLinkedTestSandbox(sandboxPmPath, sandboxGlobalPath, sourceRoots) {
943
- await copyIntoSandboxIfPresent(getSettingsPath(sourceRoots.projectPmRoot), getSettingsPath(sandboxPmPath));
944
- await copyIntoSandboxIfPresent(path.join(sourceRoots.projectPmRoot, "extensions"), path.join(sandboxPmPath, "extensions"), true);
945
- await copyIntoSandboxIfPresent(getSettingsPath(sourceRoots.globalPmRoot), getSettingsPath(sandboxGlobalPath));
946
- await copyIntoSandboxIfPresent(path.join(sourceRoots.globalPmRoot, "extensions"), path.join(sandboxGlobalPath, "extensions"), true);
947
- }
948
- async function seedLinkedTestTrackerData(sourceRoot, sandboxRoot) {
949
- if (!(await pathExists(sourceRoot))) {
950
- return;
951
- }
952
- const entries = await readdir(sourceRoot, { withFileTypes: true });
953
- for (const entry of entries) {
954
- if (LINKED_TEST_TRACKER_DIRS_TO_SKIP.has(entry.name)) {
955
- continue;
956
- }
957
- const sourcePath = path.join(sourceRoot, entry.name);
958
- const targetPath = path.join(sandboxRoot, entry.name);
959
- if (entry.isDirectory()) {
960
- await copyIntoSandboxIfPresent(sourcePath, targetPath, true);
961
- continue;
962
- }
963
- if (entry.isFile()) {
964
- await copyIntoSandboxIfPresent(sourcePath, targetPath);
965
- }
966
- }
967
- }
968
- async function countLinkedTestItemFiles(pmRoot) {
969
- if (!(await pathExists(pmRoot))) {
970
- return 0;
971
- }
972
- let total = 0;
973
- const entries = await readdir(pmRoot, { withFileTypes: true });
974
- for (const entry of entries) {
975
- if (!entry.isDirectory() ||
976
- LINKED_TEST_ITEM_COUNT_DIRS_TO_SKIP.has(entry.name)) {
977
- continue;
978
- }
979
- const folderPath = path.join(pmRoot, entry.name);
980
- let files;
981
- try {
982
- files = await readdir(folderPath, { withFileTypes: true });
983
- }
984
- catch {
985
- continue;
986
- }
987
- for (const file of files) {
988
- if (!file.isFile()) {
989
- continue;
990
- }
991
- if (ITEM_FILE_EXTENSIONS.some((extension) => file.name.toLowerCase().endsWith(extension))) {
992
- total += 1;
993
- }
994
- }
995
- }
996
- return total;
997
- }
998
- /** Implements resolve linked test failure exit code for the public runtime surface of this module. */
999
- export function resolveLinkedTestFailureExitCode(execution) {
1000
- const rawExitCode = typeof execution.exitCode === "number" ? execution.exitCode : 1;
1001
- if ((execution.timedOut || execution.maxBufferExceeded) &&
1002
- rawExitCode === 0) {
1003
- return 1;
1004
- }
1005
- return rawExitCode;
1006
- }
1007
- function splitJsonPathSegments(fieldPath) {
1008
- const segments = [];
1009
- const tokens = fieldPath.match(/[^.[\]]+|\[\d+\]/g) ?? [];
1010
- for (const token of tokens) {
1011
- if (token.startsWith("[") && token.endsWith("]")) {
1012
- const parsedIndex = Number.parseInt(token.slice(1, -1), 10);
1013
- if (!Number.isInteger(parsedIndex) || parsedIndex < 0) {
1014
- return [];
1015
- }
1016
- segments.push(parsedIndex);
1017
- continue;
1018
- }
1019
- segments.push(token);
1020
- }
1021
- return segments;
1022
- }
1023
- function readJsonPathValue(root, fieldPath) {
1024
- const normalizedPath = fieldPath.trim();
1025
- if (normalizedPath.length === 0) {
1026
- return { found: false, value: undefined };
1027
- }
1028
- const segments = splitJsonPathSegments(normalizedPath);
1029
- if (segments.length === 0) {
1030
- return { found: false, value: undefined };
1031
- }
1032
- let current = root;
1033
- for (const segment of segments) {
1034
- if (typeof segment === "number") {
1035
- if (!Array.isArray(current) || segment >= current.length) {
1036
- return { found: false, value: undefined };
1037
- }
1038
- current = current[segment];
1039
- continue;
1040
- }
1041
- if (typeof current !== "object" ||
1042
- current === null ||
1043
- !(segment in current)) {
1044
- return { found: false, value: undefined };
1045
- }
1046
- current = current[segment];
1047
- }
1048
- return { found: true, value: current };
1049
- }
1050
- /* c8 ignore start -- assertion-literal parsing edge cases are validated by assertion integration suites */
1051
- function parseAssertionLiteral(raw) {
1052
- const trimmed = raw.trim();
1053
- if (trimmed === "true") {
1054
- return true;
1055
- }
1056
- if (trimmed === "false") {
1057
- return false;
1058
- }
1059
- if (trimmed === "null") {
1060
- return null;
1061
- }
1062
- const numeric = Number(trimmed);
1063
- if (trimmed.length > 0 && Number.isFinite(numeric)) {
1064
- return numeric;
1065
- }
1066
- if ((trimmed.startsWith("{") && trimmed.endsWith("}")) ||
1067
- (trimmed.startsWith("[") && trimmed.endsWith("]"))) {
1068
- try {
1069
- return JSON.parse(trimmed);
1070
- }
1071
- catch {
1072
- // Fall back to string comparison for malformed JSON literals.
1073
- }
1074
- }
1075
- return trimmed;
1076
- }
1077
- /* c8 ignore stop */
1078
- function compareAssertionValues(actual, expected) {
1079
- if (typeof actual === "object" &&
1080
- actual !== null &&
1081
- typeof expected === "object" &&
1082
- expected !== null) {
1083
- return stableValueEquals(actual, expected);
1084
- }
1085
- return Object.is(actual, expected);
1086
- }
1087
- /* c8 ignore start -- assertion failure-path permutations are covered by linked-test integration fixtures */
1088
- function evaluateLinkedTestAssertions(linkedTest, stdout, stderr) {
1089
- const failures = [];
1090
- failures.push(...evaluateContainsAssertions("stdout", stdout, linkedTest.assert_stdout_contains));
1091
- failures.push(...evaluateRegexAssertions("stdout", stdout, linkedTest.assert_stdout_regex));
1092
- failures.push(...evaluateContainsAssertions("stderr", stderr, linkedTest.assert_stderr_contains));
1093
- failures.push(...evaluateRegexAssertions("stderr", stderr, linkedTest.assert_stderr_regex));
1094
- failures.push(...evaluateStdoutLineCountAssertion(stdout, linkedTest.assert_stdout_min_lines));
1095
- const jsonEqualsAssertions = linkedTest.assert_json_field_equals ?? {};
1096
- const jsonGteAssertions = linkedTest.assert_json_field_gte ?? {};
1097
- const needsJsonAssertions = Object.keys(jsonEqualsAssertions).length > 0 ||
1098
- Object.keys(jsonGteAssertions).length > 0;
1099
- if (!needsJsonAssertions) {
1100
- return failures;
1101
- }
1102
- let parsedJson;
1103
- try {
1104
- parsedJson = JSON.parse(stdout);
1105
- }
1106
- catch (error) {
1107
- failures.push(`stdout is not valid JSON for assert_json_field_* checks: ${error instanceof Error ? error.message : String(error)}`);
1108
- return failures;
1109
- }
1110
- for (const [fieldPath, expectedRaw] of Object.entries(jsonEqualsAssertions)) {
1111
- const resolved = readJsonPathValue(parsedJson, fieldPath);
1112
- if (!resolved.found) {
1113
- failures.push(`assert_json_field_equals missing path "${fieldPath}"`);
1114
- continue;
1115
- }
1116
- const expected = parseAssertionLiteral(expectedRaw);
1117
- if (!compareAssertionValues(resolved.value, expected)) {
1118
- failures.push(`assert_json_field_equals mismatch at "${fieldPath}" (expected=${JSON.stringify(expected)} actual=${JSON.stringify(resolved.value)})`);
1119
- }
1120
- }
1121
- for (const [fieldPath, expectedMinimum] of Object.entries(jsonGteAssertions)) {
1122
- const resolved = readJsonPathValue(parsedJson, fieldPath);
1123
- if (!resolved.found) {
1124
- failures.push(`assert_json_field_gte missing path "${fieldPath}"`);
1125
- continue;
1126
- }
1127
- if (typeof resolved.value !== "number" ||
1128
- !Number.isFinite(resolved.value)) {
1129
- failures.push(`assert_json_field_gte path "${fieldPath}" resolved to non-numeric value`);
1130
- continue;
1131
- }
1132
- if (resolved.value < expectedMinimum) {
1133
- failures.push(`assert_json_field_gte failed at "${fieldPath}" (expected >= ${expectedMinimum}, actual ${resolved.value})`);
1134
- }
1135
- }
1136
- return failures;
1137
- }
1138
- /* c8 ignore stop */
1139
- function evaluateContainsAssertions(streamName, output, expectedValues) {
1140
- const failures = [];
1141
- for (const expected of expectedValues ?? []) {
1142
- if (!output.includes(expected)) {
1143
- failures.push(`${streamName} missing required text: "${expected}"`);
1144
- }
1145
- }
1146
- return failures;
1147
- }
1148
- function evaluateRegexAssertions(streamName, output, patterns) {
1149
- const failures = [];
1150
- for (const pattern of patterns ?? []) {
1151
- try {
1152
- const regex = new RegExp(pattern, "m");
1153
- if (!regex.test(output)) {
1154
- failures.push(`${streamName} failed regex assertion: /${pattern}/m`);
1155
- }
1156
- }
1157
- catch (error) {
1158
- failures.push(`${streamName} regex assertion is invalid: /${pattern}/ (${error instanceof Error ? error.message : String(error)})`);
1159
- }
1160
- }
1161
- return failures;
1162
- }
1163
- function evaluateStdoutLineCountAssertion(stdout, minimum) {
1164
- if (typeof minimum !== "number") {
1165
- return [];
1166
- }
1167
- const lineCount = stdout
1168
- .split(/\r?\n/)
1169
- .map((line) => line.trim())
1170
- .filter((line) => line.length > 0).length;
1171
- return lineCount < minimum
1172
- ? [`stdout line count ${lineCount} is below required minimum ${minimum}`]
1173
- : [];
1174
- }
1175
- const EMPTY_LINKED_TEST_RUN_PATTERNS = [
1176
- {
1177
- code: "no_projects_matched_filters",
1178
- regex: /\bNo projects matched the filters\b/i,
1179
- },
1180
- { code: "no_test_files_found", regex: /\bNo test files found\b/i },
1181
- { code: "no_tests_found", regex: /\bNo tests found\b/i },
1182
- { code: "no_matching_tests", regex: /\bNo matching tests?\b/i },
1183
- { code: "collected_zero_items", regex: /\bcollected 0 items?\b/i },
1184
- ];
1185
- function detectEmptyLinkedTestRun(stdout, stderr) {
1186
- const combined = `${stdout}\n${stderr}`;
1187
- for (const pattern of EMPTY_LINKED_TEST_RUN_PATTERNS) {
1188
- if (pattern.regex.test(combined)) {
1189
- return pattern.code;
1190
- }
1191
- }
1192
- return null;
1193
- }
1194
- function createLinkedTestSandboxLayout(sandboxRoot) {
1195
- return {
1196
- root: sandboxRoot,
1197
- schemaProjectPmPath: path.join(sandboxRoot, "schema", "project", ".agents", "pm"),
1198
- schemaGlobalPmPath: path.join(sandboxRoot, "schema", "global"),
1199
- trackerProjectPmPath: path.join(sandboxRoot, "tracker", "project", ".agents", "pm"),
1200
- trackerGlobalPmPath: path.join(sandboxRoot, "tracker", "global"),
1201
- };
1202
- }
1203
- async function initializeLinkedTestSandboxes(layout) {
1204
- await runInit(undefined, { path: layout.schemaProjectPmPath });
1205
- await runInit(undefined, { path: layout.schemaGlobalPmPath });
1206
- await runInit(undefined, { path: layout.trackerProjectPmPath });
1207
- await runInit(undefined, { path: layout.trackerGlobalPmPath });
1208
- }
1209
- async function seedLinkedTestSandboxesFromSource(layout, sourceRoots) {
1210
- if (!sourceRoots) {
1211
- return;
1212
- }
1213
- await seedLinkedTestSandbox(layout.schemaProjectPmPath, layout.schemaGlobalPmPath, sourceRoots);
1214
- await seedLinkedTestSandbox(layout.trackerProjectPmPath, layout.trackerGlobalPmPath, sourceRoots);
1215
- await seedLinkedTestTrackerData(sourceRoots.projectPmRoot, layout.trackerProjectPmPath);
1216
- await seedLinkedTestTrackerData(sourceRoots.globalPmRoot, layout.trackerGlobalPmPath);
1217
- }
1218
- async function countLinkedTestSandboxItems(layout, sourceRoots) {
1219
- return {
1220
- sourceProjectItemCount: sourceRoots
1221
- ? await countLinkedTestItemFiles(sourceRoots.projectPmRoot)
1222
- : 0,
1223
- sourceGlobalItemCount: sourceRoots
1224
- ? await countLinkedTestItemFiles(sourceRoots.globalPmRoot)
1225
- : 0,
1226
- schemaProjectItemCount: await countLinkedTestItemFiles(layout.schemaProjectPmPath),
1227
- schemaGlobalItemCount: await countLinkedTestItemFiles(layout.schemaGlobalPmPath),
1228
- trackerProjectItemCount: await countLinkedTestItemFiles(layout.trackerProjectPmPath),
1229
- trackerGlobalItemCount: await countLinkedTestItemFiles(layout.trackerGlobalPmPath),
1230
- };
1231
- }
1232
- function buildLinkedTestExecutionContext(params) {
1233
- const trackerMode = params.effectivePmContextMode === "tracker";
1234
- const selectedSandboxProjectPmPath = trackerMode
1235
- ? params.layout.trackerProjectPmPath
1236
- : params.layout.schemaProjectPmPath;
1237
- const selectedSandboxGlobalPmPath = trackerMode
1238
- ? params.layout.trackerGlobalPmPath
1239
- : params.layout.schemaGlobalPmPath;
1240
- const selectedSandboxProjectItemCount = trackerMode
1241
- ? params.counts.trackerProjectItemCount
1242
- : params.counts.schemaProjectItemCount;
1243
- const selectedSandboxGlobalItemCount = trackerMode
1244
- ? params.counts.trackerGlobalItemCount
1245
- : params.counts.schemaGlobalItemCount;
1246
- return {
1247
- requested_pm_context_mode: params.requestedPmContextMode,
1248
- pm_context_mode: params.effectivePmContextMode,
1249
- auto_pm_context_applied: params.autoPmContextApplied,
1250
- is_pm_command: params.isPmCommand,
1251
- is_pm_tracker_read_command: params.isPmTrackerReadCommand,
1252
- source_project_pm_path: params.sourceRoots?.projectPmRoot ?? "",
1253
- sandbox_project_pm_path: selectedSandboxProjectPmPath,
1254
- source_global_pm_path: params.sourceRoots?.globalPmRoot ?? "",
1255
- sandbox_global_pm_path: selectedSandboxGlobalPmPath,
1256
- source_project_item_count: params.counts.sourceProjectItemCount,
1257
- sandbox_project_item_count: selectedSandboxProjectItemCount,
1258
- source_global_item_count: params.counts.sourceGlobalItemCount,
1259
- sandbox_global_item_count: selectedSandboxGlobalItemCount,
1260
- mismatch_detected: params.isPmCommand &&
1261
- params.counts.sourceProjectItemCount !== selectedSandboxProjectItemCount,
1262
- project_extensions_seeded: Boolean(params.sourceRoots),
1263
- global_extensions_seeded: Boolean(params.sourceRoots),
1264
- };
1265
- }
1266
- function resolveLinkedTestCommandContext(params) {
1267
- const linkedOverridePmContextMode = typeof params.linkedTest.pm_context_mode === "string" &&
1268
- params.linkedTest.pm_context_mode.trim().length > 0
1269
- ? parsePmContextMode(params.linkedTest.pm_context_mode)
1270
- : undefined;
1271
- const command = typeof params.linkedTest.command === "string" &&
1272
- params.linkedTest.command.length > 0
1273
- ? params.linkedTest.command
1274
- : undefined;
1275
- const isPmCommand = command ? commandInvokesPmCli(command) : false;
1276
- const isPmTrackerReadCommand = isPmCommand && command
1277
- ? commandInvokesPmTrackerReadCommand(command)
1278
- : false;
1279
- const autoPmContextApplied = params.options?.autoPmContext === true && isPmTrackerReadCommand;
1280
- const requestedPmContextMode = autoPmContextApplied
1281
- ? "auto"
1282
- : resolveLinkedTestRequestedContextMode(params.linkedTest, params.runLevelPmContextMode, params.options?.overrideLinkedPmContext === true);
1283
- const effectivePmContextMode = resolveLinkedTestEffectiveContextMode(requestedPmContextMode, isPmTrackerReadCommand);
1284
- return {
1285
- linkedOverridePmContextMode,
1286
- executionContext: buildLinkedTestExecutionContext({
1287
- layout: params.layout,
1288
- counts: params.counts,
1289
- sourceRoots: params.sourceRoots,
1290
- isPmCommand,
1291
- isPmTrackerReadCommand,
1292
- requestedPmContextMode,
1293
- effectivePmContextMode,
1294
- autoPmContextApplied,
1295
- }),
1296
- };
1297
- }
1298
- function buildLinkedTestSkippedResult(linkedTest, executionContext, error) {
1299
- return {
1300
- command: linkedTest.command,
1301
- path: linkedTest.path,
1302
- status: "skipped",
1303
- execution_context: executionContext,
1304
- error,
1305
- };
1306
- }
1307
- function buildLinkedTestAssertionFailureResult(linkedTest, executionContext, error, output) {
1308
- return {
1309
- command: linkedTest.command,
1310
- path: linkedTest.path,
1311
- status: "failed",
1312
- exit_code: 1,
1313
- failure_category: "assertion_failure",
1314
- execution_context: executionContext,
1315
- ...(output ? { stdout: output.stdout, stderr: output.stderr } : {}),
1316
- error,
1317
- };
1318
- }
1319
- function resolveLinkedTestPreflightResult(params) {
1320
- if (!params.linkedTest.command) {
1321
- return buildLinkedTestSkippedResult(params.linkedTest, params.executionContext, "No command configured for this linked test.");
1322
- }
1323
- const runtimeSafetySkipReason = getRuntimeSafetySkipReason(params.linkedTest.command);
1324
- if (runtimeSafetySkipReason) {
1325
- return buildLinkedTestSkippedResult(params.linkedTest, params.executionContext, runtimeSafetySkipReason);
1326
- }
1327
- const failOnMismatchByDefault = params.executionContext.pm_context_mode === "schema" &&
1328
- params.executionContext.is_pm_tracker_read_command &&
1329
- params.executionContext.mismatch_detected;
1330
- const failOnMismatchByFlag = params.options?.failOnContextMismatch === true &&
1331
- params.executionContext.is_pm_command &&
1332
- params.executionContext.mismatch_detected;
1333
- if (failOnMismatchByDefault || failOnMismatchByFlag) {
1334
- const mismatchHint = buildPmContextMismatchHint({
1335
- executionContext: params.executionContext,
1336
- runLevelPmContextMode: params.runLevelPmContextMode,
1337
- linkedOverridePmContextMode: params.linkedOverridePmContextMode,
1338
- });
1339
- const mismatchPrefix = params.options?.checkContext === true
1340
- ? "Linked test preflight PM context mismatch detected"
1341
- : "Linked test PM context mismatch detected";
1342
- return buildLinkedTestAssertionFailureResult(params.linkedTest, params.executionContext, `${mismatchPrefix} (source_project_items=${params.executionContext.source_project_item_count}, ` +
1343
- `sandbox_project_items=${params.executionContext.sandbox_project_item_count}).${mismatchHint}`);
1344
- }
1345
- if (params.options?.requireAssertionsForPm === true &&
1346
- params.executionContext.is_pm_command &&
1347
- !hasLinkedTestAssertions(params.linkedTest)) {
1348
- return buildLinkedTestAssertionFailureResult(params.linkedTest, params.executionContext, "Linked PM command requires assertions when --require-assertions-for-pm is enabled.");
1349
- }
1350
- return null;
1351
- }
1352
- function buildLinkedTestExecutionEnv(params) {
1353
- const effectiveDirectives = resolveEffectiveLinkedTestDirectives(params.runtimeDirectives, params.linkedTest);
1354
- const executionEnv = { ...process.env };
1355
- applyEnvDirectiveStage(executionEnv, params.runtimeDirectives);
1356
- applyEnvDirectiveStage(executionEnv, {
1357
- env_set: params.linkedTest.env_set ?? {},
1358
- env_clear: params.linkedTest.env_clear ?? [],
1359
- });
1360
- if (effectiveDirectives.shared_host_safe) {
1361
- applySharedHostSafeDefaults(executionEnv);
1362
- }
1363
- executionEnv.FORCE_COLOR = "0";
1364
- executionEnv.PM_PATH = params.executionContext.sandbox_project_pm_path;
1365
- executionEnv.PM_GLOBAL_PATH = params.executionContext.sandbox_global_pm_path;
1366
- return executionEnv;
1367
- }
1368
- function buildLinkedTestPassedResult(linkedTest, executionContext, execution) {
1369
- return {
1370
- command: linkedTest.command,
1371
- path: linkedTest.path,
1372
- status: "passed",
1373
- exit_code: 0,
1374
- execution_context: executionContext,
1375
- stdout: execution.stdout,
1376
- stderr: execution.stderr,
1377
- };
1378
- }
1379
- function buildLinkedTestEmptyRunResult(params) {
1380
- return {
1381
- command: params.linkedTest.command,
1382
- path: params.linkedTest.path,
1383
- status: "failed",
1384
- exit_code: 1,
1385
- failure_category: "empty_run",
1386
- execution_context: params.executionContext,
1387
- stdout: params.execution.stdout,
1388
- stderr: params.execution.stderr,
1389
- error: `Linked test reported an empty test run (${params.emptyRunSignal}) while --fail-on-empty-test-run is enabled. ` +
1390
- "Update test selection or disable --fail-on-empty-test-run for this run.",
1391
- };
1392
- }
1393
- function buildLinkedTestCommandFailureResult(params) {
1394
- return {
1395
- command: params.linkedTest.command,
1396
- path: params.linkedTest.path,
1397
- status: "failed",
1398
- exit_code: resolveLinkedTestFailureExitCode(params.execution),
1399
- failure_category: classifyLinkedTestFailure(params.execution),
1400
- execution_context: params.executionContext,
1401
- stdout: params.execution.stdout,
1402
- stderr: params.execution.stderr,
1403
- error: formatLinkedTestExecutionError(params.execution, params.timeoutMs),
1404
- };
1405
- }
1406
- function buildLinkedTestPassedExecutionResult(params) {
1407
- if (params.options?.failOnEmptyTestRun === true) {
1408
- const emptyRunSignal = detectEmptyLinkedTestRun(params.execution.stdout, params.execution.stderr);
1409
- if (emptyRunSignal) {
1410
- return buildLinkedTestEmptyRunResult({ ...params, emptyRunSignal });
1411
- }
1412
- }
1413
- const assertionFailures = evaluateLinkedTestAssertions(params.linkedTest, params.execution.stdout, params.execution.stderr);
1414
- if (assertionFailures.length > 0) {
1415
- return buildLinkedTestAssertionFailureResult(params.linkedTest, params.executionContext, `Linked test assertion(s) failed: ${assertionFailures.join("; ")}`, params.execution);
1416
- }
1417
- return buildLinkedTestPassedResult(params.linkedTest, params.executionContext, params.execution);
1418
- }
1419
- async function runSingleLinkedTest(params) {
1420
- const command = params.linkedTest.command ?? "";
1421
- const timeoutMs = (params.linkedTest.timeout_seconds ?? params.defaultTimeoutSeconds ?? 120) *
1422
- 1000;
1423
- const execution = await runLinkedTestCommand(command, timeoutMs, buildLinkedTestExecutionEnv(params), {
1424
- index: params.index + 1,
1425
- total: params.total,
1426
- timeoutMs,
1427
- command,
1428
- }, params.progressMode);
1429
- const passed = execution.exitCode === 0 &&
1430
- !execution.timedOut &&
1431
- !execution.maxBufferExceeded;
1432
- return passed
1433
- ? buildLinkedTestPassedExecutionResult({ ...params, execution })
1434
- : buildLinkedTestCommandFailureResult({ ...params, execution, timeoutMs });
1435
- }
1436
- /** Implements run linked tests for the public runtime surface of this module. */
1437
- export async function runLinkedTests(tests, defaultTimeoutSeconds, options) {
1438
- const results = [];
1439
- const sandboxRoot = await mkdtemp(path.join(tmpdir(), "pm-linked-test-"));
1440
- const layout = createLinkedTestSandboxLayout(sandboxRoot);
1441
- const runLevelPmContextMode = parsePmContextMode(options?.pmContext);
1442
- const progressMode = options?.progress === true ? "always" : "auto";
1443
- const runtimeDirectives = resolveRuntimeDirectives(options?.envSet, options?.envClear, options?.sharedHostSafe);
1444
- const sourceRoots = options?.sourceRoots;
1445
- try {
1446
- await initializeLinkedTestSandboxes(layout);
1447
- await seedLinkedTestSandboxesFromSource(layout, sourceRoots);
1448
- const counts = await countLinkedTestSandboxItems(layout, sourceRoots);
1449
- for (let index = 0; index < tests.length; index += 1) {
1450
- const linkedTest = tests[index];
1451
- const commandContext = resolveLinkedTestCommandContext({
1452
- linkedTest,
1453
- layout,
1454
- counts,
1455
- sourceRoots,
1456
- runLevelPmContextMode,
1457
- options,
1458
- });
1459
- const preflightResult = resolveLinkedTestPreflightResult({
1460
- linkedTest,
1461
- executionContext: commandContext.executionContext,
1462
- runLevelPmContextMode,
1463
- linkedOverridePmContextMode: commandContext.linkedOverridePmContextMode,
1464
- options,
1465
- });
1466
- if (preflightResult) {
1467
- results.push(preflightResult);
1468
- continue;
1469
- }
1470
- results.push(await runSingleLinkedTest({
1471
- linkedTest,
1472
- index,
1473
- total: tests.length,
1474
- defaultTimeoutSeconds,
1475
- runtimeDirectives,
1476
- progressMode,
1477
- executionContext: commandContext.executionContext,
1478
- options,
1479
- }));
1480
- }
1481
- }
1482
- finally {
1483
- await rm(layout.root, {
1484
- recursive: true,
1485
- force: true,
1486
- maxRetries: 3,
1487
- retryDelay: 100,
1488
- });
1489
- }
1490
- return results;
1491
- }
1492
- async function readLinkedTestItem(params) {
1493
- const { id, pmRoot, settings, typeToFolder } = params;
1494
- const located = await locateItem(pmRoot, id, settings.id_prefix, settings.item_format, typeToFolder);
1495
- if (!located) {
1496
- throw new PmCliError(`Item ${id} not found`, EXIT_CODE.NOT_FOUND);
1497
- }
1498
- const loaded = await readLocatedItem(located, { schema: settings.schema });
1499
- return {
1500
- itemId: located.id,
1501
- tests: loaded.document.metadata.tests ?? [],
1502
- changed: false,
1503
- };
1504
- }
1505
- function linkedTestsHaveSameIdentity(left, right) {
1506
- return (left.command === right.command &&
1507
- left.path === right.path &&
1508
- left.scope === right.scope &&
1509
- left.pm_context_mode === right.pm_context_mode);
1510
- }
1511
- function appendMissingLinkedTests(current, additions) {
1512
- const next = [...current];
1513
- for (const addition of additions) {
1514
- if (!next.some((entry) => linkedTestsHaveSameIdentity(entry, addition))) {
1515
- next.push(addition);
1516
- }
1517
- }
1518
- return next;
1519
- }
1520
- function removeLinkedTestsBySelector(current, removals) {
1521
- if (removals.length === 0) {
1522
- return current;
1523
- }
1524
- return current.filter((entry) => !removals.includes(entry.path ?? "") &&
1525
- !removals.includes(entry.command ?? ""));
1526
- }
1527
- function applyLinkedTestMutations(previous, adds, removes) {
1528
- return removeLinkedTestsBySelector(appendMissingLinkedTests(previous, adds), removes);
1529
- }
1530
- function hasTestRuntimeDirectiveFlags(options) {
1531
- return ((options.envSet?.length ?? 0) > 0 ||
1532
- (options.envClear?.length ?? 0) > 0 ||
1533
- options.sharedHostSafe === true ||
1534
- options.pmContext !== undefined ||
1535
- options.overrideLinkedPmContext === true ||
1536
- options.failOnContextMismatch === true ||
1537
- options.failOnSkipped === true ||
1538
- options.failOnEmptyTestRun === true ||
1539
- options.requireAssertionsForPm === true ||
1540
- options.checkContext === true ||
1541
- options.autoPmContext === true);
1542
- }
1543
- function assertTestRunFlagUsage(options) {
1544
- if (hasTestRuntimeDirectiveFlags(options) && options.run !== true) {
1545
- throw new PmCliError("--env-set, --env-clear, --shared-host-safe, --pm-context, --override-linked-pm-context, --fail-on-context-mismatch, --fail-on-skipped, --fail-on-empty-test-run, --require-assertions-for-pm, --check-context, and --auto-pm-context require --run", EXIT_CODE.USAGE);
1546
- }
1547
- const hasSelectorFlags = options.match !== undefined ||
1548
- options.onlyIndex !== undefined ||
1549
- options.onlyLast === true;
1550
- if (hasSelectorFlags && options.run !== true) {
1551
- throw new PmCliError("--match, --only-index, and --only-last require --run", EXIT_CODE.USAGE);
1552
- }
1553
- }
1554
- async function resolveLinkedTestItem(params) {
1555
- const { id, options, pmRoot, settings, typeToFolder, adds, removes } = params;
1556
- if (adds.length === 0 && removes.length === 0) {
1557
- return readLinkedTestItem({ id, pmRoot, settings, typeToFolder });
1558
- }
1559
- const result = await mutateItem({
1560
- pmRoot,
1561
- settings,
1562
- id,
1563
- op: "tests_add",
1564
- author: resolveAuthor(options.author, settings.author_default),
1565
- message: options.message,
1566
- force: options.force,
1567
- skipNoop: true,
1568
- mutate(document) {
1569
- const previous = document.metadata.tests ?? [];
1570
- const next = applyLinkedTestMutations(previous, adds, removes);
1571
- document.metadata.tests = next;
1572
- return {
1573
- changedFields: stableValueEquals(previous, next) ? [] : ["tests"],
1574
- };
1575
- },
1576
- });
1577
- return {
1578
- itemId: result.item.id,
1579
- tests: result.item.tests ?? [],
1580
- changed: result.changedFields.length > 0,
1581
- };
1582
- }
1583
- function resolveTestRunOptions(options, tests) {
1584
- assertTestRunFlagUsage(options);
1585
- const selectorInput = {
1586
- match: options.match,
1587
- onlyIndex: options.onlyIndex === undefined
1588
- ? undefined
1589
- : parseOnlyIndexValue(options.onlyIndex),
1590
- onlyLast: options.onlyLast,
1591
- };
1592
- const runSelection = options.run === true
1593
- ? resolveLinkedTestRunSelection(tests, selectorInput)
1594
- : undefined;
1595
- return {
1596
- defaultTimeoutSeconds: options.timeout === undefined
1597
- ? undefined
1598
- : parseOptionalNumber(options.timeout, "timeout"),
1599
- pmContextMode: parsePmContextMode(options.pmContext),
1600
- runSelection,
1601
- testsToRun: runSelection?.selected ?? tests,
1602
- };
1603
- }
1604
- async function executeSelectedLinkedTests(params) {
1605
- const { options, runOptions, pmRoot } = params;
1606
- if (options.run !== true) {
1607
- return [];
1608
- }
1609
- return await runLinkedTests(runOptions.testsToRun, runOptions.defaultTimeoutSeconds, {
1610
- progress: options.progress,
1611
- envSet: options.envSet,
1612
- envClear: options.envClear,
1613
- sharedHostSafe: options.sharedHostSafe,
1614
- pmContext: runOptions.pmContextMode,
1615
- overrideLinkedPmContext: options.overrideLinkedPmContext,
1616
- failOnContextMismatch: options.failOnContextMismatch,
1617
- failOnEmptyTestRun: options.failOnEmptyTestRun,
1618
- requireAssertionsForPm: options.requireAssertionsForPm,
1619
- checkContext: options.checkContext,
1620
- autoPmContext: options.autoPmContext,
1621
- sourceRoots: {
1622
- projectPmRoot: pmRoot,
1623
- globalPmRoot: resolveGlobalPmRoot(process.cwd()),
1624
- },
1625
- });
1626
- }
1627
- function buildTestWarnings(options, runSelection, runResults) {
1628
- const warnings = [];
1629
- if (runSelection && runSelection.selector !== null) {
1630
- warnings.push(`linked_test_selection:${runSelection.selector}=${runSelection.requested};selected=${runSelection.selected_count};skipped=${runSelection.skipped_count};indexes=${runSelection.selected_indexes.join(",")}`);
1631
- }
1632
- if (options.run === true && options.checkContext === true) {
1633
- const preflight = summarizeContextPreflight(runResults);
1634
- warnings.push(`context_preflight:checked_pm_commands=${preflight.checked_pm_commands};` +
1635
- `tracker_read_commands=${preflight.tracker_read_commands};` +
1636
- `mismatches=${preflight.mismatches};` +
1637
- `auto_remediated=${preflight.auto_remediated}`);
1638
- }
1639
- return warnings;
1640
- }
1641
- async function recordTestRunSummary(params) {
1642
- const { options, pmRoot, settings, itemId, runStartedAt, runResults, failOnSkippedTriggered, warnings, } = params;
1643
- if (options.run !== true ||
1644
- !runStartedAt ||
1645
- settings.testing.record_results_to_items !== true) {
1646
- return;
1647
- }
1648
- const summary = summarizeRunResultStatuses(runResults);
1649
- const trackedRunId = resolveTrackedRunId("test");
1650
- const attemptRaw = process.env.PM_BACKGROUND_TEST_RUN_ATTEMPT?.trim();
1651
- const parsedAttempt = attemptRaw
1652
- ? Number.parseInt(attemptRaw, 10)
1653
- : Number.NaN;
1654
- const resumedFrom = process.env.PM_BACKGROUND_TEST_RUN_RESUMED_FROM?.trim();
1655
- try {
1656
- await appendTrackedTestRunSummary({
1657
- pmRoot,
1658
- settings,
1659
- itemId,
1660
- author: resolveAuthor(options.author, settings.author_default),
1661
- message: `Track test run summary (${trackedRunId})`,
1662
- entry: {
1663
- run_id: trackedRunId,
1664
- kind: "test",
1665
- status: summary.failed > 0 || failOnSkippedTriggered === true
1666
- ? "failed"
1667
- : "passed",
1668
- started_at: runStartedAt,
1669
- finished_at: nowIso(),
1670
- recorded_at: nowIso(),
1671
- attempt: Number.isFinite(parsedAttempt) && parsedAttempt >= 1
1672
- ? parsedAttempt
1673
- : undefined,
1674
- resumed_from: resumedFrom && resumedFrom.length > 0 ? resumedFrom : undefined,
1675
- passed: summary.passed,
1676
- failed: summary.failed,
1677
- skipped: summary.skipped,
1678
- fail_on_skipped_triggered: failOnSkippedTriggered ? true : undefined,
1679
- },
1680
- });
1681
- }
1682
- catch (error) {
1683
- warnings.push(`test_result_tracking_failed:${itemId}:${error instanceof Error ? error.message : String(error)}`);
1684
- }
1685
- }
1686
- /** Implements run test for the public runtime surface of this module. */
1687
- export async function runTest(id, options, global) {
1688
- const stdinResolver = createStdinTokenResolver();
1689
- const pmRoot = resolvePmRoot(process.cwd(), global.path);
1690
- if (!(await pathExists(getSettingsPath(pmRoot)))) {
1691
- throw new PmCliError(`Tracker is not initialized at ${pmRoot}. Run pm init first.`, EXIT_CODE.NOT_FOUND);
1692
- }
1693
- const settings = await readSettings(pmRoot);
1694
- const typeRegistry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());
1695
- const resolvedAdds = await stdinResolver.resolveList(options.add, "--add");
1696
- const resolvedAddJsons = await stdinResolver.resolveList(options.addJson, "--add-json");
1697
- const resolvedRemoves = await stdinResolver.resolveList(options.remove, "--remove");
1698
- const adds = [
1699
- ...parseAddEntries(resolvedAdds),
1700
- ...parseAddJsonEntries(resolvedAddJsons),
1701
- ];
1702
- const removes = parseRemoveEntries(resolvedRemoves);
1703
- const item = await resolveLinkedTestItem({
1704
- id,
1705
- options,
1706
- pmRoot,
1707
- settings,
1708
- typeToFolder: typeRegistry.type_to_folder,
1709
- adds,
1710
- removes,
1711
- });
1712
- const runOptions = resolveTestRunOptions(options, item.tests);
1713
- const runStartedAt = options.run === true ? nowIso() : undefined;
1714
- const runResults = await executeSelectedLinkedTests({
1715
- options,
1716
- runOptions,
1717
- pmRoot,
1718
- });
1719
- const failureCategories = countFailureCategories(runResults);
1720
- const failOnSkippedTriggered = options.run === true &&
1721
- options.failOnSkipped === true &&
1722
- runResults.some((entry) => entry.status === "skipped");
1723
- const warnings = buildTestWarnings(options, runOptions.runSelection, runResults);
1724
- await recordTestRunSummary({
1725
- options,
1726
- pmRoot,
1727
- settings,
1728
- itemId: item.itemId,
1729
- runStartedAt,
1730
- runResults,
1731
- failOnSkippedTriggered,
1732
- warnings,
1733
- });
1734
- return {
1735
- ok: runResults.every((entry) => entry.status !== "failed") &&
1736
- failOnSkippedTriggered !== true,
1737
- id: item.itemId,
1738
- tests: item.tests,
1739
- run_results: runResults,
1740
- failure_categories: failureCategories,
1741
- selection: runOptions.runSelection
1742
- ? {
1743
- selector: runOptions.runSelection.selector,
1744
- requested: runOptions.runSelection.requested,
1745
- selected_indexes: runOptions.runSelection.selected_indexes,
1746
- selected_count: runOptions.runSelection.selected_count,
1747
- skipped_count: runOptions.runSelection.skipped_count,
1748
- }
1749
- : undefined,
1750
- fail_on_skipped_triggered: failOnSkippedTriggered ? true : undefined,
1751
- warnings: warnings.length > 0 ? warnings : undefined,
1752
- changed: item.changed,
1753
- count: item.tests.length,
1754
- };
1755
- }
1756
- /* c8 ignore stop */
1757
- /** Public contract for test only test command, shared by SDK and presentation-layer consumers. */
1758
- export const _testOnlyTestCommand = {
1759
- buildPmContextMismatchHint,
1760
- commandInvokesPmCli,
1761
- commandInvokesPmTrackerReadCommand,
1762
- copyIntoSandboxIfPresent,
1763
- countLinkedTestItemFiles,
1764
- ensureScope,
1765
- evaluateLinkedTestAssertions,
1766
- extractPmInvocationArgsFromSegment,
1767
- firstDirectTestRunnerSubcommand,
1768
- hasLinkedTestAssertions,
1769
- parseAddJsonEntries,
1770
- parsePmContextMode,
1771
- readJsonPathValue,
1772
- resolveAuthor,
1773
- resolveDirectRunnerSubcommand,
1774
- resolveLinkedTestEffectiveContextMode,
1775
- resolveLinkedTestFailureExitCode,
1776
- resolveLinkedTestRequestedContextMode,
1777
- resolveTrackedRunId,
1778
- runLinkedTestCommand,
1779
- appendLinkedTestOutputChunk,
1780
- seedLinkedTestSandbox,
1781
- seedLinkedTestTrackerData,
1782
- splitJsonPathSegments,
1783
- summarizeRunResultStatuses,
1784
- };
7
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="40fd73ac-c67e-5c04-9d09-27672a026c08")}catch(e){}}();
8
+ export * from "../../sdk/test/execution.js";
1785
9
  //# sourceMappingURL=test.js.map
1786
- //# debugId=1f9bc440-299f-5f61-be67-cad0c40f56a7
10
+ //# debugId=40fd73ac-c67e-5c04-9d09-27672a026c08