agentic-qe 3.15.16 → 3.15.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 (415) hide show
  1. package/.claude/skills/skills-manifest.json +1 -1
  2. package/CHANGELOG.md +78 -0
  3. package/assets/skills/skills-manifest.json +1 -1
  4. package/dist/cli/bundle.js +6 -6
  5. package/dist/cli/chunks/adapter-OMILP6KH.js +2 -0
  6. package/dist/cli/chunks/{agent-booster-wasm-45NWEKVS.js → agent-booster-wasm-6BUOFQZA.js} +2 -2
  7. package/dist/cli/chunks/{agent-handler-LVHMYFEF.js → agent-handler-HPDK3JI3.js} +2 -2
  8. package/dist/cli/chunks/{agent-memory-branch-YDWOJFEQ.js → agent-memory-branch-5QKUTWK5.js} +2 -2
  9. package/dist/cli/chunks/aqe-learning-engine-OXH5CCOS.js +2 -0
  10. package/dist/cli/chunks/{arena-CZKHXDDS.js → arena-7OKPMNHD.js} +2 -2
  11. package/dist/cli/chunks/{arena-ELDZH3CZ.js → arena-HZ35LESR.js} +4 -4
  12. package/dist/cli/chunks/{audit-5MT4T47Z.js → audit-XI575SVK.js} +3 -3
  13. package/dist/cli/chunks/base-MAK2BLTG.js +2 -0
  14. package/dist/cli/chunks/{better-sqlite3-6TGYPC2B.js → better-sqlite3-YO5X7ZJS.js} +2 -2
  15. package/dist/cli/chunks/{brain-handler-HQWZFO52.js → brain-handler-GCQZFZGQ.js} +3 -3
  16. package/dist/cli/chunks/{branch-enumerator-WVILM4SO.js → branch-enumerator-N6G44UU2.js} +2 -2
  17. package/dist/cli/chunks/{browser-RX5ALU3H.js → browser-EVKPTLOI.js} +2 -2
  18. package/dist/cli/chunks/browser-workflow-IR3VF2TL.js +2 -0
  19. package/dist/cli/chunks/{chunk-F742SZAX.js → chunk-2EQK7B5L.js} +2 -2
  20. package/dist/cli/chunks/{chunk-5NNNEWLS.js → chunk-2PCEMDIX.js} +67 -65
  21. package/dist/cli/chunks/{chunk-FBDVGRSC.js → chunk-2UUZCQSD.js} +7 -7
  22. package/dist/cli/chunks/{chunk-AG2EWGXS.js → chunk-2YWYW7NU.js} +2 -2
  23. package/dist/cli/chunks/{chunk-4LQFBY5L.js → chunk-45223KK6.js} +3 -3
  24. package/dist/cli/chunks/chunk-4EJLHNER.js +12 -0
  25. package/dist/cli/chunks/{chunk-KQYJ4VQ5.js → chunk-4L6WX5KC.js} +1 -1
  26. package/dist/cli/chunks/{chunk-KVF4NXGQ.js → chunk-4NKZU2JZ.js} +2 -2
  27. package/dist/cli/chunks/{chunk-YRAX7SFJ.js → chunk-4UKTIQDT.js} +2 -2
  28. package/dist/cli/chunks/{chunk-YTHTQPWR.js → chunk-4YM45Z5B.js} +1 -1
  29. package/dist/cli/chunks/{chunk-XIIQ5QTT.js → chunk-5FSPELOG.js} +2 -2
  30. package/dist/cli/chunks/{chunk-LKTTUHLF.js → chunk-5WATBVU6.js} +2 -2
  31. package/dist/cli/chunks/{chunk-SR52XP5F.js → chunk-5WYZVSL2.js} +1 -1
  32. package/dist/cli/chunks/{chunk-GQ6TUIKY.js → chunk-6LSZCEW2.js} +1 -1
  33. package/dist/cli/chunks/{chunk-NDJ7P2EP.js → chunk-6V6BD6PH.js} +1 -1
  34. package/dist/cli/chunks/{chunk-63GMRQ25.js → chunk-74MDUIAZ.js} +1 -1
  35. package/dist/cli/chunks/{chunk-4D4DENG6.js → chunk-776K4ZLE.js} +2 -2
  36. package/dist/cli/chunks/{chunk-ZJH5MU2I.js → chunk-7BSOO3CY.js} +2 -2
  37. package/dist/cli/chunks/{chunk-IOQ6ZQ5W.js → chunk-7SNSI4VY.js} +1 -1
  38. package/dist/cli/chunks/{chunk-LRSX2FJM.js → chunk-A4BVDYIL.js} +1 -1
  39. package/dist/cli/chunks/{chunk-SASBO5Y5.js → chunk-AGCS5GSO.js} +2 -2
  40. package/dist/cli/chunks/{chunk-GAHNO6JJ.js → chunk-AVHYJ3XP.js} +2 -2
  41. package/dist/cli/chunks/{chunk-CGGUM2YJ.js → chunk-BE7ZHM34.js} +2 -2
  42. package/dist/cli/chunks/{chunk-7TE5ONQQ.js → chunk-BHQ2DLJU.js} +1 -1
  43. package/dist/cli/chunks/{chunk-IESR7TNB.js → chunk-BKHEQIRZ.js} +2 -2
  44. package/dist/cli/chunks/{chunk-J4ELZNLY.js → chunk-BSIWI4ES.js} +2 -2
  45. package/dist/cli/chunks/{chunk-NVEWF4JV.js → chunk-C7QLLMYI.js} +1 -1
  46. package/dist/cli/chunks/{chunk-V5NHZV7S.js → chunk-CMN7PU2H.js} +2 -2
  47. package/dist/cli/chunks/{chunk-PPUZWYUG.js → chunk-COTQ44YO.js} +2 -2
  48. package/dist/cli/chunks/{chunk-5V3TI2LG.js → chunk-CQER6IJ5.js} +1 -1
  49. package/dist/cli/chunks/{chunk-SI6DPU5D.js → chunk-CVPXHDQU.js} +1 -1
  50. package/dist/cli/chunks/{chunk-6ZBXSOX6.js → chunk-CVYPMGUM.js} +2 -2
  51. package/dist/cli/chunks/{chunk-DXD6K2ZP.js → chunk-CXCMATZ6.js} +2 -2
  52. package/dist/cli/chunks/{chunk-PF7RBAYL.js → chunk-D75GLKEL.js} +2 -2
  53. package/dist/cli/chunks/chunk-DCDSN67A.js +2 -0
  54. package/dist/cli/chunks/{chunk-MAFQV4U4.js → chunk-DHKSPOUQ.js} +2 -2
  55. package/dist/cli/chunks/{chunk-RJIEG3NA.js → chunk-DJDVD6RM.js} +2 -2
  56. package/dist/cli/chunks/{chunk-GFWHUQSF.js → chunk-DNVRTJKB.js} +2 -2
  57. package/dist/cli/chunks/{chunk-G5RHFBAY.js → chunk-DS5IFRY6.js} +2 -2
  58. package/dist/cli/chunks/{chunk-BEKDKVQT.js → chunk-E7XIMOKW.js} +2 -2
  59. package/dist/cli/chunks/{chunk-5JZRZI4S.js → chunk-ECKHDHR2.js} +2 -2
  60. package/dist/cli/chunks/chunk-EPVPXHL7.js +2 -0
  61. package/dist/cli/chunks/{chunk-HVRRLYX6.js → chunk-ERYADKMZ.js} +2 -2
  62. package/dist/cli/chunks/{chunk-SUDMM5SO.js → chunk-EUWG2JG4.js} +2 -2
  63. package/dist/cli/chunks/{chunk-VSIKHWZ4.js → chunk-FAQ24UHB.js} +3 -3
  64. package/dist/cli/chunks/{chunk-YNMJEDN5.js → chunk-FBBPRVNF.js} +2 -2
  65. package/dist/cli/chunks/{chunk-72XSEQMW.js → chunk-FBSBXCZS.js} +2 -2
  66. package/dist/cli/chunks/{chunk-J7I6PABJ.js → chunk-G2X3OLMN.js} +2 -2
  67. package/dist/cli/chunks/{chunk-YU2BDRSD.js → chunk-GG7PMTHD.js} +1 -1
  68. package/dist/cli/chunks/{chunk-HLUXXCHF.js → chunk-GN6OE3JT.js} +1 -1
  69. package/dist/cli/chunks/{chunk-AGRV5B3T.js → chunk-GPPTRKEM.js} +2 -2
  70. package/dist/cli/chunks/{chunk-ZQ2XW3IP.js → chunk-H2LHWZRE.js} +2 -2
  71. package/dist/cli/chunks/{chunk-6DPYNAOK.js → chunk-HAQJFUAQ.js} +2 -2
  72. package/dist/cli/chunks/{chunk-SSUAAX3F.js → chunk-HD6W6PHV.js} +2 -2
  73. package/dist/cli/chunks/{chunk-L2DWPVNJ.js → chunk-HFZD5KLR.js} +1 -1
  74. package/dist/cli/chunks/{chunk-QVDCVD5D.js → chunk-HRUHHHVR.js} +2 -2
  75. package/dist/cli/chunks/{chunk-PINSJCM3.js → chunk-HVT7RMGV.js} +1 -1
  76. package/dist/cli/chunks/chunk-HWQPMUSN.js +2 -0
  77. package/dist/cli/chunks/{chunk-4NFQLP6R.js → chunk-HZ5O7G2P.js} +1 -1
  78. package/dist/cli/chunks/{chunk-C6D5AHBO.js → chunk-IHQGNDMX.js} +2 -2
  79. package/dist/cli/chunks/{chunk-QQWBWEJS.js → chunk-IJSROBM6.js} +3 -3
  80. package/dist/cli/chunks/{chunk-OCV2XEWQ.js → chunk-IJZFJPHS.js} +2 -2
  81. package/dist/cli/chunks/{chunk-N7HL5PHH.js → chunk-IKB3M7OF.js} +1 -1
  82. package/dist/cli/chunks/{chunk-24OX5TQJ.js → chunk-INI3Q4CN.js} +1 -1
  83. package/dist/cli/chunks/{chunk-SJ6Y4725.js → chunk-IOWEBPXJ.js} +2 -2
  84. package/dist/cli/chunks/{chunk-VXFLJNCA.js → chunk-IQL6XRF5.js} +2 -2
  85. package/dist/cli/chunks/{chunk-WP4RETKG.js → chunk-IRHXGCQR.js} +2 -2
  86. package/dist/cli/chunks/{chunk-63ZKI4PX.js → chunk-J3QFJI2Y.js} +2 -2
  87. package/dist/cli/chunks/{chunk-UHEOGZLX.js → chunk-J6QRNQJF.js} +5 -5
  88. package/dist/cli/chunks/{chunk-KNSRL6NO.js → chunk-J7Q5TXFZ.js} +2 -2
  89. package/dist/cli/chunks/{chunk-L6QSTQME.js → chunk-JHKKIJT2.js} +2 -2
  90. package/dist/cli/chunks/{chunk-VMDFFTCK.js → chunk-JI33PMPZ.js} +1 -1
  91. package/dist/cli/chunks/{chunk-E3D4GPLP.js → chunk-JRIJM4LE.js} +3 -3
  92. package/dist/cli/chunks/{chunk-XIQW7EFL.js → chunk-JVWZAE2H.js} +2 -2
  93. package/dist/cli/chunks/{chunk-YPBSUGMI.js → chunk-K7WAI662.js} +1 -1
  94. package/dist/cli/chunks/{chunk-RV74I3YO.js → chunk-KB34MTFZ.js} +2 -2
  95. package/dist/cli/chunks/{chunk-MI5MFHRA.js → chunk-KPIPVSIP.js} +2 -2
  96. package/dist/cli/chunks/{chunk-Y4PFUMOU.js → chunk-KR2TAAF6.js} +1 -1
  97. package/dist/cli/chunks/{chunk-W5HQUIML.js → chunk-KT2QCXO6.js} +2 -2
  98. package/dist/cli/chunks/{chunk-SSYAQZXA.js → chunk-KTORRIX3.js} +2 -2
  99. package/dist/cli/chunks/{chunk-CRPIYUTJ.js → chunk-LCWEQRZI.js} +2 -2
  100. package/dist/cli/chunks/{chunk-NO3IV5Q5.js → chunk-LG5PPJT7.js} +1 -1
  101. package/dist/cli/chunks/{chunk-5VZL4UVN.js → chunk-LIF6UWHV.js} +2 -2
  102. package/dist/cli/chunks/{chunk-32BPDLRZ.js → chunk-LN7NKE3N.js} +2 -2
  103. package/dist/cli/chunks/{chunk-ZB3LEFYG.js → chunk-LOLSZG5J.js} +2 -2
  104. package/dist/cli/chunks/{chunk-6XXZDV2C.js → chunk-LOMT4UC2.js} +2 -2
  105. package/dist/cli/chunks/{chunk-JDIYMZCQ.js → chunk-LRKLATSH.js} +2 -2
  106. package/dist/cli/chunks/{chunk-5SPCGMBB.js → chunk-LRY6UIRI.js} +2 -2
  107. package/dist/cli/chunks/{chunk-5PBLPQ5T.js → chunk-LV7UIK4Q.js} +2 -2
  108. package/dist/cli/chunks/{chunk-FDDC72IA.js → chunk-M2YI5YUR.js} +2 -2
  109. package/dist/cli/chunks/{chunk-D6COXLYE.js → chunk-MCXW3DKE.js} +2 -2
  110. package/dist/cli/chunks/{chunk-J442IZLE.js → chunk-MGZ6XZHU.js} +1 -1
  111. package/dist/cli/chunks/{chunk-TIUKLYAI.js → chunk-MLMD3I75.js} +1 -1
  112. package/dist/cli/chunks/{chunk-PHT5N7SC.js → chunk-MVVVGQJ6.js} +2 -2
  113. package/dist/cli/chunks/{chunk-525CFDUE.js → chunk-ND72UDVH.js} +2 -2
  114. package/dist/cli/chunks/{chunk-XWUWX7BV.js → chunk-NE3LRUNC.js} +4 -4
  115. package/dist/cli/chunks/{chunk-DTMAS2GB.js → chunk-NKUHMA4T.js} +2 -2
  116. package/dist/cli/chunks/{chunk-QPEOLAAS.js → chunk-NQFDJ6BT.js} +1 -1
  117. package/dist/cli/chunks/{chunk-MO55CVMT.js → chunk-NZJVDOUN.js} +14 -14
  118. package/dist/cli/chunks/{chunk-NZU4ACBZ.js → chunk-O7VJ3VKD.js} +2 -2
  119. package/dist/cli/chunks/{chunk-32GN3JKR.js → chunk-OJIUIEI4.js} +1 -1
  120. package/dist/cli/chunks/{chunk-UNGBRZDK.js → chunk-OO2M2QUV.js} +3 -3
  121. package/dist/cli/chunks/{chunk-CJSHWQXP.js → chunk-ORQ2YBRR.js} +2 -2
  122. package/dist/cli/chunks/chunk-OWIQR6N2.js +4 -0
  123. package/dist/cli/chunks/{chunk-NAEWCFQT.js → chunk-OWIZBZLN.js} +2 -2
  124. package/dist/cli/chunks/{chunk-24QHCVX6.js → chunk-P3D7SEHW.js} +1 -1
  125. package/dist/cli/chunks/{chunk-YLMNVLDK.js → chunk-P4OB6WDJ.js} +1 -1
  126. package/dist/cli/chunks/{chunk-PEQDY4BO.js → chunk-PCL5JRKN.js} +2 -2
  127. package/dist/cli/chunks/{chunk-IUBJVHNB.js → chunk-PIWGKGWP.js} +2 -2
  128. package/dist/cli/chunks/{chunk-GJYHWYXR.js → chunk-PK34KJH7.js} +2 -2
  129. package/dist/cli/chunks/{chunk-5B5QPCNU.js → chunk-POPSZDI2.js} +4 -4
  130. package/dist/cli/chunks/{chunk-HCH4Y6XX.js → chunk-Q6F3DYZN.js} +2 -2
  131. package/dist/cli/chunks/{chunk-SHKOCGNK.js → chunk-QJSSUBO3.js} +2 -2
  132. package/dist/cli/chunks/{chunk-DVYHMDFR.js → chunk-QN7HP2UW.js} +421 -418
  133. package/dist/cli/chunks/{chunk-ZFL436FN.js → chunk-QSQNXBD2.js} +2 -2
  134. package/dist/cli/chunks/{chunk-TVGI32MB.js → chunk-QTQDX4TZ.js} +3 -3
  135. package/dist/cli/chunks/{chunk-EK7OLYOZ.js → chunk-R3KBOQ3O.js} +2 -2
  136. package/dist/cli/chunks/{chunk-LE4QJREF.js → chunk-REY52O7J.js} +1 -1
  137. package/dist/cli/chunks/{chunk-LQLPB2T6.js → chunk-RKCN4B26.js} +2 -2
  138. package/dist/cli/chunks/{chunk-ZR2TKVXQ.js → chunk-S3DT5TPR.js} +2 -2
  139. package/dist/cli/chunks/{chunk-6ICX3FEG.js → chunk-S3TBOKAZ.js} +22 -22
  140. package/dist/cli/chunks/{chunk-JHQCRRJI.js → chunk-SAEECT23.js} +2 -2
  141. package/dist/cli/chunks/{chunk-VWPM27GU.js → chunk-SAZ4PJBR.js} +2 -2
  142. package/dist/cli/chunks/{chunk-KPRCB5LT.js → chunk-SFITYZLV.js} +2 -2
  143. package/dist/cli/chunks/{chunk-5LAVKGLH.js → chunk-SRBCBVSI.js} +2 -2
  144. package/dist/cli/chunks/{chunk-O5W3FIO6.js → chunk-SUAZ5Z47.js} +2 -2
  145. package/dist/cli/chunks/{chunk-KU2AUFGX.js → chunk-TDZ6N43D.js} +2 -2
  146. package/dist/cli/chunks/{chunk-YAPLJR7K.js → chunk-TIVKDIF7.js} +2 -2
  147. package/dist/cli/chunks/{chunk-U2A7NHZA.js → chunk-TM75GAXG.js} +2 -2
  148. package/dist/cli/chunks/{chunk-A5GBXCP5.js → chunk-TWBZONKT.js} +2 -2
  149. package/dist/cli/chunks/{chunk-I7MQIM2U.js → chunk-U4S74IIZ.js} +1 -1
  150. package/dist/cli/chunks/{chunk-3HD7E6HN.js → chunk-U5SMBJ6F.js} +2 -2
  151. package/dist/cli/chunks/{chunk-JQ3DYUMS.js → chunk-UHJVZEQA.js} +2 -2
  152. package/dist/cli/chunks/{chunk-C5FP5GW3.js → chunk-UOVCTK5L.js} +2 -2
  153. package/dist/cli/chunks/{chunk-HJ6ZGVTB.js → chunk-VDEKVIP5.js} +2 -2
  154. package/dist/cli/chunks/{chunk-KXCLACFG.js → chunk-VITV7AEC.js} +2 -2
  155. package/dist/cli/chunks/{chunk-P3EYRILV.js → chunk-VKREKVFI.js} +2 -2
  156. package/dist/cli/chunks/{chunk-2H4XH6FT.js → chunk-VLTDW7XJ.js} +2 -2
  157. package/dist/cli/chunks/{chunk-MD43XRX5.js → chunk-VQFV2IPV.js} +1 -1
  158. package/dist/cli/chunks/{chunk-67Z5R7RJ.js → chunk-VYPVU3JF.js} +2 -2
  159. package/dist/cli/chunks/{chunk-SDLWKRVL.js → chunk-WAOEQA3W.js} +2 -2
  160. package/dist/cli/chunks/{chunk-IOYG4VFL.js → chunk-WBDWHHKP.js} +2 -2
  161. package/dist/cli/chunks/{chunk-ASEOFRIG.js → chunk-WX4PO65Q.js} +2 -2
  162. package/dist/cli/chunks/chunk-X2DWHGCC.js +6 -0
  163. package/dist/cli/chunks/{chunk-CEYSYSK5.js → chunk-X5QD76IU.js} +2 -2
  164. package/dist/cli/chunks/{chunk-GSKMOPL7.js → chunk-XBTGEYED.js} +2 -2
  165. package/dist/cli/chunks/{chunk-FL64OUBA.js → chunk-XEMCHGAJ.js} +2 -2
  166. package/dist/cli/chunks/{chunk-2YZ4G6NW.js → chunk-XEYFZLIT.js} +1 -1
  167. package/dist/cli/chunks/{chunk-EA4YQVKS.js → chunk-XFTX3KLE.js} +1 -1
  168. package/dist/cli/chunks/{chunk-HGWXF45W.js → chunk-XPTCQKVE.js} +1 -1
  169. package/dist/cli/chunks/{chunk-CAKMOVZ6.js → chunk-YAJOBZE5.js} +2 -2
  170. package/dist/cli/chunks/{chunk-NQXXI77K.js → chunk-YCVLKU6H.js} +2 -2
  171. package/dist/cli/chunks/{chunk-AR67RJPY.js → chunk-YD2C6EPN.js} +2 -2
  172. package/dist/cli/chunks/{chunk-S75SOOZL.js → chunk-YKRLUTK7.js} +2 -2
  173. package/dist/cli/chunks/{chunk-IOKYCMTJ.js → chunk-YMUY3TES.js} +2 -2
  174. package/dist/cli/chunks/{chunk-5QO3R3TU.js → chunk-YR5QBUHZ.js} +2 -2
  175. package/dist/cli/chunks/{chunk-AJMJNQMP.js → chunk-Z7SKUC6P.js} +1 -1
  176. package/dist/cli/chunks/{chunk-KITOPKRG.js → chunk-ZAQMRFBB.js} +2 -2
  177. package/dist/cli/chunks/{chunk-AAMLQ2LF.js → chunk-ZC3KDNJW.js} +3 -3
  178. package/dist/cli/chunks/{chunk-VJCIEHEF.js → chunk-ZGV7L4MW.js} +1 -1
  179. package/dist/cli/chunks/{chunk-BY5OF7OH.js → chunk-ZN35XSKF.js} +2 -2
  180. package/dist/cli/chunks/{chunk-KKU2QGSJ.js → chunk-ZNXM6WVL.js} +2 -2
  181. package/dist/cli/chunks/{chunk-FLNAW7C4.js → chunk-ZP5AWQRO.js} +2 -2
  182. package/dist/cli/chunks/{chunk-IHRXZZQM.js → chunk-ZTP3DQ5M.js} +1 -1
  183. package/dist/cli/chunks/{chunk-OAEE6JWQ.js → chunk-ZVMSSCTH.js} +2 -2
  184. package/dist/cli/chunks/{chunk-M7WJCTG3.js → chunk-ZWUF27P4.js} +2 -2
  185. package/dist/cli/chunks/{ci-MFUR4CWV.js → ci-3RTTTS2D.js} +2 -2
  186. package/dist/cli/chunks/{ci-config-PNDLQ6XV.js → ci-config-XRUR3I4K.js} +2 -2
  187. package/dist/cli/chunks/{ci-output-PFZ4M7NC.js → ci-output-E5IAMU2U.js} +2 -2
  188. package/dist/cli/chunks/{circuit-breaker-5HH6NLZN.js → circuit-breaker-SHR2P44P.js} +2 -2
  189. package/dist/cli/chunks/{claude-flow-setup-QCKYLGLC.js → claude-flow-setup-ZDDILFMF.js} +2 -2
  190. package/dist/cli/chunks/client-NO5FOWT4.js +2 -0
  191. package/dist/cli/chunks/{cline-installer-EASVPFXR.js → cline-installer-BGYVUM6G.js} +2 -2
  192. package/dist/cli/chunks/{code-UJXDVYRK.js → code-PJ4MC3MC.js} +3 -3
  193. package/dist/cli/chunks/{code-index-extractor-BZJ3UDP4.js → code-index-extractor-IW2P22YG.js} +2 -2
  194. package/dist/cli/chunks/{codex-installer-XSQZUVOZ.js → codex-installer-A7WZ6OGL.js} +2 -2
  195. package/dist/cli/chunks/{completions-OWOOJFI2.js → completions-KS23WD5J.js} +2 -2
  196. package/dist/cli/chunks/{complexity-analyzer-KP5TOHDT.js → complexity-analyzer-Q7GLSR2E.js} +2 -2
  197. package/dist/cli/chunks/{continuedev-installer-IFKQXLHM.js → continuedev-installer-SK55BFW2.js} +2 -2
  198. package/dist/cli/chunks/copilot-installer-3N5J3WTM.js +3 -0
  199. package/dist/cli/chunks/core-handlers-JNAZPXE2.js +2 -0
  200. package/dist/cli/chunks/{cost-tracker-MMDDNKZB.js → cost-tracker-NENVSO4A.js} +2 -2
  201. package/dist/cli/chunks/{coverage-LUH2B7NT.js → coverage-5L7UQWDH.js} +3 -3
  202. package/dist/cli/chunks/cross-domain-router-HEBM767Z.js +2 -0
  203. package/dist/cli/chunks/{cursor-installer-4YLM5GWM.js → cursor-installer-XXBO2ZE6.js} +2 -2
  204. package/dist/cli/chunks/{daemon-MZKVM4CJ.js → daemon-CDCQU3LR.js} +3 -3
  205. package/dist/cli/chunks/{daemon-CAVZ7OFV.js → daemon-JEBJGEUK.js} +4 -4
  206. package/dist/cli/chunks/{dag-attention-scheduler-X4CYW665.js → dag-attention-scheduler-HOMMF7FA.js} +2 -2
  207. package/dist/cli/chunks/{detect-7BM2XINO.js → detect-FXCOUG6X.js} +2 -2
  208. package/dist/cli/chunks/{dist-node-Y5APLEYB.js → dist-node-GXQ7FMTY.js} +2 -2
  209. package/dist/cli/chunks/{domain-handler-X3ZRJNAH.js → domain-handler-TI3JBAPC.js} +2 -2
  210. package/dist/cli/chunks/{domain-plugins-2UW5KQJB.js → domain-plugins-R7LTUM32.js} +2 -2
  211. package/dist/cli/chunks/{domain-transfer-35W4CIBV.js → domain-transfer-LBIAFHIQ.js} +2 -2
  212. package/dist/cli/chunks/dream-GQDCEJMS.js +2 -0
  213. package/dist/cli/chunks/embed-and-insert-pattern-33KLHDD5.js +3 -0
  214. package/dist/cli/chunks/{embedding-space-SBM2MZD2.js → embedding-space-HHLWTBF5.js} +2 -2
  215. package/dist/cli/chunks/{eval-4QA2SROK.js → eval-KDOZMAXJ.js} +2 -2
  216. package/dist/cli/chunks/{experience-capture-middleware-Z6BF6KYM.js → experience-capture-middleware-X45PECQN.js} +3 -3
  217. package/dist/cli/chunks/{fast-paths-FIORX6GN.js → fast-paths-462V6UUB.js} +2 -2
  218. package/dist/cli/chunks/{feature-flags-ZOO7LMIC.js → feature-flags-G66OT3AS.js} +2 -2
  219. package/dist/cli/chunks/{feature-flags-6LYI2T4G.js → feature-flags-NIRQ4YDM.js} +2 -2
  220. package/dist/cli/chunks/file-discovery-33USPLB5.js +2 -0
  221. package/dist/cli/chunks/{fleet-7WF53H4F.js → fleet-PXWGB7CU.js} +3 -3
  222. package/dist/cli/chunks/{gnn-wrapper-KJ6B7BRM.js → gnn-wrapper-7MUW3M5M.js} +2 -2
  223. package/dist/cli/chunks/{heartbeat-handler-DEKKMOVW.js → heartbeat-handler-5237PB35.js} +4 -4
  224. package/dist/cli/chunks/heartbeat-scheduler-LIXLC5IH.js +2 -0
  225. package/dist/cli/chunks/hnsw-adapter-62D5UH27.js +2 -0
  226. package/dist/cli/chunks/hnsw-index-GSGUMQQC.js +2 -0
  227. package/dist/cli/chunks/{hnsw-legacy-bridge-L27WS27N.js → hnsw-legacy-bridge-OSQPW7JP.js} +2 -2
  228. package/dist/cli/chunks/{hnswlib-node-4YOQC6L4.js → hnswlib-node-GX6WG2GB.js} +2 -2
  229. package/dist/cli/chunks/{hooks-TAOKV4EJ.js → hooks-GUWHL7VC.js} +10 -10
  230. package/dist/cli/chunks/hybrid-backend-FRWP4BOY.js +2 -0
  231. package/dist/cli/chunks/{hypergraph-engine-BODRJLHL.js → hypergraph-engine-SRWLLCU3.js} +2 -2
  232. package/dist/cli/chunks/{hypergraph-handler-RKMYJNTU.js → hypergraph-handler-AVOPRHHO.js} +3 -3
  233. package/dist/cli/chunks/impact-analyzer-7KF3AQXV.js +2 -0
  234. package/dist/cli/chunks/{init-guard-MXHSLSB2.js → init-guard-P4N6EVZS.js} +2 -2
  235. package/dist/cli/chunks/{init-handler-HUE57IFW.js → init-handler-LRGWOJMD.js} +6 -6
  236. package/dist/cli/chunks/init-wizard-XWWAXY25.js +2 -0
  237. package/dist/cli/chunks/kernel-ZEJPNDBW.js +2 -0
  238. package/dist/cli/chunks/{kilocode-installer-S333IKYQ.js → kilocode-installer-7R2EPOQ6.js} +2 -2
  239. package/dist/cli/chunks/{kiro-installer-WM5DLQWC.js → kiro-installer-QNM7DPOB.js} +2 -2
  240. package/dist/cli/chunks/knowledge-graph-RRZQS7KY.js +2 -0
  241. package/dist/cli/chunks/{learning-LNHMQLH5.js → learning-7OIZBPXZ.js} +3 -3
  242. package/dist/cli/chunks/{llm-router-EWFXYZZR.js → llm-router-SIDXES23.js} +4 -4
  243. package/dist/cli/chunks/llm-router-service-3OSW67LC.js +2 -0
  244. package/dist/cli/chunks/{load-FGYGWVDK.js → load-EI2E2C3S.js} +2 -2
  245. package/dist/cli/chunks/load-test-7TRIH2WJ.js +2 -0
  246. package/dist/cli/chunks/{mcp-2FHNAAOM.js → mcp-IOE5WOCS.js} +2 -2
  247. package/dist/cli/chunks/{memory-DZMQ73AB.js → memory-DLYGJAP7.js} +5 -5
  248. package/dist/cli/chunks/memory-backend-G7ZW6Q2B.js +2 -0
  249. package/dist/cli/chunks/memory-handlers-TPF3KCO5.js +2 -0
  250. package/dist/cli/chunks/{multi-model-executor-6F2UAEUW.js → multi-model-executor-WHH4YCHM.js} +2 -2
  251. package/dist/cli/chunks/{opencode-installer-XY3BGOTZ.js → opencode-installer-63FDZAMS.js} +2 -2
  252. package/dist/cli/chunks/{orchestrator-B4CNKUOS.js → orchestrator-3LA776KK.js} +5 -5
  253. package/dist/cli/chunks/pattern-null-store-OU3ZC3NR.js +2 -0
  254. package/dist/cli/chunks/{pattern-usage-recorder-R4GUFNMD.js → pattern-usage-recorder-NW54QUGI.js} +2 -2
  255. package/dist/cli/chunks/{pipeline-FG5RKVRO.js → pipeline-P3TYX6J6.js} +2 -2
  256. package/dist/cli/chunks/{platform-3BT4KEVJ.js → platform-FNA2WLI6.js} +2 -2
  257. package/dist/cli/chunks/{plugin-WI4RIN7O.js → plugin-NJS7BC2S.js} +2 -2
  258. package/dist/cli/chunks/{prime-radiant-advanced-wasm-7ECDNQFS.js → prime-radiant-advanced-wasm-NIAVL2OT.js} +2 -2
  259. package/dist/cli/chunks/project-root-GMOFJEKD.js +2 -0
  260. package/dist/cli/chunks/protocol-executor-AD345XRO.js +2 -0
  261. package/dist/cli/chunks/{protocol-handler-WNODKPGW.js → protocol-handler-JU5C4JHY.js} +2 -2
  262. package/dist/cli/chunks/{prove-5RHAEPYZ.js → prove-35VOSLYP.js} +2 -2
  263. package/dist/cli/chunks/qe-reasoning-bank-NLTP26RC.js +2 -0
  264. package/dist/cli/chunks/{quality-WPHR7BGQ.js → quality-ET74X7HN.js} +2 -2
  265. package/dist/cli/chunks/{quality-gate-4RKTEZMX.js → quality-gate-FEDQISNB.js} +3 -3
  266. package/dist/cli/chunks/queen-coordinator-2TB4FWS6.js +2 -0
  267. package/dist/cli/chunks/real-embeddings-II6CXTCI.js +2 -0
  268. package/dist/cli/chunks/{ref-validation-TPAWHOHH.js → ref-validation-DTBPYCEB.js} +2 -2
  269. package/dist/cli/chunks/{roocode-installer-7AVHFNDI.js → roocode-installer-LYQEMR4J.js} +2 -2
  270. package/dist/cli/chunks/router-PLM3MWME.js +2 -0
  271. package/dist/cli/chunks/routing-feedback-I7VOX2HU.js +2 -0
  272. package/dist/cli/chunks/{routing-handler-YKEDVJSH.js → routing-handler-DJOJFPII.js} +2 -2
  273. package/dist/cli/chunks/{ruvector-commands-JUAMM354.js → ruvector-commands-VXYGJDPW.js} +2 -2
  274. package/dist/cli/chunks/rvf-dual-writer-GQZHFWO2.js +2 -0
  275. package/dist/cli/chunks/rvf-migration-adapter-3TVKBCAM.js +2 -0
  276. package/dist/cli/chunks/rvf-migration-coordinator-XUHKLMT6.js +2 -0
  277. package/dist/cli/chunks/rvf-native-adapter-5GUTYOWS.js +2 -0
  278. package/dist/cli/chunks/{rvf-store-integrity-VJDUIRTX.js → rvf-store-integrity-GA2ZYOEG.js} +2 -2
  279. package/dist/cli/chunks/safe-db-RZPQGLGQ.js +2 -0
  280. package/dist/cli/chunks/schedule-G7JMQDUX.js +2 -0
  281. package/dist/cli/chunks/scheduler-4SEGPCKD.js +2 -0
  282. package/dist/cli/chunks/{security-ORDN3RD2.js → security-MM6YOECX.js} +3 -3
  283. package/dist/cli/chunks/{shared-rvf-adapter-CF4BCIO7.js → shared-rvf-adapter-6AHPA3V5.js} +2 -2
  284. package/dist/cli/chunks/{shared-rvf-dual-writer-C32UBR6D.js → shared-rvf-dual-writer-EYAVY2GZ.js} +2 -2
  285. package/dist/cli/chunks/sqlite-persistence-IVE4SQXR.js +2 -0
  286. package/dist/cli/chunks/{standalone-memory-OXRJYZXN.js → standalone-memory-A3PLB4CZ.js} +2 -2
  287. package/dist/cli/chunks/{status-handler-BCX5D4HY.js → status-handler-OSSFAP4Z.js} +2 -2
  288. package/dist/cli/chunks/{structural-health-LFG7RUU6.js → structural-health-PGY5XUNO.js} +2 -2
  289. package/dist/cli/chunks/{sync-YJEE2K2L.js → sync-CWEHYGNN.js} +2 -2
  290. package/dist/cli/chunks/sync-PM6D7EQF.js +2 -0
  291. package/dist/cli/chunks/{task-handler-6LXKPTXJ.js → task-handler-LHMQ75W4.js} +2 -2
  292. package/dist/cli/chunks/{task-handlers-CILP36I7.js → task-handlers-S2TX5FTR.js} +3 -3
  293. package/dist/cli/chunks/test-4EGZZ6NJ.js +34 -0
  294. package/dist/cli/chunks/test-runner-process-72YACW6M.js +2 -0
  295. package/dist/cli/chunks/{test-scheduling-ISI2O4Q5.js → test-scheduling-YJQHH3XE.js} +3 -3
  296. package/dist/cli/chunks/{token-bootstrap-VUELSBOS.js → token-bootstrap-DJNETMVW.js} +2 -2
  297. package/dist/cli/chunks/{token-usage-XOC5KG7S.js → token-usage-WPNOJR6H.js} +2 -2
  298. package/dist/cli/chunks/{transformers-LSLQAARK.js → transformers-4MRPXCPU.js} +2 -2
  299. package/dist/cli/chunks/tree-sitter-wasm-parser-UVWSDXFR.js +2 -0
  300. package/dist/cli/chunks/{types-5BLCGLCR.js → types-6P5FB4EB.js} +2 -2
  301. package/dist/cli/chunks/unified-memory-2VMGSGQL.js +2 -0
  302. package/dist/cli/chunks/unified-memory-hnsw-3KULVD3N.js +2 -0
  303. package/dist/cli/chunks/unified-persistence-QCSLU2SV.js +2 -0
  304. package/dist/cli/chunks/{upgrade-RQJYLK3J.js → upgrade-4ICTN63Y.js} +2 -2
  305. package/dist/cli/chunks/{validate-QBHWXXCK.js → validate-HQF5GZ7L.js} +2 -2
  306. package/dist/cli/chunks/{validate-swarm-IKXBKFB5.js → validate-swarm-45JYG7VW.js} +2 -2
  307. package/dist/cli/chunks/visual-security-ZYP2KPH7.js +2 -0
  308. package/dist/cli/chunks/{web-tree-sitter-ZF6FIE5R.js → web-tree-sitter-UOTWZLNH.js} +2 -2
  309. package/dist/cli/chunks/{windsurf-installer-HQGDZT5D.js → windsurf-installer-WDWSBXGN.js} +2 -2
  310. package/dist/cli/chunks/witness-chain-5QRT7EMX.js +2 -0
  311. package/dist/cli/chunks/{witness-chain-DCHCAMSQ.js → witness-chain-DOYMNPC7.js} +2 -2
  312. package/dist/cli/chunks/{witness-chain-repair-PUX2NFDL.js → witness-chain-repair-CUF2AFQB.js} +2 -2
  313. package/dist/cli/chunks/{witness-chain-verifier-PX2OQ6XT.js → witness-chain-verifier-JB42X62J.js} +2 -2
  314. package/dist/cli/chunks/{witness-key-manager-RXYQNFJB.js → witness-key-manager-LXXO6L2G.js} +2 -2
  315. package/dist/cli/chunks/{workflow-FBKCA4H6.js → workflow-6ARK47NF.js} +4 -4
  316. package/dist/cli/chunks/workflow-orchestrator-RYDDWIXN.js +2 -0
  317. package/dist/cli/chunks/{wrappers-TWSKBTWD.js → wrappers-CYQBOMPL.js} +2 -2
  318. package/dist/cli/commands/test.js +26 -4
  319. package/dist/coordination/handlers/test-execution-handlers.js +64 -20
  320. package/dist/domains/code-intelligence/services/semantic-analyzer.d.ts +8 -3
  321. package/dist/domains/code-intelligence/services/semantic-analyzer.js +39 -25
  322. package/dist/domains/code-intelligence/services/text-relevance.d.ts +32 -0
  323. package/dist/domains/code-intelligence/services/text-relevance.js +63 -0
  324. package/dist/domains/test-execution/coordinator.d.ts +3 -1
  325. package/dist/domains/test-execution/coordinator.js +13 -4
  326. package/dist/domains/test-execution/interfaces.d.ts +5 -0
  327. package/dist/domains/test-execution/plugin.js +2 -0
  328. package/dist/domains/test-execution/services/flaky-detector.d.ts +9 -1
  329. package/dist/domains/test-execution/services/flaky-detector.js +26 -8
  330. package/dist/domains/test-execution/services/retry-handler.d.ts +7 -1
  331. package/dist/domains/test-execution/services/retry-handler.js +44 -5
  332. package/dist/domains/test-execution/services/runner-test-cases.d.ts +2 -0
  333. package/dist/domains/test-execution/services/runner-test-cases.js +7 -3
  334. package/dist/domains/test-execution/services/test-executor.d.ts +5 -1
  335. package/dist/domains/test-execution/services/test-executor.js +79 -15
  336. package/dist/init/copilot-installer.d.ts +6 -0
  337. package/dist/init/copilot-installer.js +37 -17
  338. package/dist/init/platform-config-generator.d.ts +10 -0
  339. package/dist/init/platform-config-generator.js +26 -1
  340. package/dist/kernel/unified-memory.d.ts +8 -0
  341. package/dist/kernel/unified-memory.js +13 -0
  342. package/dist/learning/embedder-endpoint-client.d.ts +45 -0
  343. package/dist/learning/embedder-endpoint-client.js +98 -3
  344. package/dist/learning/embedding-space-registry.d.ts +75 -0
  345. package/dist/learning/embedding-space-registry.js +142 -0
  346. package/dist/learning/real-embeddings.d.ts +3 -0
  347. package/dist/learning/real-embeddings.js +49 -11
  348. package/dist/mcp/bundle.js +564 -555
  349. package/dist/mcp/protocol-server.js +1 -1
  350. package/dist/shared/embeddings/index.d.ts +2 -2
  351. package/dist/shared/embeddings/index.js +1 -1
  352. package/dist/shared/embeddings/nomic-embedder.d.ts +8 -2
  353. package/dist/shared/embeddings/nomic-embedder.js +19 -11
  354. package/dist/shared/embeddings/ollama-client.d.ts +28 -2
  355. package/dist/shared/embeddings/ollama-client.js +84 -22
  356. package/dist/shared/embeddings/types.d.ts +15 -0
  357. package/dist/shared/embeddings/types.js +4 -0
  358. package/dist/shared/pytest-junit-report.d.ts +93 -0
  359. package/dist/shared/pytest-junit-report.js +241 -0
  360. package/dist/shared/test-runner-project.d.ts +51 -1
  361. package/dist/shared/test-runner-project.js +140 -25
  362. package/package.json +1 -1
  363. package/dist/cli/chunks/adapter-6CQ2PIP5.js +0 -2
  364. package/dist/cli/chunks/aqe-learning-engine-73RR52VS.js +0 -2
  365. package/dist/cli/chunks/base-SMCMMVGP.js +0 -2
  366. package/dist/cli/chunks/browser-workflow-A2MEZ66K.js +0 -2
  367. package/dist/cli/chunks/chunk-EGYE5UPQ.js +0 -2
  368. package/dist/cli/chunks/chunk-KL7OKSU2.js +0 -4
  369. package/dist/cli/chunks/chunk-M4FRQ4TE.js +0 -12
  370. package/dist/cli/chunks/chunk-UE5ZOZR2.js +0 -2
  371. package/dist/cli/chunks/client-MHQRTZM4.js +0 -2
  372. package/dist/cli/chunks/copilot-installer-IGJ6KGQY.js +0 -3
  373. package/dist/cli/chunks/core-handlers-UAK3LLJE.js +0 -2
  374. package/dist/cli/chunks/cross-domain-router-WTRZQPNQ.js +0 -2
  375. package/dist/cli/chunks/dream-EJY24JN6.js +0 -2
  376. package/dist/cli/chunks/embed-and-insert-pattern-COG4C7ZI.js +0 -3
  377. package/dist/cli/chunks/file-discovery-UZSFSS4V.js +0 -2
  378. package/dist/cli/chunks/heartbeat-scheduler-NVR356I7.js +0 -2
  379. package/dist/cli/chunks/hnsw-adapter-LFMPLUJU.js +0 -2
  380. package/dist/cli/chunks/hnsw-index-POCPMVJH.js +0 -2
  381. package/dist/cli/chunks/hybrid-backend-4STAO7CV.js +0 -2
  382. package/dist/cli/chunks/impact-analyzer-3VIIISBQ.js +0 -2
  383. package/dist/cli/chunks/init-wizard-PL6QN6RQ.js +0 -2
  384. package/dist/cli/chunks/kernel-CCDWT7KS.js +0 -2
  385. package/dist/cli/chunks/knowledge-graph-KFOMEN3H.js +0 -2
  386. package/dist/cli/chunks/llm-router-service-7NBE2EX6.js +0 -2
  387. package/dist/cli/chunks/load-test-UNZUWY3F.js +0 -2
  388. package/dist/cli/chunks/memory-backend-DFGKWA2Q.js +0 -2
  389. package/dist/cli/chunks/memory-handlers-MP426XRJ.js +0 -2
  390. package/dist/cli/chunks/pattern-null-store-SSVF5TE5.js +0 -2
  391. package/dist/cli/chunks/project-root-BEANNYWU.js +0 -2
  392. package/dist/cli/chunks/protocol-executor-FQVIHXZ7.js +0 -2
  393. package/dist/cli/chunks/qe-reasoning-bank-5TFYSE24.js +0 -2
  394. package/dist/cli/chunks/queen-coordinator-Y2OUL7IN.js +0 -2
  395. package/dist/cli/chunks/real-embeddings-OXLYU7JW.js +0 -2
  396. package/dist/cli/chunks/router-EP34O3KB.js +0 -2
  397. package/dist/cli/chunks/routing-feedback-FJCRKXNG.js +0 -2
  398. package/dist/cli/chunks/rvf-dual-writer-ILITJSFG.js +0 -2
  399. package/dist/cli/chunks/rvf-migration-adapter-XF6W4C2N.js +0 -2
  400. package/dist/cli/chunks/rvf-migration-coordinator-CMKG56AR.js +0 -2
  401. package/dist/cli/chunks/rvf-native-adapter-7YFW6S4Y.js +0 -2
  402. package/dist/cli/chunks/safe-db-TCAU4FUT.js +0 -2
  403. package/dist/cli/chunks/schedule-NB5KV435.js +0 -2
  404. package/dist/cli/chunks/scheduler-JKXGKVK6.js +0 -2
  405. package/dist/cli/chunks/sqlite-persistence-IXCNZRTW.js +0 -2
  406. package/dist/cli/chunks/sync-OSF7C2NL.js +0 -2
  407. package/dist/cli/chunks/test-SD457QJ6.js +0 -34
  408. package/dist/cli/chunks/test-runner-process-VKD65QQU.js +0 -2
  409. package/dist/cli/chunks/tree-sitter-wasm-parser-YAIPHRIL.js +0 -2
  410. package/dist/cli/chunks/unified-memory-GI76TXFV.js +0 -2
  411. package/dist/cli/chunks/unified-memory-hnsw-GXJ5BTZO.js +0 -2
  412. package/dist/cli/chunks/unified-persistence-OP7FDQPD.js +0 -2
  413. package/dist/cli/chunks/visual-security-GZ2MOKWB.js +0 -2
  414. package/dist/cli/chunks/witness-chain-P3XXXA62.js +0 -2
  415. package/dist/cli/chunks/workflow-orchestrator-P2APAJAA.js +0 -2
@@ -7,6 +7,7 @@ import { spawn } from 'node:child_process';
7
7
  import { createVitestJsonReport } from '../../../shared/vitest-json-report.js';
8
8
  import { jestExactPathPattern, nameFilterArg, runnerFilePath } from '../../../shared/test-runner-args.js';
9
9
  import { runnerCwdFor } from '../../../shared/test-runner-project.js';
10
+ import { createPytestJunitReport, isPythonTestFile, parsePytestJunitXml, pytestCommand, PYTEST_ENV, } from '../../../shared/pytest-junit-report.js';
10
11
  import { existsSync, readFileSync, realpathSync } from 'node:fs';
11
12
  import { resolve as resolvePath } from 'node:path';
12
13
  import { ok, err } from '../../../shared/types/index.js';
@@ -300,8 +301,8 @@ export class RetryHandlerService {
300
301
  // projectRoot, else a configured directory, else the file's runner
301
302
  // project. The file path stays relative to `cwd`.
302
303
  const runCwd = projectRoot ?? this.config.cwd ?? runnerCwdFor(testFile);
303
- // Detect or use configured test runner
304
- const runner = await this.detectTestRunner(runCwd);
304
+ // Detect or use configured test runner. #1248: a Python file is pytest's.
305
+ const runner = isPythonTestFile(testFile) ? 'pytest' : await this.detectTestRunner(runCwd);
305
306
  if (!runner) {
306
307
  throw new Error(`No test runner detected or configured. Install vitest, jest, or mocha, ` +
307
308
  `or configure testRunner in RetryHandlerConfig. Cannot execute retry for: ${testFile}`);
@@ -309,7 +310,7 @@ export class RetryHandlerService {
309
310
  // Build command based on runner
310
311
  const { command, args, report } = this.buildTestCommand(runner, testFile, testName, cwd);
311
312
  // Execute the test
312
- return this.spawnTestProcess(command, args, runCwd, report, runner === 'vitest' ? testFile : undefined);
313
+ return this.spawnTestProcess(command, args, runCwd, report, runner === 'vitest' ? testFile : undefined, runner === 'pytest' ? (code, reportText, output) => this.parsePytestRetry(code, reportText, output) : undefined);
313
314
  }
314
315
  /**
315
316
  * Detect which test runner is available in the project
@@ -415,6 +416,13 @@ export class RetryHandlerService {
415
416
  mochaArgs.push(nameFilterArg('mocha', testName));
416
417
  return { command: npx, args: mochaArgs };
417
418
  }
419
+ case 'pytest':
420
+ // #1248: the failed test's node id is <file>::<name> (name from the run).
421
+ {
422
+ const report = createPytestJunitReport();
423
+ const file = runnerFilePath(testFile, cwd);
424
+ return { ...pytestCommand([filterByName ? `${file}::${testName}` : file], report.path), report };
425
+ }
418
426
  default:
419
427
  throw new Error(`Unsupported test runner: ${runner}`);
420
428
  }
@@ -422,7 +430,7 @@ export class RetryHandlerService {
422
430
  /**
423
431
  * Spawn a test process and parse the result
424
432
  */
425
- spawnTestProcess(command, args, cwd, report, targetFile) {
433
+ spawnTestProcess(command, args, cwd, report, targetFile, parseReport) {
426
434
  return new Promise((resolve, reject) => {
427
435
  const timeout = this.config.testTimeout;
428
436
  let stdout = '';
@@ -439,7 +447,7 @@ export class RetryHandlerService {
439
447
  const proc = spawn(command, args, {
440
448
  cwd,
441
449
  detached: process.platform !== 'win32',
442
- env: { ...process.env, FORCE_COLOR: '0', CI: 'true' },
450
+ env: { ...process.env, FORCE_COLOR: '0', CI: 'true', ...PYTEST_ENV },
443
451
  });
444
452
  const untrackExit = trackTestRunnerExit(proc);
445
453
  const timeoutHandle = setTimeout(() => {
@@ -470,6 +478,10 @@ export class RetryHandlerService {
470
478
  // report to the --outputFile; read it back rather than trusting stdout).
471
479
  try {
472
480
  const reportText = report ? report.read(stdout) : stdout;
481
+ if (parseReport) {
482
+ settle(resolve, parseReport(code, reportText, `${stderr}\n${stdout}`.trim()));
483
+ return;
484
+ }
473
485
  if (reportText === undefined) {
474
486
  throw new Error('The current Vitest JSON report is missing for the retry run.');
475
487
  }
@@ -489,6 +501,33 @@ export class RetryHandlerService {
489
501
  });
490
502
  });
491
503
  }
504
+ /**
505
+ * #1248: a pytest retry passes only when its JUnit report shows the test
506
+ * passed. A node id pytest cannot find (exit code 4) or no collected test
507
+ * (exit code 5) reran nothing.
508
+ */
509
+ parsePytestRetry(exitCode, report, output) {
510
+ const failure = (text) => ({
511
+ passed: false,
512
+ error: redactFailureText(text || `pytest exited with code ${exitCode}`).substring(0, 1000),
513
+ });
514
+ if (exitCode === 4 || exitCode === 5)
515
+ return UNMATCHED;
516
+ if (report === undefined)
517
+ return failure(output);
518
+ try {
519
+ const cases = parsePytestJunitXml(report);
520
+ if (cases.length === 0)
521
+ return UNMATCHED;
522
+ const failed = cases.find(c => c.status === 'failed' || c.status === 'error');
523
+ if (exitCode === 0 && !failed && cases.some(c => c.status === 'passed'))
524
+ return { passed: true };
525
+ return failure(failed ? [failed.message, failed.details].filter(Boolean).join('\n') : output);
526
+ }
527
+ catch {
528
+ return failure(output);
529
+ }
530
+ }
492
531
  /**
493
532
  * Parse test runner output to determine pass/fail status
494
533
  */
@@ -6,6 +6,8 @@
6
6
  * derived from aggregate counts.
7
7
  */
8
8
  import type { ITestCaseResult } from '../interfaces';
9
+ /** A test case's failure text: redacted (#1122) and capped. */
10
+ export declare function testCaseFailureMessage(text: string): string | undefined;
9
11
  /**
10
12
  * #1122: failure text goes back over MCP and into saved results, so
11
13
  * credential-shaped values (e.g. a connection string) are redacted first.
@@ -12,10 +12,14 @@ const MAX_FAILURE_MESSAGE_LENGTH = 4000;
12
12
  function failureMessageOf(assertion) {
13
13
  if (!Array.isArray(assertion.failureMessages))
14
14
  return undefined;
15
- const joined = assertion.failureMessages.filter((m) => typeof m === 'string').join('\n').trim();
16
- if (!joined)
15
+ return testCaseFailureMessage(assertion.failureMessages.filter((m) => typeof m === 'string').join('\n'));
16
+ }
17
+ /** A test case's failure text: redacted (#1122) and capped. */
18
+ export function testCaseFailureMessage(text) {
19
+ const trimmed = text.trim();
20
+ if (!trimmed)
17
21
  return undefined;
18
- const message = redactFailureText(joined);
22
+ const message = redactFailureText(trimmed);
19
23
  return message.length > MAX_FAILURE_MESSAGE_LENGTH
20
24
  ? `${message.slice(0, MAX_FAILURE_MESSAGE_LENGTH)}… [truncated]`
21
25
  : message;
@@ -115,7 +115,7 @@ export declare class TestExecutorService implements ITestExecutionService {
115
115
  private executeTestFiles;
116
116
  private executeProjectFiles;
117
117
  /**
118
- * Spawn actual test runner process (vitest, jest, mocha)
118
+ * Spawn actual test runner process (vitest, jest, mocha, node:test, pytest)
119
119
  */
120
120
  private spawnTestRunner;
121
121
  /**
@@ -126,6 +126,10 @@ export declare class TestExecutorService implements ITestExecutionService {
126
126
  * Parse test runner output to extract results
127
127
  */
128
128
  private parseTestOutput;
129
+ /**
130
+ * #1248: a pytest run from its JUnit report (undefined when pytest wrote none).
131
+ */
132
+ private parsePytestOutput;
129
133
  /**
130
134
  * Parse the TAP or spec summary emitted by Node's built-in test runner.
131
135
  */
@@ -17,11 +17,12 @@ import { secureRandom, secureRandomInt } from '../../../shared/utils/crypto-rand
17
17
  import { writeTestRunEvidence } from '../../quality-assessment/quality-evidence.js';
18
18
  import { istanbulLineHits } from '../../../coordination/handlers/handler-utils.js';
19
19
  import { fileCoverageKey, projectFileCoverageKeys } from '../../coverage-analysis/collected-metrics.js';
20
- import { mergeTestCases, redactFailedTests, redactFailureText, testCasesFromRunnerReport } from './runner-test-cases.js';
20
+ import { mergeTestCases, redactFailedTests, redactFailureText, testCaseFailureMessage, testCasesFromRunnerReport } from './runner-test-cases.js';
21
21
  import { capDiagnostics, getTestRunnerExecutionError, TestRunnerExecutionError } from '../../../shared/test-runner-verdict.js';
22
22
  import { createVitestJsonReport } from '../../../shared/vitest-json-report.js';
23
+ import { createPytestJunitReport, isPythonTestFile, pytestCommand, pytestRunFromReport, PYTEST_ENV } from '../../../shared/pytest-junit-report.js';
23
24
  import { jestExactPathPattern, runnerFilePath } from '../../../shared/test-runner-args.js';
24
- import { groupByRunnerProject } from '../../../shared/test-runner-project.js';
25
+ import { groupByRunnerProject, runnerFrameworkFor } from '../../../shared/test-runner-project.js';
25
26
  import { getClaudeModelForTier } from '../../../shared/llm/model-registry.js';
26
27
  import { terminateTestRunner, trackTestRunnerExit } from '../../../shared/test-runner-process.js';
27
28
  const DEFAULT_CONFIG = {
@@ -315,7 +316,7 @@ Provide:
315
316
  return ok(undefined);
316
317
  }
317
318
  async runTests(request) {
318
- const { testFiles, framework, timeout = 30000, projectRoot } = request;
319
+ const { testFiles, framework, timeout = 30000, projectRoot, frameworkFromConfig } = request;
319
320
  const failedTests = [];
320
321
  const coverages = [];
321
322
  const allFileCoverages = [];
@@ -324,7 +325,7 @@ Provide:
324
325
  let failed = 0;
325
326
  let skipped = 0;
326
327
  for (const file of testFiles) {
327
- const result = await this.executeTestFile(file, framework, timeout, projectRoot);
328
+ const result = await this.executeTestFile(file, framework, timeout, projectRoot, frameworkFromConfig);
328
329
  executionResults.push(result);
329
330
  passed += result.passed;
330
331
  failed += result.failed;
@@ -394,25 +395,40 @@ Provide:
394
395
  const coverage = this.extractCoverageFromJson({ coverageMap: merged });
395
396
  return coverage.summary ? { summary: coverage.summary, perFile: coverage.perFile } : undefined;
396
397
  }
397
- async executeTestFile(file, framework, timeout, projectRoot) {
398
- return this.executeTestFiles([file], framework, timeout, projectRoot);
398
+ async executeTestFile(file, framework, timeout, projectRoot, frameworkFromConfig = false) {
399
+ return this.executeTestFiles([file], framework, timeout, projectRoot, frameworkFromConfig);
399
400
  }
400
- async executeTestFiles(files, framework, timeout, projectRoot) {
401
+ async executeTestFiles(files, framework, timeout, projectRoot, frameworkFromConfig = false) {
401
402
  // In simulation mode (for unit testing), use random behavior
402
403
  if (this.config.simulateForTesting) {
403
404
  return this.aggregateResults(files.map(file => this.simulateTestExecution(file)));
404
405
  }
405
406
  // #1247: a runner loads the config of the directory it starts in, so each
406
407
  // file runs from its own runner project (or the caller's projectRoot).
408
+ // #1248: Python files run apart from the others, with pytest.
407
409
  const groups = projectRoot
408
- ? [{ cwd: projectRoot, files }]
410
+ ? [files.filter(isPythonTestFile), files.filter(file => !isPythonTestFile(file))]
411
+ .filter(group => group.length > 0)
412
+ .map(group => ({ cwd: projectRoot, files: group }))
409
413
  : groupByRunnerProject(files);
414
+ // #1272: an explicit framework wins; otherwise the project's config decides.
415
+ // #1248: Python files run with pytest, never with a JavaScript runner.
416
+ const frameworkIn = (group) => {
417
+ if (group.files.some(isPythonTestFile)) {
418
+ if (frameworkFromConfig || framework.toLowerCase() === 'pytest')
419
+ return 'pytest';
420
+ throw new TestRunnerExecutionError(`Python test files cannot run with ${framework}: ${group.files.filter(isPythonTestFile).join(', ')}. ` +
421
+ `Use framework 'pytest', or leave the framework unset.`);
422
+ }
423
+ return (frameworkFromConfig ? runnerFrameworkFor(group.cwd) : undefined) ?? framework;
424
+ };
410
425
  if (groups.length === 1) {
411
- return this.executeProjectFiles(groups[0].files, framework, timeout, groups[0].cwd);
426
+ return this.executeProjectFiles(groups[0].files, frameworkIn(groups[0]), timeout, groups[0].cwd);
412
427
  }
413
428
  // Each project gets its own runner and timeout. Their coverage maps are
414
429
  // merged from raw counters, or left unmeasured (#1030).
415
- const results = await Promise.all(groups.map(group => this.executeProjectFiles(group.files, framework, timeout, group.cwd)));
430
+ const frameworks = groups.map(frameworkIn);
431
+ const results = await Promise.all(groups.map((group, index) => this.executeProjectFiles(group.files, frameworks[index], timeout, group.cwd)));
416
432
  const combined = this.aggregateResults(results);
417
433
  const merged = this.mergeSequentialCoverage(results);
418
434
  combined.coverage = merged?.summary;
@@ -445,7 +461,7 @@ Provide:
445
461
  return result.value;
446
462
  }
447
463
  /**
448
- * Spawn actual test runner process (vitest, jest, mocha)
464
+ * Spawn actual test runner process (vitest, jest, mocha, node:test, pytest)
449
465
  */
450
466
  async spawnTestRunner(files, framework, timeout, cwd = process.cwd()) {
451
467
  // Verify test file exists
@@ -490,6 +506,7 @@ Provide:
490
506
  env: {
491
507
  ...process.env,
492
508
  FORCE_COLOR: '0', // Disable color codes for easier parsing
509
+ ...PYTEST_ENV, // pytest reads any FORCE_COLOR as "force colour" (#1248)
493
510
  CI: 'true', // Enable CI mode for consistent output
494
511
  },
495
512
  });
@@ -534,11 +551,15 @@ Provide:
534
551
  finish(err(toError(error)));
535
552
  return;
536
553
  }
537
- if (reportText === undefined) {
554
+ // #1248: pytest reports its own missing report (pytest not installed).
555
+ const pytest = framework.toLowerCase() === 'pytest';
556
+ if (reportText === undefined && !pytest) {
538
557
  finish(err(new TestRunnerExecutionError(`The current Vitest JSON report is missing for ${fileLabel}.`)));
539
558
  return;
540
559
  }
541
- const parseResult = this.parseTestOutput(reportText, stderr, fileLabel, framework, code);
560
+ const parseResult = pytest
561
+ ? this.parsePytestOutput(reportText, `${stderr}\n${stdout}`, files, code, command)
562
+ : this.parseTestOutput(reportText ?? '', stderr, fileLabel, framework, code);
542
563
  // Read only this invocation's coverage artifacts. A previous or
543
564
  // concurrent run's project coverage directory is not evidence.
544
565
  if (parseResult.success && coverageDirectory) {
@@ -611,8 +632,14 @@ Provide:
611
632
  command: process.execPath,
612
633
  args: ['--test', ...files],
613
634
  };
635
+ case 'pytest': {
636
+ // #1248: results come from the JUnit report file; no coverage is collected.
637
+ const report = createPytestJunitReport();
638
+ return { ...pytestCommand(files, report.path), report };
639
+ }
614
640
  default: {
615
- // Default to vitest
641
+ // Default to vitest. Python files never get here: executeTestFiles
642
+ // sends them to pytest or refuses the run (#1248).
616
643
  const coverageDirectory = createCoverageDirectory();
617
644
  let report;
618
645
  try {
@@ -655,6 +682,43 @@ Provide:
655
682
  `stdout: ${capDiagnostics(stdout, 500)}\nstderr: ${capDiagnostics(stderr, 500)}`));
656
683
  }
657
684
  }
685
+ /**
686
+ * #1248: a pytest run from its JUnit report (undefined when pytest wrote none).
687
+ */
688
+ parsePytestOutput(report, output, files, exitCode, python) {
689
+ const run = pytestRunFromReport(report, files, exitCode, output, python);
690
+ if (!run.success)
691
+ return run;
692
+ const failedTests = run.value.tests
693
+ .filter(test => test.status === 'failed')
694
+ .map(test => ({
695
+ testId: uuidv4(),
696
+ testName: test.name,
697
+ file: test.file,
698
+ error: test.failureMessage ?? 'Test failed',
699
+ stack: test.failureMessage ?? '',
700
+ duration: test.duration ?? 0,
701
+ }));
702
+ const testCases = run.value.tests.map(test => {
703
+ const failureMessage = test.failureMessage && testCaseFailureMessage(test.failureMessage);
704
+ return {
705
+ name: test.name,
706
+ file: test.file,
707
+ status: test.status,
708
+ ...(test.duration !== undefined ? { duration: test.duration } : {}),
709
+ ...(failureMessage ? { failureMessage } : {}),
710
+ };
711
+ });
712
+ return ok({
713
+ total: run.value.total,
714
+ passed: run.value.passed,
715
+ failed: run.value.failed,
716
+ skipped: run.value.skipped,
717
+ failedTests,
718
+ testCases,
719
+ coverage: undefined,
720
+ });
721
+ }
658
722
  /**
659
723
  * Parse the TAP or spec summary emitted by Node's built-in test runner.
660
724
  */
@@ -1018,7 +1082,7 @@ Provide:
1018
1082
  return shards;
1019
1083
  }
1020
1084
  async executeWorker(files, _workerIndex, _isolation, request) {
1021
- return this.executeTestFiles(files, request.framework, request.timeout ?? 30000, request.projectRoot);
1085
+ return this.executeTestFiles(files, request.framework, request.timeout ?? 30000, request.projectRoot, request.frameworkFromConfig);
1022
1086
  }
1023
1087
  aggregateResults(results) {
1024
1088
  const aggregated = {
@@ -29,6 +29,12 @@ export declare class CopilotInstaller {
29
29
  private generator;
30
30
  constructor(options: CopilotInstallerOptions);
31
31
  install(): Promise<CopilotInstallResult>;
32
+ /**
33
+ * Replace AQE's server entry in an existing config, keeping everything else.
34
+ * Returns null when the file cannot be merged safely (e.g. JSONC comments,
35
+ * which VS Code accepts but JSON.parse does not) so the user's file is never
36
+ * clobbered wholesale.
37
+ */
32
38
  private mergeExistingConfig;
33
39
  }
34
40
  export declare function createCopilotInstaller(options: CopilotInstallerOptions): CopilotInstaller;
@@ -8,6 +8,7 @@
8
8
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
9
9
  import { join, dirname } from 'path';
10
10
  import { toErrorMessage } from '../shared/error-utils.js';
11
+ import { writeFileIfChanged } from './idempotent-write.js';
11
12
  import { createPlatformConfigGenerator, } from './platform-config-generator.js';
12
13
  // ============================================================================
13
14
  // Copilot Installer Class
@@ -37,20 +38,28 @@ export class CopilotInstaller {
37
38
  const mcpConfig = this.generator.generateMcpConfig('copilot', { memoryBackend: this.options.memoryBackend });
38
39
  const configPath = join(this.projectRoot, mcpConfig.path);
39
40
  result.configPath = configPath;
40
- if (!existsSync(configPath) || this.overwrite) {
41
+ // AQE's own server entry is refreshed on every init, independent of
42
+ // `overwrite` (#1269): its launch config is version-pinned, and a stale one
43
+ // leaves VS Code serving tool schemas cached from an older server. Other
44
+ // servers and top-level keys in the file are preserved.
45
+ if (!existsSync(configPath)) {
41
46
  const configDir = dirname(configPath);
42
47
  if (!existsSync(configDir)) {
43
48
  mkdirSync(configDir, { recursive: true });
44
49
  }
45
- // Merge with existing if present
46
- if (existsSync(configPath) && this.overwrite) {
47
- const merged = this.mergeExistingConfig(configPath, mcpConfig.content);
48
- writeFileSync(configPath, merged);
50
+ writeFileSync(configPath, mcpConfig.content);
51
+ result.mcpConfigured = true;
52
+ }
53
+ else {
54
+ const merged = this.mergeExistingConfig(configPath, mcpConfig.content);
55
+ if (merged === null) {
56
+ result.errors.push(`${configPath} is not plain JSON (comments?) and was left unchanged; ` +
57
+ `update its "agentic-qe" server entry by hand`);
49
58
  }
50
59
  else {
51
- writeFileSync(configPath, mcpConfig.content);
60
+ writeFileIfChanged(configPath, merged);
61
+ result.mcpConfigured = true;
52
62
  }
53
- result.mcpConfigured = true;
54
63
  }
55
64
  // Generate behavioral rules
56
65
  const rules = this.generator.generateBehavioralRules('copilot');
@@ -71,23 +80,34 @@ export class CopilotInstaller {
71
80
  }
72
81
  return result;
73
82
  }
83
+ /**
84
+ * Replace AQE's server entry in an existing config, keeping everything else.
85
+ * Returns null when the file cannot be merged safely (e.g. JSONC comments,
86
+ * which VS Code accepts but JSON.parse does not) so the user's file is never
87
+ * clobbered wholesale.
88
+ */
74
89
  mergeExistingConfig(configPath, newContent) {
90
+ let existing;
75
91
  try {
76
- const existing = JSON.parse(readFileSync(configPath, 'utf-8'));
77
- const incoming = JSON.parse(newContent);
78
- // Merge servers
79
- if (!existing.servers) {
80
- existing.servers = {};
81
- }
82
- Object.assign(existing.servers, incoming.servers);
83
- return JSON.stringify(existing, null, 2) + '\n';
92
+ existing = JSON.parse(readFileSync(configPath, 'utf-8'));
84
93
  }
85
94
  catch {
86
- // If existing config is invalid, overwrite
87
- return newContent;
95
+ return null;
88
96
  }
97
+ if (!isPlainObject(existing))
98
+ return null;
99
+ if (existing.servers === undefined)
100
+ existing.servers = {};
101
+ if (!isPlainObject(existing.servers))
102
+ return null;
103
+ const incoming = JSON.parse(newContent);
104
+ Object.assign(existing.servers, incoming.servers);
105
+ return JSON.stringify(existing, null, 2) + '\n';
89
106
  }
90
107
  }
108
+ function isPlainObject(value) {
109
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
110
+ }
91
111
  // ============================================================================
92
112
  // Factory Function
93
113
  // ============================================================================
@@ -23,6 +23,16 @@ export interface GeneratedConfig {
23
23
  format: string;
24
24
  }
25
25
  export declare const PLATFORM_REGISTRY: Record<PlatformId, PlatformDefinition>;
26
+ /**
27
+ * Issue #1269: VS Code caches each MCP server's tool list keyed by a hash of its
28
+ * launch config (command/args/env) and only restarts the server when that hash
29
+ * changes. The `agentic-qe@latest` entry is identical across releases, so tool
30
+ * schemas cached from an older server (the pre-#1185 "array type must have items"
31
+ * ones) survived upgrades. Stamping the installing version into the Copilot
32
+ * entry's env changes the hash whenever `aqe init` runs after an upgrade, without
33
+ * pinning which server version npx launches. The server does not read it.
34
+ */
35
+ export declare function getCopilotInitVersionEnv(): Record<string, string>;
26
36
  export declare class PlatformConfigGenerator {
27
37
  /**
28
38
  * Get the platform definition for a given platform ID
@@ -4,6 +4,7 @@
4
4
  *
5
5
  * Supports: GitHub Copilot, Cursor, Cline, Kilo Code, Roo Code, OpenAI Codex, Windsurf, Continue.dev
6
6
  */
7
+ import { createRequire } from 'module';
7
8
  // ============================================================================
8
9
  // Platform Registry
9
10
  // ============================================================================
@@ -146,6 +147,29 @@ function getMcpServerEnv(dbFree) {
146
147
  ? { AQE_MEMORY_BACKEND: 'memory', AQE_V3_MODE: 'true' }
147
148
  : { AQE_MEMORY_PATH: '.agentic-qe/memory.db', AQE_V3_MODE: 'true' };
148
149
  }
150
+ /**
151
+ * Installed AQE version: the build-time define in the CLI/MCP bundles, otherwise
152
+ * package.json (tsc output and tests). Both src/init/ and dist/cli/ sit two levels
153
+ * below the package root.
154
+ */
155
+ function getInstalledAqeVersion() {
156
+ if (typeof __CLI_VERSION__ !== 'undefined')
157
+ return __CLI_VERSION__;
158
+ const pkg = createRequire(import.meta.url)('../../package.json');
159
+ return pkg.version;
160
+ }
161
+ /**
162
+ * Issue #1269: VS Code caches each MCP server's tool list keyed by a hash of its
163
+ * launch config (command/args/env) and only restarts the server when that hash
164
+ * changes. The `agentic-qe@latest` entry is identical across releases, so tool
165
+ * schemas cached from an older server (the pre-#1185 "array type must have items"
166
+ * ones) survived upgrades. Stamping the installing version into the Copilot
167
+ * entry's env changes the hash whenever `aqe init` runs after an upgrade, without
168
+ * pinning which server version npx launches. The server does not read it.
169
+ */
170
+ export function getCopilotInitVersionEnv() {
171
+ return { AQE_INIT_VERSION: getInstalledAqeVersion() };
172
+ }
149
173
  function getMcpServerEntry(withAutoApprove, dbFree) {
150
174
  const entry = {
151
175
  command: 'npx',
@@ -164,12 +188,13 @@ function getMcpServerEntry(withAutoApprove, dbFree) {
164
188
  function generateJsonConfig(platform, dbFree) {
165
189
  const serverEntry = getMcpServerEntry(platform.supportsAutoApprove, dbFree);
166
190
  if (platform.id === 'copilot') {
167
- // Copilot uses "servers" key with "type": "stdio"
191
+ // Copilot uses "servers" key with "type": "stdio"; env carries the init version stamp (#1269)
168
192
  const config = {
169
193
  [platform.configKey]: {
170
194
  'agentic-qe': {
171
195
  type: 'stdio',
172
196
  ...serverEntry,
197
+ env: { ...serverEntry.env, ...getCopilotInitVersionEnv() },
173
198
  },
174
199
  },
175
200
  };
@@ -82,6 +82,8 @@ export declare class UnifiedMemoryManager {
82
82
  private constructor();
83
83
  static getInstance(config?: Partial<UnifiedMemoryConfig>): UnifiedMemoryManager;
84
84
  static getInstanceAsync(config?: Partial<UnifiedMemoryConfig>): Promise<UnifiedMemoryManager>;
85
+ /** The shared instance when it is initialized; never creates one. */
86
+ static peekInitialized(): UnifiedMemoryManager | null;
85
87
  static resetInstance(): void;
86
88
  initialize(options?: {
87
89
  signal?: AbortSignal;
@@ -227,6 +229,12 @@ export declare class UnifiedMemoryManager {
227
229
  }
228
230
  export declare function getUnifiedMemory(config?: Partial<UnifiedMemoryConfig>): UnifiedMemoryManager;
229
231
  export declare function initializeUnifiedMemory(config?: Partial<UnifiedMemoryConfig>): Promise<UnifiedMemoryManager>;
232
+ /**
233
+ * The shared memory.db connection when UnifiedMemory is already initialized,
234
+ * else null. Never opens it: callers that run before it keep their
235
+ * no-database behavior (#1298).
236
+ */
237
+ export declare function getOpenUnifiedMemoryDatabase(): DatabaseType | null;
230
238
  export declare function resetUnifiedMemory(): void;
231
239
  /**
232
240
  * Run a write on `db` through the shared manager's writeWhenUnlocked queue
@@ -174,6 +174,11 @@ export class UnifiedMemoryManager {
174
174
  }
175
175
  return UnifiedMemoryManager.instancePromise;
176
176
  }
177
+ /** The shared instance when it is initialized; never creates one. */
178
+ static peekInitialized() {
179
+ const instance = UnifiedMemoryManager.instance;
180
+ return instance?.initialized ? instance : null;
181
+ }
177
182
  static resetInstance() {
178
183
  if (UnifiedMemoryManager.instance) {
179
184
  UnifiedMemoryManager.instance.close();
@@ -1118,6 +1123,14 @@ export async function initializeUnifiedMemory(config) {
1118
1123
  await manager.initialize();
1119
1124
  return manager;
1120
1125
  }
1126
+ /**
1127
+ * The shared memory.db connection when UnifiedMemory is already initialized,
1128
+ * else null. Never opens it: callers that run before it keep their
1129
+ * no-database behavior (#1298).
1130
+ */
1131
+ export function getOpenUnifiedMemoryDatabase() {
1132
+ return UnifiedMemoryManager.peekInitialized()?.getDatabase() ?? null;
1133
+ }
1121
1134
  export function resetUnifiedMemory() {
1122
1135
  UnifiedMemoryManager.resetInstance();
1123
1136
  }
@@ -15,6 +15,8 @@
15
15
  * - Bearer auth from env only; URL userinfo stripped + warned on construct.
16
16
  * - Probe + identity fingerprint required before `embed()`; breaker recovery
17
17
  * invalidates identity so re-probe runs against a fresh endpoint.
18
+ * - The first identity is bound for the client's lifetime: a re-probe that
19
+ * finds another model is refused, never adopted (#1282).
18
20
  * - True TCP connect timeout via socket-level setTimeout (not req.setTimeout).
19
21
  * - TLS knobs (ca / cert / key / rejectUnauthorized / servername) for self-hosted.
20
22
  */
@@ -64,6 +66,8 @@ export interface EmbedderEndpointClientOptions {
64
66
  /** TLS overrides for https transport. Ignored for http/unix. */
65
67
  tlsOptions?: EmbedderTlsOptions;
66
68
  }
69
+ /** The text every probe embeds; its vector is the endpoint's identity evidence. */
70
+ export declare const ENDPOINT_IDENTITY_CANARY = "AQE embedder endpoint identity canary v1";
67
71
  /**
68
72
  * Parsed endpoint — either an HTTP(S) URL or a Unix socket path.
69
73
  */
@@ -92,6 +96,17 @@ export declare class EmbedderEndpointTimeoutError extends Error {
92
96
  readonly limitMs: number;
93
97
  constructor(phase: 'connect' | 'request', limitMs: number);
94
98
  }
99
+ /**
100
+ * #1282: a probe found a different endpoint identity than the one the client
101
+ * bound to. Vectors from the new identity are not comparable with stored ones,
102
+ * so the client refuses to embed until the endpoint serves the bound identity
103
+ * again or the process restarts.
104
+ */
105
+ export declare class EmbedderEndpointIdentityChangedError extends Error {
106
+ readonly bound: EndpointIdentity;
107
+ readonly current: EndpointIdentity;
108
+ constructor(bound: EndpointIdentity, current: EndpointIdentity);
109
+ }
95
110
  /**
96
111
  * OpenAI-compatible embeddings client with keep-alive, circuit breaker, and identity probe.
97
112
  */
@@ -101,6 +116,15 @@ export declare class EmbedderEndpointClient {
101
116
  private readonly breaker;
102
117
  private readonly opts;
103
118
  private cachedIdentity;
119
+ /**
120
+ * #1282: the first identity a probe found. Every embedding this client
121
+ * returns belongs to it; later probes must find it again.
122
+ */
123
+ private boundIdentity;
124
+ /** #1282: the canary vector behind `boundIdentity`. */
125
+ private boundCanary;
126
+ /** #1282: set while the endpoint serves an identity other than the bound one. */
127
+ private identityChange;
104
128
  /** True while a probe is in flight — prevents the embed() lazy-probe race. */
105
129
  private probeInFlight;
106
130
  /**
@@ -146,7 +170,28 @@ export declare class EmbedderEndpointClient {
146
170
  probe(): Promise<EndpointIdentity>;
147
171
  private ensureProbed;
148
172
  private doProbe;
173
+ /**
174
+ * #1282: true when a re-probe found the bound model. The int16 fingerprint
175
+ * flips on noise of about 3e-5 per component, which the same model restarted
176
+ * on other hardware or kernels can produce, so a changed hash alone is not a
177
+ * changed model: the canary must also have moved below the ADR-097
178
+ * round-trip cosine.
179
+ */
180
+ private isBoundModel;
181
+ /**
182
+ * #1282: the endpoint answers, but as a different model than the one this
183
+ * client bound to (an endpoint restarted with another model of the same
184
+ * dimension, typically seen when the breaker recovers). Treat it as down:
185
+ * open the breaker so every caller fast-fails with this error, and retry
186
+ * as a half-open trial after each window, in case the bound model returns.
187
+ * Reported once per new identity.
188
+ */
189
+ private refuseIdentityChange;
149
190
  getCachedIdentity(): EndpointIdentity | null;
191
+ /** #1282: the identity every vector from this client belongs to. */
192
+ getBoundIdentity(): EndpointIdentity | null;
193
+ /** #1298: the canary vector behind the bound identity (ENDPOINT_IDENTITY_CANARY). */
194
+ getBoundCanary(): readonly number[] | null;
150
195
  getBreakerState(): {
151
196
  open: boolean;
152
197
  failures: number;