agentic-qe 3.15.1 → 3.15.3

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 (447) hide show
  1. package/.claude/helpers/brain-checkpoint.cjs +46 -6
  2. package/.claude/hooks/aqe-hook.cjs +280 -51
  3. package/.claude/skills/skills-manifest.json +1 -1
  4. package/CHANGELOG.md +129 -0
  5. package/assets/skills/skills-manifest.json +1 -1
  6. package/dist/adapters/ag-ui/state-delta-cache.js +14 -5
  7. package/dist/adapters/trajectory-adapter.js +3 -1
  8. package/dist/cli/bundle.js +5 -5
  9. package/dist/cli/chunks/adapter-WQSFQES5.js +2 -0
  10. package/dist/cli/chunks/{agent-booster-wasm-XUHRLKWP.js → agent-booster-wasm-CYG3PKHH.js} +2 -2
  11. package/dist/cli/chunks/{agent-handler-CL7MJP5W.js → agent-handler-WTFYFZKL.js} +2 -2
  12. package/dist/cli/chunks/{agent-memory-branch-F7RV72FC.js → agent-memory-branch-G6WE3ZXU.js} +2 -2
  13. package/dist/cli/chunks/aqe-learning-engine-TDHBBADE.js +2 -0
  14. package/dist/cli/chunks/{arena-GRRNK7IN.js → arena-S72QW44C.js} +4 -4
  15. package/dist/cli/chunks/{arena-LHLVOQHW.js → arena-ZFXQEVUQ.js} +2 -2
  16. package/dist/cli/chunks/{audit-EOP2K34L.js → audit-KPYIEQJ3.js} +3 -3
  17. package/dist/cli/chunks/base-CZSB27VO.js +2 -0
  18. package/dist/cli/chunks/{better-sqlite3-YERQ5DOL.js → better-sqlite3-L2M3TI5D.js} +2 -2
  19. package/dist/cli/chunks/{brain-handler-FBXBM5XE.js → brain-handler-FHKLQTB4.js} +3 -3
  20. package/dist/cli/chunks/{branch-enumerator-NWO6LNHB.js → branch-enumerator-3BSHOPOK.js} +2 -2
  21. package/dist/cli/chunks/{browser-EDCG7TNF.js → browser-JUIJPL6Y.js} +2 -2
  22. package/dist/cli/chunks/browser-workflow-AEMIS6PA.js +2 -0
  23. package/dist/cli/chunks/{chunk-ARWSPV2C.js → chunk-2GJJGO5D.js} +2 -2
  24. package/dist/cli/chunks/{chunk-SUFXUM6W.js → chunk-2M75CW5Q.js} +2 -2
  25. package/dist/cli/chunks/{chunk-ZX4I7IND.js → chunk-2MEWIXW4.js} +2 -2
  26. package/dist/cli/chunks/{chunk-VEKRK3R6.js → chunk-2TBHPYOU.js} +2 -2
  27. package/dist/cli/chunks/{chunk-OH4SKOAM.js → chunk-34Y4CIHD.js} +2 -2
  28. package/dist/cli/chunks/{chunk-JY6HWYC4.js → chunk-35VDOH4Y.js} +1 -1
  29. package/dist/cli/chunks/{chunk-NK2BR4QZ.js → chunk-366IBPZB.js} +2 -2
  30. package/dist/cli/chunks/{chunk-PZBYZV5M.js → chunk-3MNKYCLH.js} +1 -1
  31. package/dist/cli/chunks/chunk-3UUMGWHW.js +316 -0
  32. package/dist/cli/chunks/{chunk-REGPCPEJ.js → chunk-3Y4GX5FL.js} +2 -2
  33. package/dist/cli/chunks/{chunk-PGARKOE6.js → chunk-3ZTBV6M3.js} +1 -1
  34. package/dist/cli/chunks/{chunk-GUHJWBPN.js → chunk-4IYHYHTG.js} +2 -2
  35. package/dist/cli/chunks/{chunk-J2WALRWR.js → chunk-4JVVVKAX.js} +6 -6
  36. package/dist/cli/chunks/chunk-4N7YXTV3.js +4 -0
  37. package/dist/cli/chunks/{chunk-YM3GAJMN.js → chunk-4TM5K6EZ.js} +2 -2
  38. package/dist/cli/chunks/{chunk-IUGY6Z4Q.js → chunk-5LEUEWJY.js} +2 -2
  39. package/dist/cli/chunks/{chunk-Q7ONRZBD.js → chunk-5QUOM357.js} +1 -1
  40. package/dist/cli/chunks/{chunk-5B5TA3X4.js → chunk-5WOBFN2T.js} +2 -2
  41. package/dist/cli/chunks/{chunk-JEXPSOT2.js → chunk-6AKJ73X3.js} +2 -2
  42. package/dist/cli/chunks/{chunk-K4NB3MYN.js → chunk-6EQDA4EC.js} +2 -2
  43. package/dist/cli/chunks/{chunk-HU4QGCIJ.js → chunk-6TYTBQPV.js} +2 -2
  44. package/dist/cli/chunks/{chunk-RXKOZ6VS.js → chunk-6V6XVGCL.js} +3 -3
  45. package/dist/cli/chunks/{chunk-4KHSWNFW.js → chunk-6W6GZHQA.js} +6 -6
  46. package/dist/cli/chunks/{chunk-WTFVYFRZ.js → chunk-7IJVCDDC.js} +1 -1
  47. package/dist/cli/chunks/{chunk-T5K6ZCA6.js → chunk-7PDC4SKR.js} +1 -1
  48. package/dist/cli/chunks/{chunk-NF6SLLE6.js → chunk-7SWHW5AC.js} +20 -20
  49. package/dist/cli/chunks/{chunk-UE33MZOC.js → chunk-7TW5UGDP.js} +2 -2
  50. package/dist/cli/chunks/{chunk-4AEFJEZH.js → chunk-7UUSV2SK.js} +1 -1
  51. package/dist/cli/chunks/{chunk-WONHFDWF.js → chunk-A3IQU2ND.js} +2 -2
  52. package/dist/cli/chunks/{chunk-ALLABEUK.js → chunk-A5H7TF7C.js} +2 -2
  53. package/dist/cli/chunks/{chunk-C3BW3Q27.js → chunk-A6PII4R4.js} +1 -1
  54. package/dist/cli/chunks/{chunk-ZE6WJDXM.js → chunk-AEL4XJGJ.js} +2 -2
  55. package/dist/cli/chunks/{chunk-5QEXDXHQ.js → chunk-AOZJ6UUZ.js} +2 -2
  56. package/dist/cli/chunks/chunk-APV5UWTU.js +15 -0
  57. package/dist/cli/chunks/{chunk-YWX7KLNG.js → chunk-AQTQ24SK.js} +3 -3
  58. package/dist/cli/chunks/{chunk-PBWR2SKH.js → chunk-AS54N3H7.js} +2 -2
  59. package/dist/cli/chunks/chunk-ASUXS4N4.js +2 -0
  60. package/dist/cli/chunks/{chunk-JSHASVQ2.js → chunk-B23ROYST.js} +3 -3
  61. package/dist/cli/chunks/{chunk-NTLWHLAY.js → chunk-BDKQSEEY.js} +1 -1
  62. package/dist/cli/chunks/{chunk-VLL7ASGH.js → chunk-BO43BGHX.js} +2 -2
  63. package/dist/cli/chunks/{chunk-KP6LNSDO.js → chunk-CF3BPD2R.js} +161 -159
  64. package/dist/cli/chunks/{chunk-KTBA2HJC.js → chunk-CFXROOIU.js} +2 -2
  65. package/dist/cli/chunks/{chunk-SRXXPZVT.js → chunk-CNQUU6CF.js} +2 -2
  66. package/dist/cli/chunks/{chunk-OKS25EGZ.js → chunk-D5V6C3XG.js} +3 -3
  67. package/dist/cli/chunks/{chunk-ADEYBXAS.js → chunk-D6PUDLJ4.js} +2 -2
  68. package/dist/cli/chunks/{chunk-D3LREV4P.js → chunk-DE3QNPTG.js} +1 -1
  69. package/dist/cli/chunks/{chunk-TJCMG3QE.js → chunk-DH5NWHH2.js} +2 -2
  70. package/dist/cli/chunks/{chunk-GDSYJHVB.js → chunk-DLA3EHKJ.js} +1 -1
  71. package/dist/cli/chunks/{chunk-VGYLV6VD.js → chunk-DWG4TN6A.js} +1 -1
  72. package/dist/cli/chunks/{chunk-4KSCJ462.js → chunk-EBIMVSPH.js} +4 -4
  73. package/dist/cli/chunks/{chunk-4XEZ562Q.js → chunk-ED5HUPUR.js} +2 -2
  74. package/dist/cli/chunks/{chunk-CHX65QXY.js → chunk-EQGT4VLC.js} +1 -1
  75. package/dist/cli/chunks/{chunk-WFDDWRWY.js → chunk-F5BREV2Q.js} +8 -8
  76. package/dist/cli/chunks/{chunk-7FGSX4UD.js → chunk-FPFGN2Z5.js} +2 -2
  77. package/dist/cli/chunks/{chunk-3TZRJ5QD.js → chunk-FTUNC4EI.js} +3 -3
  78. package/dist/cli/chunks/chunk-FXTZXZCU.js +54 -0
  79. package/dist/cli/chunks/{chunk-DREYYJ7A.js → chunk-GJB3LPCS.js} +2 -2
  80. package/dist/cli/chunks/{chunk-4P7CGSRL.js → chunk-GPZH6OPP.js} +4 -4
  81. package/dist/cli/chunks/{chunk-NWNZMXNO.js → chunk-HR7RL4PB.js} +2 -2
  82. package/dist/cli/chunks/{chunk-NGDRSF6Y.js → chunk-HSR53REE.js} +2 -2
  83. package/dist/cli/chunks/{chunk-UOHZRR5C.js → chunk-HU474NXP.js} +1 -1
  84. package/dist/cli/chunks/{chunk-LI7N45GM.js → chunk-HV3ZVUHO.js} +1 -1
  85. package/dist/cli/chunks/{chunk-WPG6SW7C.js → chunk-HVIFA73X.js} +2 -2
  86. package/dist/cli/chunks/{chunk-6U6JQS4Z.js → chunk-HW4V7BVV.js} +2 -2
  87. package/dist/cli/chunks/{chunk-X6W35QXO.js → chunk-I5VJ3FBC.js} +2 -2
  88. package/dist/cli/chunks/{chunk-YTMWPGVR.js → chunk-IARE5VGI.js} +1 -1
  89. package/dist/cli/chunks/chunk-INVDDFJC.js +2 -0
  90. package/dist/cli/chunks/{chunk-RDI3W4H6.js → chunk-JJBTM4JO.js} +2 -2
  91. package/dist/cli/chunks/chunk-JVQK6NGI.js +14 -0
  92. package/dist/cli/chunks/{chunk-CFZJEOCD.js → chunk-K65X6CQA.js} +1 -1
  93. package/dist/cli/chunks/{chunk-6DF6X3SZ.js → chunk-KCBCYF7M.js} +2 -2
  94. package/dist/cli/chunks/{chunk-QOOADAT7.js → chunk-KGS6H2HB.js} +2 -2
  95. package/dist/cli/chunks/{chunk-TCJ65NPY.js → chunk-L6OSEWOS.js} +1 -1
  96. package/dist/cli/chunks/{chunk-BW7S6LIJ.js → chunk-LEB6O2IN.js} +2 -2
  97. package/dist/cli/chunks/{chunk-WHBDSJUE.js → chunk-LPZAB3N2.js} +3 -3
  98. package/dist/cli/chunks/{chunk-JYF3QF4C.js → chunk-M3ACHBC7.js} +2 -2
  99. package/dist/cli/chunks/{chunk-WQZR6DS6.js → chunk-M3ONCPSU.js} +2 -2
  100. package/dist/cli/chunks/{chunk-7B3XVVYP.js → chunk-MUSYQF53.js} +2 -2
  101. package/dist/cli/chunks/{chunk-6AVVC7Y3.js → chunk-MZDUBFLP.js} +1 -1
  102. package/dist/cli/chunks/{chunk-53HWWWFZ.js → chunk-NT6FYFJA.js} +2 -2
  103. package/dist/cli/chunks/{chunk-6WW6A6JM.js → chunk-O66D4NEJ.js} +2 -2
  104. package/dist/cli/chunks/{chunk-3NOSMJS4.js → chunk-OGARNKLS.js} +2 -2
  105. package/dist/cli/chunks/{chunk-KHVWIUAF.js → chunk-OKNMZLGB.js} +2 -2
  106. package/dist/cli/chunks/{chunk-XCVD57GW.js → chunk-OMHISPPF.js} +1 -1
  107. package/dist/cli/chunks/{chunk-N5OSH5JO.js → chunk-OT6SOPAL.js} +2 -2
  108. package/dist/cli/chunks/{chunk-ZZV6GR46.js → chunk-OTTTHNIT.js} +1 -1
  109. package/dist/cli/chunks/{chunk-XZGRHJGC.js → chunk-P36IODAM.js} +2 -2
  110. package/dist/cli/chunks/{chunk-JHKMUY4W.js → chunk-P6EGRAQG.js} +2 -2
  111. package/dist/cli/chunks/{chunk-5JJWVFUV.js → chunk-PBUWNMZ2.js} +1 -1
  112. package/dist/cli/chunks/{chunk-LQI5GVH7.js → chunk-POTVF6BY.js} +1 -1
  113. package/dist/cli/chunks/{chunk-N4HQ6FE2.js → chunk-POVP6O6K.js} +1 -1
  114. package/dist/cli/chunks/{chunk-P24ZBDZY.js → chunk-PPA53NJB.js} +2 -2
  115. package/dist/cli/chunks/{chunk-OABFAREV.js → chunk-PUPEKA2J.js} +2 -2
  116. package/dist/cli/chunks/{chunk-27S47AYK.js → chunk-QDQLL2QB.js} +2 -2
  117. package/dist/cli/chunks/{chunk-MEOAKMKF.js → chunk-QSVNVDA5.js} +1 -1
  118. package/dist/cli/chunks/{chunk-66HKJJFH.js → chunk-QUXX2DP7.js} +2 -2
  119. package/dist/cli/chunks/{chunk-TLUMENRZ.js → chunk-QVNMTMDJ.js} +2 -2
  120. package/dist/cli/chunks/{chunk-LDDIYDIP.js → chunk-QZBFMXO5.js} +54 -54
  121. package/dist/cli/chunks/{chunk-4THIRDBL.js → chunk-RDTR43YN.js} +2 -2
  122. package/dist/cli/chunks/{chunk-6MGJMGAD.js → chunk-RGD2CG23.js} +2 -2
  123. package/dist/cli/chunks/{chunk-V5RP2SU3.js → chunk-RQUSJEON.js} +2 -2
  124. package/dist/cli/chunks/{chunk-WYE3ICSL.js → chunk-RRSZ27A7.js} +2 -2
  125. package/dist/cli/chunks/{chunk-GUKBN3BS.js → chunk-RWLOERKK.js} +2 -2
  126. package/dist/cli/chunks/{chunk-5TEDVUEB.js → chunk-RWQDRPN5.js} +2 -2
  127. package/dist/cli/chunks/{chunk-2IPBCXTT.js → chunk-S7D4GD7H.js} +2 -2
  128. package/dist/cli/chunks/{chunk-FTHXV7N7.js → chunk-SKHP5WUP.js} +2 -2
  129. package/dist/cli/chunks/{chunk-QVTV47TM.js → chunk-SP2JO53K.js} +2 -2
  130. package/dist/cli/chunks/{chunk-UTFNHITI.js → chunk-SRDECRTL.js} +2 -2
  131. package/dist/cli/chunks/{chunk-HVAYG54D.js → chunk-TBVPNN65.js} +2 -2
  132. package/dist/cli/chunks/{chunk-JQVECGYL.js → chunk-U5AVZ3T2.js} +1 -1
  133. package/dist/cli/chunks/{chunk-EQ3BJS37.js → chunk-UCSGZVJX.js} +1 -1
  134. package/dist/cli/chunks/{chunk-5C4UYXQL.js → chunk-UGNTLSBL.js} +2 -2
  135. package/dist/cli/chunks/{chunk-W5NHBYYS.js → chunk-UTALYUMW.js} +2 -2
  136. package/dist/cli/chunks/{chunk-35XRY6ZW.js → chunk-UZDTRCVU.js} +9 -9
  137. package/dist/cli/chunks/{chunk-AVOYMVD6.js → chunk-V5NYGDSX.js} +2 -2
  138. package/dist/cli/chunks/{chunk-FQYXPSWD.js → chunk-VGN46ZT4.js} +2 -2
  139. package/dist/cli/chunks/{chunk-QMHWJBD3.js → chunk-VHBZADYK.js} +2 -2
  140. package/dist/cli/chunks/{chunk-54JYUOSR.js → chunk-VOKIUF7I.js} +1 -1
  141. package/dist/cli/chunks/{chunk-PDLVO3ZR.js → chunk-VRT736E3.js} +2 -2
  142. package/dist/cli/chunks/{chunk-DV7I6CRH.js → chunk-VUBLJBHQ.js} +2 -2
  143. package/dist/cli/chunks/{chunk-FRGNM6SW.js → chunk-VX7CQUO7.js} +2 -2
  144. package/dist/cli/chunks/{chunk-YDM2DPUU.js → chunk-W7EHNX3Y.js} +2 -2
  145. package/dist/cli/chunks/{chunk-W5HQQTVH.js → chunk-WI7I6LMM.js} +1 -1
  146. package/dist/cli/chunks/{chunk-46DUU44C.js → chunk-WLOHTLHO.js} +2 -2
  147. package/dist/cli/chunks/{chunk-W6K77PQR.js → chunk-WQZBKLAG.js} +1 -1
  148. package/dist/cli/chunks/{chunk-UGUZFUQG.js → chunk-WSND64RL.js} +2 -2
  149. package/dist/cli/chunks/{chunk-PNK5KHSI.js → chunk-WSUYEVSY.js} +1 -1
  150. package/dist/cli/chunks/{chunk-FIIHSEXP.js → chunk-WTMLRMKW.js} +2 -2
  151. package/dist/cli/chunks/{chunk-OPBPFNBO.js → chunk-WW4RJ6BH.js} +2 -2
  152. package/dist/cli/chunks/{chunk-KBK4GBJQ.js → chunk-X335K4SU.js} +2 -2
  153. package/dist/cli/chunks/{chunk-NS4RIZ4F.js → chunk-X33LID2T.js} +1 -1
  154. package/dist/cli/chunks/{chunk-L5GEWKR3.js → chunk-XTGVGZ4J.js} +3 -3
  155. package/dist/cli/chunks/{chunk-CTLHNFPM.js → chunk-XV2TIODR.js} +1 -1
  156. package/dist/cli/chunks/{chunk-GAKVCN3C.js → chunk-XXW4KFBB.js} +1 -1
  157. package/dist/cli/chunks/{chunk-CTK7NMSJ.js → chunk-YCGU2LI7.js} +2 -2
  158. package/dist/cli/chunks/chunk-YGEC3PSD.js +2 -0
  159. package/dist/cli/chunks/{chunk-ARGMYSDY.js → chunk-YGKU2QRC.js} +1 -1
  160. package/dist/cli/chunks/{chunk-6Q7PWKWV.js → chunk-YHZGFWJE.js} +2 -2
  161. package/dist/cli/chunks/{chunk-V3ISBQ5Q.js → chunk-YJH7UFA2.js} +2 -2
  162. package/dist/cli/chunks/{chunk-A5LOELVV.js → chunk-YQ3ZW47V.js} +2 -2
  163. package/dist/cli/chunks/{chunk-25IWHVMW.js → chunk-YTRGMILO.js} +2 -2
  164. package/dist/cli/chunks/chunk-YW4GM36K.js +2 -0
  165. package/dist/cli/chunks/{chunk-JW2HNT3J.js → chunk-Z7JPWXW2.js} +2 -2
  166. package/dist/cli/chunks/{chunk-PZDI7WQ3.js → chunk-Z7UGEQ4G.js} +1 -1
  167. package/dist/cli/chunks/{chunk-TBCQWD5A.js → chunk-ZATQLTYL.js} +1 -1
  168. package/dist/cli/chunks/{chunk-DKWB4ERY.js → chunk-ZI6NJEBY.js} +1 -1
  169. package/dist/cli/chunks/{chunk-B3DWOR5R.js → chunk-ZJW4HRUA.js} +1 -1
  170. package/dist/cli/chunks/{chunk-X4PGLEPQ.js → chunk-ZL2GYU7H.js} +2 -2
  171. package/dist/cli/chunks/{ci-K7DG4GSO.js → ci-JPISJ25U.js} +3 -3
  172. package/dist/cli/chunks/{ci-output-EBSUG6HP.js → ci-output-DPHTFIGX.js} +2 -2
  173. package/dist/cli/chunks/{circuit-breaker-P6N6YIRZ.js → circuit-breaker-PQ65VU2M.js} +2 -2
  174. package/dist/cli/chunks/{claude-flow-setup-P6EZPQZT.js → claude-flow-setup-GKHVO7AD.js} +2 -2
  175. package/dist/cli/chunks/client-BS7I637W.js +2 -0
  176. package/dist/cli/chunks/{cline-installer-EVZZ3EFY.js → cline-installer-HWMQZJ64.js} +2 -2
  177. package/dist/cli/chunks/{code-3WLBG2XK.js → code-OTY7BF3D.js} +3 -3
  178. package/dist/cli/chunks/{code-index-extractor-ZP6D4WL2.js → code-index-extractor-FG3TMHHR.js} +2 -2
  179. package/dist/cli/chunks/{codex-installer-XAUI4SB7.js → codex-installer-63JARKKS.js} +2 -2
  180. package/dist/cli/chunks/{completions-RHFNDDG3.js → completions-4ZHONFML.js} +2 -2
  181. package/dist/cli/chunks/{complexity-analyzer-DCW7Q3OR.js → complexity-analyzer-FYHTJW5Y.js} +2 -2
  182. package/dist/cli/chunks/{continuedev-installer-53SQA5T6.js → continuedev-installer-ZAWDSUR3.js} +2 -2
  183. package/dist/cli/chunks/{copilot-installer-SXXMFB6T.js → copilot-installer-5QK565JX.js} +2 -2
  184. package/dist/cli/chunks/core-handlers-UG7RMTK5.js +2 -0
  185. package/dist/cli/chunks/cost-tracker-AWWMPPBJ.js +2 -0
  186. package/dist/cli/chunks/{coverage-AWCS2SP7.js → coverage-SMFQEGKE.js} +3 -3
  187. package/dist/cli/chunks/cross-domain-router-NX7F6TOF.js +2 -0
  188. package/dist/cli/chunks/{cursor-installer-4TYF5V5J.js → cursor-installer-3BL7JACV.js} +2 -2
  189. package/dist/cli/chunks/{daemon-CTZXGN5V.js → daemon-OJ624POF.js} +4 -4
  190. package/dist/cli/chunks/{daemon-OOY4H6RJ.js → daemon-R6ULBHHF.js} +3 -3
  191. package/dist/cli/chunks/{dag-attention-scheduler-3WG24Q33.js → dag-attention-scheduler-J6I3LTMY.js} +2 -2
  192. package/dist/cli/chunks/{detect-O7MUZ6NX.js → detect-5Q5W33UR.js} +2 -2
  193. package/dist/cli/chunks/{dist-node-H4XI7BAF.js → dist-node-GJNW56NA.js} +2 -2
  194. package/dist/cli/chunks/{domain-handler-FU4WZ23B.js → domain-handler-IZQY2G44.js} +2 -2
  195. package/dist/cli/chunks/{domain-plugins-XK26KYNJ.js → domain-plugins-PIGO3KI2.js} +2 -2
  196. package/dist/cli/chunks/{domain-transfer-6B5NOVH6.js → domain-transfer-NU3B4FQG.js} +2 -2
  197. package/dist/cli/chunks/dream-GYEH57FW.js +2 -0
  198. package/dist/cli/chunks/{embed-and-insert-pattern-XNZXPZNL.js → embed-and-insert-pattern-5QDDRPWV.js} +2 -2
  199. package/dist/cli/chunks/{eval-J3Q5TTI7.js → eval-TB5HOAUY.js} +2 -2
  200. package/dist/cli/chunks/{experience-capture-middleware-COKIGMXW.js → experience-capture-middleware-SIYVLKDE.js} +3 -3
  201. package/dist/cli/chunks/{fast-paths-IHWPJI6I.js → fast-paths-T7QELS6D.js} +2 -2
  202. package/dist/cli/chunks/{feature-flags-WUXFWZLR.js → feature-flags-T3CNNYMJ.js} +2 -2
  203. package/dist/cli/chunks/{feature-flags-G7ONDNTT.js → feature-flags-TNZ7ZAJV.js} +2 -2
  204. package/dist/cli/chunks/{file-discovery-JN3YMBOJ.js → file-discovery-M45P2ZCY.js} +2 -2
  205. package/dist/cli/chunks/{fleet-OUHUZJE4.js → fleet-DSBZPHBZ.js} +3 -3
  206. package/dist/cli/chunks/{gnn-wrapper-PRH55ZT6.js → gnn-wrapper-EHODCF32.js} +2 -2
  207. package/dist/cli/chunks/{heartbeat-handler-6YF35AQS.js → heartbeat-handler-V5DBVF7V.js} +4 -4
  208. package/dist/cli/chunks/heartbeat-scheduler-4TJ3T7LR.js +2 -0
  209. package/dist/cli/chunks/hnsw-adapter-PHFK4EAP.js +2 -0
  210. package/dist/cli/chunks/hnsw-index-434XDDBH.js +2 -0
  211. package/dist/cli/chunks/{hnsw-legacy-bridge-7PAFSTJO.js → hnsw-legacy-bridge-IYKDYA2F.js} +2 -2
  212. package/dist/cli/chunks/{hnswlib-node-UETDZNNN.js → hnswlib-node-DKG4LW3X.js} +2 -2
  213. package/dist/cli/chunks/{hooks-QQNUKQAS.js → hooks-VKNMAILY.js} +10 -10
  214. package/dist/cli/chunks/hybrid-backend-DYVJQENQ.js +2 -0
  215. package/dist/cli/chunks/{hypergraph-engine-5GDGE3ET.js → hypergraph-engine-AXZVP7A7.js} +2 -2
  216. package/dist/cli/chunks/{hypergraph-handler-C3F2OJYA.js → hypergraph-handler-6EO6JN4Z.js} +3 -3
  217. package/dist/cli/chunks/impact-analyzer-CBAST6M2.js +2 -0
  218. package/dist/cli/chunks/init-handler-N3NG3RHN.js +86 -0
  219. package/dist/cli/chunks/init-wizard-DWIJW7HY.js +2 -0
  220. package/dist/cli/chunks/kernel-AQGCS4X2.js +2 -0
  221. package/dist/cli/chunks/{kilocode-installer-VLJENC76.js → kilocode-installer-JICGAHLM.js} +2 -2
  222. package/dist/cli/chunks/{kiro-installer-UYPYM6LA.js → kiro-installer-VYBFP6ZH.js} +2 -2
  223. package/dist/cli/chunks/knowledge-graph-2ICXFUUV.js +2 -0
  224. package/dist/cli/chunks/{learning-SFIWIG6Z.js → learning-3BHEZEPK.js} +3 -3
  225. package/dist/cli/chunks/{llm-router-V633KAS5.js → llm-router-GPTEZCUN.js} +4 -4
  226. package/dist/cli/chunks/llm-router-service-C47RGTH6.js +2 -0
  227. package/dist/cli/chunks/{load-UWZV4JRA.js → load-W5BIRPU4.js} +2 -2
  228. package/dist/cli/chunks/load-test-LRDAW3N6.js +2 -0
  229. package/dist/cli/chunks/{mcp-XVFHUKCP.js → mcp-EBV4DZPG.js} +2 -2
  230. package/dist/cli/chunks/{memory-BQ5652VK.js → memory-7F6YYKNL.js} +5 -5
  231. package/dist/cli/chunks/memory-backend-UFBAYPQ6.js +2 -0
  232. package/dist/cli/chunks/memory-handlers-OGLJHAAJ.js +2 -0
  233. package/dist/cli/chunks/{multi-model-executor-X6AQ7VVR.js → multi-model-executor-3ZIA2YOL.js} +2 -2
  234. package/dist/cli/chunks/{opencode-installer-N3V2Z4EF.js → opencode-installer-2XRZUTLR.js} +2 -2
  235. package/dist/cli/chunks/{orchestrator-KNEKS4F7.js → orchestrator-VSZVJUJW.js} +87 -28
  236. package/dist/cli/chunks/pattern-null-store-27FCITT3.js +2 -0
  237. package/dist/cli/chunks/{pattern-usage-recorder-MZIM6XWU.js → pattern-usage-recorder-I2IGVHRL.js} +2 -2
  238. package/dist/cli/chunks/{pipeline-LNLBKSXR.js → pipeline-5G3O6WBY.js} +2 -2
  239. package/dist/cli/chunks/{platform-OMUDXHD3.js → platform-6GUFDIA3.js} +2 -2
  240. package/dist/cli/chunks/{plugin-HGY6KKZW.js → plugin-GYXE4CIC.js} +2 -2
  241. package/dist/cli/chunks/{prime-radiant-advanced-wasm-LZBHLQYN.js → prime-radiant-advanced-wasm-THX6JLGZ.js} +2 -2
  242. package/dist/cli/chunks/{project-root-VPSCDBMD.js → project-root-QJRBKZQU.js} +2 -2
  243. package/dist/cli/chunks/protocol-executor-XWXXTMEW.js +2 -0
  244. package/dist/cli/chunks/{protocol-handler-LZXT3TXU.js → protocol-handler-B54LRU26.js} +2 -2
  245. package/dist/cli/chunks/{prove-I4VKQEYQ.js → prove-PCY2WQOD.js} +2 -2
  246. package/dist/cli/chunks/qe-reasoning-bank-3RMYXENE.js +2 -0
  247. package/dist/cli/chunks/{quality-VVAWK2DD.js → quality-LPVDZC7U.js} +2 -2
  248. package/dist/cli/chunks/{quality-gate-RGXLWYT6.js → quality-gate-L3KXL6WE.js} +3 -3
  249. package/dist/cli/chunks/queen-coordinator-AS6DZ7UJ.js +2 -0
  250. package/dist/cli/chunks/{real-embeddings-WM66PMQ6.js → real-embeddings-N3H523PJ.js} +2 -2
  251. package/dist/cli/chunks/{ref-validation-ZIWJNI6M.js → ref-validation-6BKDPHZ7.js} +2 -2
  252. package/dist/cli/chunks/{roocode-installer-QYSI3STC.js → roocode-installer-NSGGTWXE.js} +2 -2
  253. package/dist/cli/chunks/router-OVNLNGHO.js +2 -0
  254. package/dist/cli/chunks/routing-feedback-TBOWEB6H.js +2 -0
  255. package/dist/cli/chunks/{routing-handler-BID3EOLE.js → routing-handler-SRQNUBG3.js} +2 -2
  256. package/dist/cli/chunks/{ruvector-commands-DXIFMF4W.js → ruvector-commands-2IGULGDE.js} +2 -2
  257. package/dist/cli/chunks/rvf-dual-writer-YJYRCYGT.js +2 -0
  258. package/dist/cli/chunks/rvf-migration-adapter-VMRQ2SFO.js +2 -0
  259. package/dist/cli/chunks/{rvf-migration-coordinator-EV5E6SAO.js → rvf-migration-coordinator-ZD6WK5CK.js} +2 -2
  260. package/dist/cli/chunks/rvf-native-adapter-B75L3ALW.js +2 -0
  261. package/dist/cli/chunks/{rvf-store-integrity-IT6DCCJK.js → rvf-store-integrity-QULKUBBI.js} +2 -2
  262. package/dist/cli/chunks/safe-db-CRQHMCV6.js +2 -0
  263. package/dist/cli/chunks/schedule-L3DKJRXU.js +2 -0
  264. package/dist/cli/chunks/scheduler-VRHYUGY5.js +2 -0
  265. package/dist/cli/chunks/{security-AAFAEATQ.js → security-JW4EBARW.js} +3 -3
  266. package/dist/cli/chunks/{shared-rvf-adapter-QIHSYHAF.js → shared-rvf-adapter-VQ7NJTGY.js} +2 -2
  267. package/dist/cli/chunks/{shared-rvf-dual-writer-V7OZ6TBR.js → shared-rvf-dual-writer-SKTS52HK.js} +2 -2
  268. package/dist/cli/chunks/sqlite-persistence-JVAZETTL.js +2 -0
  269. package/dist/cli/chunks/{standalone-memory-ALZI6VPX.js → standalone-memory-3N4YJCSY.js} +2 -2
  270. package/dist/cli/chunks/{status-handler-DED5A3OW.js → status-handler-5BQ2IIDG.js} +2 -2
  271. package/dist/cli/chunks/{structural-health-CB7L3NWH.js → structural-health-WGYR2RJB.js} +2 -2
  272. package/dist/cli/chunks/{sync-QNPGETIO.js → sync-DLKSXTIR.js} +2 -2
  273. package/dist/cli/chunks/sync-R5OKUBTQ.js +2 -0
  274. package/dist/cli/chunks/{task-handler-CGHXYFIF.js → task-handler-Z5KNTSUX.js} +2 -2
  275. package/dist/cli/chunks/{task-handlers-A6BGQJIB.js → task-handlers-RZFMYFSC.js} +3 -3
  276. package/dist/cli/chunks/test-LHWKZJRN.js +34 -0
  277. package/dist/cli/chunks/test-scheduling-EN7WXUMS.js +15 -0
  278. package/dist/cli/chunks/token-bootstrap-4V3OO4EC.js +2 -0
  279. package/dist/cli/chunks/{token-usage-25BRFKJ5.js → token-usage-PFC2BYBS.js} +2 -2
  280. package/dist/cli/chunks/{transformers-TBVVSZMF.js → transformers-VZCC4SHC.js} +2 -2
  281. package/dist/cli/chunks/{tree-sitter-wasm-parser-N7KCOQT4.js → tree-sitter-wasm-parser-ZYDQXGKN.js} +2 -2
  282. package/dist/cli/chunks/{types-TFHWJGRK.js → types-I6AWHZZQ.js} +2 -2
  283. package/dist/cli/chunks/unified-memory-WOOCCIUM.js +2 -0
  284. package/dist/cli/chunks/unified-memory-hnsw-PDDHFLUB.js +2 -0
  285. package/dist/cli/chunks/unified-persistence-6ETD3JSC.js +2 -0
  286. package/dist/cli/chunks/{upgrade-4VWQU7RD.js → upgrade-T7SG75PA.js} +2 -2
  287. package/dist/cli/chunks/{validate-FF7WVXMP.js → validate-YLYEHTY3.js} +2 -2
  288. package/dist/cli/chunks/{validate-swarm-NRLH4EDC.js → validate-swarm-VTLTRUE3.js} +2 -2
  289. package/dist/cli/chunks/visual-security-O4OT2YPY.js +2 -0
  290. package/dist/cli/chunks/{web-tree-sitter-VVU3LULW.js → web-tree-sitter-JUM7ZY5M.js} +2 -2
  291. package/dist/cli/chunks/{windsurf-installer-Q2ZNWG2D.js → windsurf-installer-4KS2466T.js} +2 -2
  292. package/dist/cli/chunks/witness-chain-67JHPDCN.js +2 -0
  293. package/dist/cli/chunks/{witness-chain-FP3D4PQL.js → witness-chain-E4X6TOCT.js} +2 -2
  294. package/dist/cli/chunks/witness-chain-repair-MB53OZO6.js +2 -0
  295. package/dist/cli/chunks/{witness-chain-verifier-LACGL6BK.js → witness-chain-verifier-LBWJHO7Y.js} +2 -2
  296. package/dist/cli/chunks/{witness-key-manager-GQZIB5ZE.js → witness-key-manager-5IHVMXHJ.js} +2 -2
  297. package/dist/cli/chunks/{workflow-JPA5Y7L6.js → workflow-XUQXIRNE.js} +4 -4
  298. package/dist/cli/chunks/workflow-orchestrator-ZVFSNRYZ.js +2 -0
  299. package/dist/cli/chunks/wrappers-YVF5SQUN.js +2 -0
  300. package/dist/cli/commands/test.js +42 -9
  301. package/dist/cli/handlers/init-flags.d.ts +45 -0
  302. package/dist/cli/handlers/init-flags.js +35 -0
  303. package/dist/cli/handlers/init-handler.d.ts +6 -0
  304. package/dist/cli/handlers/init-handler.js +24 -10
  305. package/dist/cli/utils/generated-test-writer.d.ts +35 -0
  306. package/dist/cli/utils/generated-test-writer.js +44 -0
  307. package/dist/context/compiler.js +4 -1
  308. package/dist/coordination/consensus/providers/ollama-provider.js +16 -27
  309. package/dist/coordination/consensus/providers/openrouter-provider.js +13 -24
  310. package/dist/coordination/handlers/test-execution-handlers.js +4 -2
  311. package/dist/coordination/protocols/defect-investigation.js +4 -1
  312. package/dist/coordination/task-executor.js +4 -2
  313. package/dist/domains/code-intelligence/services/metric-collector/test-counter.js +3 -3
  314. package/dist/domains/coverage-analysis/services/gap-detector.js +3 -1
  315. package/dist/domains/learning-optimization/services/learning-coordinator.js +4 -2
  316. package/dist/domains/test-execution/services/flaky-detector.js +8 -2
  317. package/dist/domains/test-execution/services/retry-handler.js +23 -20
  318. package/dist/domains/test-execution/services/test-executor.js +5 -2
  319. package/dist/domains/test-generation/services/test-generator.js +5 -2
  320. package/dist/governance/compliance-reporter.js +8 -7
  321. package/dist/governance/proof-envelope-integration.js +3 -1
  322. package/dist/init/claude-plugin-detection.d.ts +63 -0
  323. package/dist/init/claude-plugin-detection.js +118 -0
  324. package/dist/init/init-wizard-hooks.d.ts +6 -1
  325. package/dist/init/init-wizard-hooks.js +9 -1
  326. package/dist/init/init-wizard.d.ts +4 -0
  327. package/dist/init/init-wizard.js +3 -1
  328. package/dist/init/orchestrator.js +1 -0
  329. package/dist/init/phases/07-hooks.js +30 -4
  330. package/dist/init/phases/08-mcp.d.ts +7 -0
  331. package/dist/init/phases/08-mcp.js +22 -0
  332. package/dist/init/phases/10-workers.js +42 -6
  333. package/dist/init/phases/phase-interface.d.ts +5 -1
  334. package/dist/integrations/agentic-flow/onnx-embeddings/embedding-generator.d.ts +4 -1
  335. package/dist/integrations/agentic-flow/onnx-embeddings/embedding-generator.js +6 -2
  336. package/dist/integrations/browser/qe-dashboard/wasm-vector-store.js +2 -1
  337. package/dist/integrations/ruvector/coverage-router.d.ts +3 -1
  338. package/dist/integrations/ruvector/coverage-router.js +7 -6
  339. package/dist/integrations/ruvector/diff-risk-classifier.js +5 -4
  340. package/dist/integrations/ruvector/rvf-dual-writer.js +10 -1
  341. package/dist/integrations/vibium/runtime.js +2 -6
  342. package/dist/learning/dream/dream-engine.d.ts +5 -0
  343. package/dist/learning/dream/dream-engine.js +20 -3
  344. package/dist/learning/embedding-space.d.ts +18 -0
  345. package/dist/learning/embedding-space.js +33 -0
  346. package/dist/learning/rvf-pattern-store.js +19 -5
  347. package/dist/mcp/bundle.js +443 -441
  348. package/dist/mcp/handlers/domain-handler-configs.js +3 -1
  349. package/dist/mcp/handlers/handler-factory.js +7 -0
  350. package/dist/mcp/handlers/save-results-option.d.ts +97 -0
  351. package/dist/mcp/handlers/save-results-option.js +94 -0
  352. package/dist/mcp/protocol-server.js +23 -11
  353. package/dist/mcp/security/rate-limiter.d.ts +8 -1
  354. package/dist/mcp/security/rate-limiter.js +33 -4
  355. package/dist/mcp/services/session-resume.js +11 -0
  356. package/dist/mcp/services/session-store.d.ts +31 -2
  357. package/dist/mcp/services/session-store.js +84 -15
  358. package/dist/mcp/services/session-write-buffer.d.ts +55 -0
  359. package/dist/mcp/services/session-write-buffer.js +144 -0
  360. package/dist/mcp/types.d.ts +9 -0
  361. package/dist/memory/crdt/g-counter.js +10 -8
  362. package/dist/shared/embeddings/ollama-client.d.ts +1 -1
  363. package/dist/shared/embeddings/ollama-client.js +30 -31
  364. package/dist/shared/git/git-analyzer.d.ts +4 -1
  365. package/dist/shared/git/git-analyzer.js +9 -4
  366. package/dist/shared/llm/cost-tracker.js +8 -6
  367. package/dist/shared/llm/providers/azure-openai.js +5 -21
  368. package/dist/shared/llm/providers/bedrock.js +5 -21
  369. package/dist/shared/llm/providers/claude.js +5 -21
  370. package/dist/shared/llm/providers/cognitum.js +5 -17
  371. package/dist/shared/llm/providers/gemini.js +9 -23
  372. package/dist/shared/llm/providers/ollama.js +5 -21
  373. package/dist/shared/llm/providers/openai.js +5 -21
  374. package/dist/shared/llm/providers/openrouter.js +9 -23
  375. package/dist/shared/llm/providers/response-deadline.d.ts +3 -0
  376. package/dist/shared/llm/providers/response-deadline.js +100 -0
  377. package/dist/shared/llm/spend-ledger.js +3 -2
  378. package/dist/shared/metrics/code-metrics.d.ts +1 -0
  379. package/dist/shared/metrics/code-metrics.js +3 -44
  380. package/dist/shared/metrics/cognitive-complexity.d.ts +17 -0
  381. package/dist/shared/metrics/cognitive-complexity.js +108 -0
  382. package/dist/shared/npm-cli-invocation.d.ts +21 -0
  383. package/dist/shared/npm-cli-invocation.js +28 -0
  384. package/dist/shared/optional-module.js +24 -0
  385. package/dist/shared/test-runner-args.d.ts +42 -0
  386. package/dist/shared/test-runner-args.js +74 -0
  387. package/dist/shared/utils/safe-record.d.ts +18 -0
  388. package/dist/shared/utils/safe-record.js +28 -0
  389. package/dist/test-scheduling/executors/vitest-executor.js +23 -5
  390. package/dist/workers/quality-daemon/git-watcher.js +5 -0
  391. package/package.json +1 -1
  392. package/dist/adapters/ag-ui/json-patch-utils.d.ts +0 -136
  393. package/dist/adapters/ag-ui/json-patch-utils.js +0 -575
  394. package/dist/cli/chunks/adapter-Q6RPGMUE.js +0 -2
  395. package/dist/cli/chunks/aqe-learning-engine-JQPXIU7C.js +0 -2
  396. package/dist/cli/chunks/base-5SK64NXB.js +0 -2
  397. package/dist/cli/chunks/browser-workflow-WN7XNTCJ.js +0 -2
  398. package/dist/cli/chunks/chunk-2K3QFLX2.js +0 -2
  399. package/dist/cli/chunks/chunk-53C7TGC4.js +0 -4
  400. package/dist/cli/chunks/chunk-J4ULR4QR.js +0 -54
  401. package/dist/cli/chunks/chunk-R2ICZKQA.js +0 -2
  402. package/dist/cli/chunks/chunk-TR37Q7A6.js +0 -15
  403. package/dist/cli/chunks/chunk-XYZUBAR6.js +0 -316
  404. package/dist/cli/chunks/chunk-YDMPTCJ3.js +0 -14
  405. package/dist/cli/chunks/client-ZYH66YRI.js +0 -2
  406. package/dist/cli/chunks/core-handlers-XKSPHEHE.js +0 -2
  407. package/dist/cli/chunks/cost-tracker-CKLDQ5AZ.js +0 -2
  408. package/dist/cli/chunks/cross-domain-router-6VYNFQZA.js +0 -2
  409. package/dist/cli/chunks/dream-DRSSIHPP.js +0 -2
  410. package/dist/cli/chunks/heartbeat-scheduler-FMICCNWK.js +0 -2
  411. package/dist/cli/chunks/hnsw-adapter-4TGBNJEZ.js +0 -2
  412. package/dist/cli/chunks/hnsw-index-J4NSCPAZ.js +0 -2
  413. package/dist/cli/chunks/hybrid-backend-NKPA3QE7.js +0 -2
  414. package/dist/cli/chunks/impact-analyzer-MWX7XY7X.js +0 -2
  415. package/dist/cli/chunks/init-handler-C7ZBDAC5.js +0 -81
  416. package/dist/cli/chunks/init-wizard-EX5N5Q7X.js +0 -2
  417. package/dist/cli/chunks/kernel-EQLZDHDD.js +0 -2
  418. package/dist/cli/chunks/knowledge-graph-A3WSMQ6U.js +0 -2
  419. package/dist/cli/chunks/llm-router-service-A6XYWTL6.js +0 -2
  420. package/dist/cli/chunks/load-test-WF2PCXLI.js +0 -2
  421. package/dist/cli/chunks/memory-backend-BKGLI2RF.js +0 -2
  422. package/dist/cli/chunks/memory-handlers-PWI3G4P4.js +0 -2
  423. package/dist/cli/chunks/pattern-null-store-YTBLEH7D.js +0 -2
  424. package/dist/cli/chunks/protocol-executor-HFR2D54O.js +0 -2
  425. package/dist/cli/chunks/qe-reasoning-bank-MYFBQUYV.js +0 -2
  426. package/dist/cli/chunks/queen-coordinator-CQQMOTIW.js +0 -2
  427. package/dist/cli/chunks/router-GKWLPA3N.js +0 -2
  428. package/dist/cli/chunks/routing-feedback-WA4D5JRF.js +0 -2
  429. package/dist/cli/chunks/rvf-dual-writer-H3ZXS5MA.js +0 -2
  430. package/dist/cli/chunks/rvf-migration-adapter-J7MTCOQA.js +0 -2
  431. package/dist/cli/chunks/rvf-native-adapter-HXBY4VYI.js +0 -2
  432. package/dist/cli/chunks/safe-db-INVJ5LHR.js +0 -2
  433. package/dist/cli/chunks/schedule-XRIPPL52.js +0 -2
  434. package/dist/cli/chunks/scheduler-HBN3KPRW.js +0 -2
  435. package/dist/cli/chunks/sqlite-persistence-6KNLT5Q2.js +0 -2
  436. package/dist/cli/chunks/sync-S6Z2U46T.js +0 -2
  437. package/dist/cli/chunks/test-IISTF5W6.js +0 -33
  438. package/dist/cli/chunks/test-scheduling-FKYX4OLF.js +0 -15
  439. package/dist/cli/chunks/token-bootstrap-OKO3JEKT.js +0 -2
  440. package/dist/cli/chunks/unified-memory-WVELSL6T.js +0 -2
  441. package/dist/cli/chunks/unified-memory-hnsw-7P5MVKXD.js +0 -2
  442. package/dist/cli/chunks/unified-persistence-YLFCEWYY.js +0 -2
  443. package/dist/cli/chunks/visual-security-T5OM742H.js +0 -2
  444. package/dist/cli/chunks/witness-chain-D6X4OZP5.js +0 -2
  445. package/dist/cli/chunks/witness-chain-repair-3LG4BF7C.js +0 -2
  446. package/dist/cli/chunks/workflow-orchestrator-OORDDKT3.js +0 -2
  447. package/dist/cli/chunks/wrappers-2B5NHICD.js +0 -2
@@ -6,17 +6,35 @@
6
6
  * changes within a session. Supports write batching (100ms window) and
7
7
  * lazy file creation (no file until first append).
8
8
  *
9
+ * Issue #910: writes track progress byte by byte, so a write that fails partway
10
+ * (ENOSPC, EIO) resumes where it stopped instead of re-appending what already
11
+ * reached the disk. The unwritten backlog is bounded while the disk keeps
12
+ * failing; dropped entries become one gap marker that keeps the transcript
13
+ * resumable (see session-write-buffer.ts).
14
+ *
9
15
  * @module mcp/services/session-store
10
16
  */
11
17
  import { randomUUID } from 'crypto';
12
18
  import * as fs from 'fs';
13
19
  import * as path from 'path';
14
20
  import { findProjectRoot } from '../../kernel/project-root.js';
21
+ import { SessionWriteBuffer, encodeEntry } from './session-write-buffer.js';
15
22
  // ============================================================================
16
23
  // Session Store
17
24
  // ============================================================================
18
25
  const DEFAULT_SESSION_DIR = '.agentic-qe/sessions';
19
26
  const BATCH_FLUSH_MS = 100;
27
+ const DEFAULT_MAX_BUFFERED_ENTRIES = 10_000;
28
+ // Matches the largest transcript session-resume will read.
29
+ const DEFAULT_MAX_BUFFERED_BYTES = 16 * 1024 * 1024;
30
+ function positiveLimit(name, value, fallback) {
31
+ if (value === undefined)
32
+ return fallback;
33
+ if (!Number.isSafeInteger(value) || value <= 0) {
34
+ throw new RangeError(`SessionStore ${name} must be a positive integer, got ${value}`);
35
+ }
36
+ return value;
37
+ }
20
38
  export class SessionStore {
21
39
  sessionDir;
22
40
  sessionId = null;
@@ -27,13 +45,20 @@ export class SessionStore {
27
45
  createdAt = 0;
28
46
  lastActivityAt = 0;
29
47
  currentState = 'idle';
30
- writeBuffer = [];
48
+ /** Lines not yet fully on disk, oldest first. */
49
+ writeBuffer;
50
+ dropWarned = false;
51
+ maxBufferedEntries;
52
+ maxBufferedBytes;
31
53
  flushTimer = null;
32
54
  closed = false;
33
55
  // Database-free mode (#534): keep session bookkeeping in memory but never
34
56
  // write .agentic-qe/sessions/*.jsonl to disk.
35
57
  persistDisabled = process.env.AQE_MEMORY_BACKEND === 'memory';
36
- constructor(sessionDir) {
58
+ constructor(sessionDir, options = {}) {
59
+ this.maxBufferedEntries = positiveLimit('maxBufferedEntries', options.maxBufferedEntries, DEFAULT_MAX_BUFFERED_ENTRIES);
60
+ this.maxBufferedBytes = positiveLimit('maxBufferedBytes', options.maxBufferedBytes, DEFAULT_MAX_BUFFERED_BYTES);
61
+ this.writeBuffer = this.createWriteBuffer();
37
62
  // #735: a cwd-relative default created `<subdir>/.agentic-qe/sessions`
38
63
  // on the first MCP tool call, which later runs then adopted as the
39
64
  // nearest project store. Anchor the default at the project root.
@@ -55,7 +80,8 @@ export class SessionStore {
55
80
  this.createdAt = Date.now();
56
81
  this.lastActivityAt = this.createdAt;
57
82
  this.currentState = 'idle';
58
- this.writeBuffer = [];
83
+ this.writeBuffer = this.createWriteBuffer();
84
+ this.dropWarned = false;
59
85
  this.flushTimer = null;
60
86
  this.closed = false;
61
87
  return this.sessionId;
@@ -65,7 +91,7 @@ export class SessionStore {
65
91
  * Assigns a uuid, links parentUuid to the previous entry,
66
92
  * and writes a JSON line to the file.
67
93
  *
68
- * First write uses appendFileSync for write-ahead guarantee.
94
+ * The first write is synchronous for a write-ahead guarantee.
69
95
  * Subsequent writes are batched for up to 100ms before flushing.
70
96
  *
71
97
  * Returns the assigned uuid.
@@ -82,24 +108,37 @@ export class SessionStore {
82
108
  };
83
109
  // Database-free mode keeps bookkeeping without serialization or disk I/O.
84
110
  if (!this.persistDisabled) {
85
- const line = JSON.stringify(fullEntry) + '\n';
111
+ const line = encodeEntry(fullEntry);
86
112
  if (!this.fileCreated) {
87
113
  // First write: synchronous for write-ahead guarantee
88
114
  this.ensureDirectory();
89
- fs.appendFileSync(this.filePath, line, 'utf-8');
115
+ this.writeBuffer.push(fullEntry, line);
116
+ try {
117
+ this.writePending();
118
+ }
119
+ catch (error) {
120
+ if (!this.writeBuffer.hasPartialHead) {
121
+ // Nothing reached the disk: reject the entry and leave the chain as it was.
122
+ this.writeBuffer.popNewest();
123
+ throw error;
124
+ }
125
+ // Part of the line is on disk. Keep it so a retry completes the record
126
+ // rather than leaving a torn prefix for the next line to glue onto.
127
+ this.fileCreated = true;
128
+ this.accept(fullEntry);
129
+ this.scheduleBatchFlush();
130
+ throw error;
131
+ }
90
132
  this.fileCreated = true;
91
133
  }
92
134
  else {
93
135
  // Subsequent writes: buffer and batch
94
- this.writeBuffer.push(line);
136
+ this.writeBuffer.push(fullEntry, line);
95
137
  this.scheduleBatchFlush();
96
138
  }
97
139
  }
98
140
  // Only advance the chain and metadata after the entry has been accepted.
99
- this.lastUuid = uuid;
100
- this.entryCount++;
101
- this.lastActivityAt = fullEntry.timestamp;
102
- this.currentState = fullEntry.state;
141
+ this.accept(fullEntry);
103
142
  return uuid;
104
143
  }
105
144
  /**
@@ -110,12 +149,20 @@ export class SessionStore {
110
149
  clearTimeout(this.flushTimer);
111
150
  this.flushTimer = null;
112
151
  }
113
- if (this.writeBuffer.length > 0 && this.filePath && this.fileCreated) {
114
- const batch = this.writeBuffer.join('');
115
- fs.appendFileSync(this.filePath, batch, 'utf-8');
116
- this.writeBuffer = [];
152
+ if (this.fileCreated) {
153
+ this.writePending();
117
154
  }
118
155
  }
156
+ /**
157
+ * Size of the unwritten backlog and how many entries the cap has dropped.
158
+ */
159
+ getWriteBufferStats() {
160
+ return {
161
+ bufferedEntries: this.writeBuffer.size,
162
+ bufferedBytes: this.writeBuffer.bufferedBytes,
163
+ droppedEntries: this.writeBuffer.droppedEntries,
164
+ };
165
+ }
119
166
  /**
120
167
  * Returns metadata about the current session.
121
168
  */
@@ -162,6 +209,28 @@ export class SessionStore {
162
209
  fs.mkdirSync(dir, { recursive: true });
163
210
  }
164
211
  }
212
+ accept(entry) {
213
+ this.lastUuid = entry.uuid;
214
+ this.entryCount++;
215
+ this.lastActivityAt = entry.timestamp;
216
+ this.currentState = entry.state;
217
+ }
218
+ writePending() {
219
+ if (this.filePath)
220
+ this.writeBuffer.writeTo(this.filePath);
221
+ }
222
+ createWriteBuffer() {
223
+ return new SessionWriteBuffer(this.maxBufferedEntries, this.maxBufferedBytes, () => {
224
+ if (this.dropWarned)
225
+ return;
226
+ this.dropWarned = true;
227
+ // "[AQE] WARN" passes the MCP entry's stderr filter.
228
+ console.error(`[AQE] WARN session journal ${this.filePath}: writes keep failing and the buffer reached its cap `
229
+ + `(${this.maxBufferedEntries} entries / ${this.maxBufferedBytes} bytes). The oldest unwritten entries `
230
+ + 'are replaced by one gap marker: their content is lost, but the transcript stays resumable. '
231
+ + 'The dropped count is in getWriteBufferStats() and in the marker.');
232
+ });
233
+ }
165
234
  scheduleBatchFlush() {
166
235
  if (this.flushTimer === null) {
167
236
  this.flushTimer = setTimeout(() => {
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Bounded, progress-tracking write buffer for the JSONL session journal (#910).
3
+ *
4
+ * - Writes track byte progress, so a write that fails partway (ENOSPC, EIO)
5
+ * resumes where it stopped instead of re-appending what reached the disk.
6
+ * - While writes keep failing, the backlog is capped. The oldest unwritten
7
+ * entries are replaced by one `state_change` gap marker that reuses the last
8
+ * dropped entry's uuid and the first dropped entry's parentUuid, so the
9
+ * parentUuid chain on disk stays valid and session-resume still accepts it.
10
+ *
11
+ * @module mcp/services/session-write-buffer
12
+ */
13
+ import type { SessionEntry } from './session-store';
14
+ /** `result` payload of a gap marker entry. */
15
+ export interface JournalGap {
16
+ droppedEntries: number;
17
+ reason: string;
18
+ }
19
+ export declare function encodeEntry(entry: SessionEntry): Buffer;
20
+ export declare class SessionWriteBuffer {
21
+ private readonly maxEntries;
22
+ private readonly maxBytes;
23
+ /** Called once per drop event with the running dropped total. */
24
+ private readonly onDrop;
25
+ private lines;
26
+ /** Bytes of lines[0] already on disk after a write that failed partway. */
27
+ private headWritten;
28
+ private bytes;
29
+ private dropped;
30
+ constructor(maxEntries: number, maxBytes: number,
31
+ /** Called once per drop event with the running dropped total. */
32
+ onDrop: (droppedTotal: number) => void);
33
+ get size(): number;
34
+ get bufferedBytes(): number;
35
+ get droppedEntries(): number;
36
+ /** True when part of the oldest line is already on disk. */
37
+ get hasPartialHead(): boolean;
38
+ push(entry: SessionEntry, data?: Buffer): void;
39
+ /** Remove the newest line (an entry whose first write put nothing on disk). */
40
+ popNewest(): void;
41
+ /**
42
+ * Append every buffered line with one write loop over a single buffer, then
43
+ * map the bytes written back onto line boundaries. On failure only the
44
+ * unwritten remainder stays buffered.
45
+ */
46
+ writeTo(filePath: string): void;
47
+ /** Drop the lines fully covered by `offset` bytes and keep partial progress. */
48
+ private settle;
49
+ /**
50
+ * Replace the oldest droppable lines with one gap marker until both caps hold.
51
+ * The newest line and a partially written head line are never dropped.
52
+ */
53
+ private enforceCaps;
54
+ }
55
+ //# sourceMappingURL=session-write-buffer.d.ts.map
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Bounded, progress-tracking write buffer for the JSONL session journal (#910).
3
+ *
4
+ * - Writes track byte progress, so a write that fails partway (ENOSPC, EIO)
5
+ * resumes where it stopped instead of re-appending what reached the disk.
6
+ * - While writes keep failing, the backlog is capped. The oldest unwritten
7
+ * entries are replaced by one `state_change` gap marker that reuses the last
8
+ * dropped entry's uuid and the first dropped entry's parentUuid, so the
9
+ * parentUuid chain on disk stays valid and session-resume still accepts it.
10
+ *
11
+ * @module mcp/services/session-write-buffer
12
+ */
13
+ import * as fs from 'fs';
14
+ const GAP_REASON = 'write buffer cap reached while the session journal could not be written';
15
+ // Upper bound on a gap marker line, used while choosing how many lines to drop.
16
+ const GAP_MARKER_MAX_BYTES = 512;
17
+ export function encodeEntry(entry) {
18
+ return Buffer.from(JSON.stringify(entry) + '\n', 'utf-8');
19
+ }
20
+ export class SessionWriteBuffer {
21
+ maxEntries;
22
+ maxBytes;
23
+ onDrop;
24
+ lines = [];
25
+ /** Bytes of lines[0] already on disk after a write that failed partway. */
26
+ headWritten = 0;
27
+ bytes = 0;
28
+ dropped = 0;
29
+ constructor(maxEntries, maxBytes,
30
+ /** Called once per drop event with the running dropped total. */
31
+ onDrop) {
32
+ this.maxEntries = maxEntries;
33
+ this.maxBytes = maxBytes;
34
+ this.onDrop = onDrop;
35
+ }
36
+ get size() { return this.lines.length; }
37
+ get bufferedBytes() { return this.bytes; }
38
+ get droppedEntries() { return this.dropped; }
39
+ /** True when part of the oldest line is already on disk. */
40
+ get hasPartialHead() { return this.headWritten > 0; }
41
+ push(entry, data = encodeEntry(entry)) {
42
+ this.lines.push({
43
+ data, uuid: entry.uuid, parentUuid: entry.parentUuid,
44
+ timestamp: entry.timestamp, state: entry.state, represents: 1,
45
+ });
46
+ this.bytes += data.length;
47
+ this.enforceCaps();
48
+ }
49
+ /** Remove the newest line (an entry whose first write put nothing on disk). */
50
+ popNewest() {
51
+ const line = this.lines.pop();
52
+ if (line)
53
+ this.bytes -= line.data.length;
54
+ }
55
+ /**
56
+ * Append every buffered line with one write loop over a single buffer, then
57
+ * map the bytes written back onto line boundaries. On failure only the
58
+ * unwritten remainder stays buffered.
59
+ */
60
+ writeTo(filePath) {
61
+ if (this.lines.length === 0)
62
+ return;
63
+ const pending = Buffer.concat(this.lines.map(line => line.data));
64
+ let offset = this.headWritten;
65
+ const fd = fs.openSync(filePath, 'a');
66
+ try {
67
+ while (offset < pending.length) {
68
+ const count = fs.writeSync(fd, pending, offset, pending.length - offset);
69
+ if (count <= 0)
70
+ throw new Error(`session journal write made no progress: ${filePath}`);
71
+ offset += count;
72
+ }
73
+ }
74
+ finally {
75
+ this.settle(offset);
76
+ try {
77
+ fs.closeSync(fd);
78
+ }
79
+ catch {
80
+ // The bytes were handed to the kernel already; a write error, if any,
81
+ // is the one worth reporting.
82
+ }
83
+ }
84
+ }
85
+ /** Drop the lines fully covered by `offset` bytes and keep partial progress. */
86
+ settle(offset) {
87
+ let completed = 0;
88
+ let consumed = 0;
89
+ while (completed < this.lines.length && consumed + this.lines[completed].data.length <= offset) {
90
+ consumed += this.lines[completed].data.length;
91
+ completed++;
92
+ }
93
+ if (completed > 0) {
94
+ this.lines.splice(0, completed);
95
+ this.bytes -= consumed;
96
+ }
97
+ this.headWritten = offset - consumed;
98
+ }
99
+ /**
100
+ * Replace the oldest droppable lines with one gap marker until both caps hold.
101
+ * The newest line and a partially written head line are never dropped.
102
+ */
103
+ enforceCaps() {
104
+ const start = this.headWritten > 0 ? 1 : 0;
105
+ const newest = this.lines.length - 1;
106
+ let end = start;
107
+ let removedBytes = 0;
108
+ const over = () => {
109
+ const removed = end - start;
110
+ const marker = removed > 0 ? 1 : 0;
111
+ return this.lines.length - removed + marker > this.maxEntries
112
+ || this.bytes - removedBytes + marker * GAP_MARKER_MAX_BYTES > this.maxBytes;
113
+ };
114
+ if (!over())
115
+ return;
116
+ while (end < newest && over()) {
117
+ removedBytes += this.lines[end].data.length;
118
+ end++;
119
+ }
120
+ // Swapping a single line for a marker frees nothing (caps below 2 lines).
121
+ if (end - start < 2)
122
+ return;
123
+ const run = this.lines.slice(start, end);
124
+ const first = run[0];
125
+ const last = run[run.length - 1];
126
+ const represents = run.reduce((sum, line) => sum + line.represents, 0);
127
+ // An earlier marker inside the run was already counted.
128
+ const newlyDropped = run.filter(line => line.represents === 1).length;
129
+ const gap = { droppedEntries: represents, reason: GAP_REASON };
130
+ const markerEntry = {
131
+ uuid: last.uuid, parentUuid: first.parentUuid, timestamp: last.timestamp,
132
+ type: 'state_change', state: last.state, result: { journalGap: gap },
133
+ };
134
+ const data = encodeEntry(markerEntry);
135
+ this.lines.splice(start, run.length, {
136
+ data, uuid: last.uuid, parentUuid: first.parentUuid,
137
+ timestamp: last.timestamp, state: last.state, represents,
138
+ });
139
+ this.bytes += data.length - removedBytes;
140
+ this.dropped += newlyDropped;
141
+ this.onDrop(this.dropped);
142
+ }
143
+ }
144
+ //# sourceMappingURL=session-write-buffer.js.map
@@ -178,6 +178,11 @@ export interface TestGenerateParams {
178
178
  behaviorExamples?: import('../domains/test-generation/interfaces').BehaviorExample[];
179
179
  aiEnhancement?: boolean;
180
180
  detectAntiPatterns?: boolean;
181
+ /**
182
+ * #925: write a manifest and report under .agentic-qe/results/tests/
183
+ * (default true). false generates without writing any result files.
184
+ */
185
+ saveResults?: boolean;
181
186
  }
182
187
  /**
183
188
  * Test execution parameters
@@ -477,6 +482,10 @@ export interface TestGenerateResult {
477
482
  antiPatternsDetected?: number;
478
483
  suggestions?: string[];
479
484
  savedFiles?: string[];
485
+ /** #925: true when result files were written; see savedFiles for their paths. */
486
+ resultsSaved?: boolean;
487
+ /** #925: plain statement of what was (or was not) written to disk. */
488
+ resultsNote?: string;
480
489
  patternsUsed?: string[];
481
490
  /**
482
491
  * #567: true when the ADR-051 LLM branch actually ran. When false the tests
@@ -7,6 +7,7 @@
7
7
  *
8
8
  * @module memory/crdt/g-counter
9
9
  */
10
+ import { addToCount, createSafeRecord, getOwn, setOwn } from '../../shared/utils/safe-record.js';
10
11
  // =============================================================================
11
12
  // G-Counter Implementation
12
13
  // =============================================================================
@@ -27,12 +28,13 @@
27
28
  export function createGCounter(nodeId) {
28
29
  // Internal state: per-node counts
29
30
  const state = {
30
- counts: {},
31
+ // Node ids are data: keep them off Object.prototype (#914).
32
+ counts: createSafeRecord(),
31
33
  version: 0,
32
34
  lastUpdated: Date.now(),
33
35
  };
34
36
  // Initialize this node's count
35
- state.counts[nodeId] = 0;
37
+ setOwn(state.counts, nodeId, 0);
36
38
  return {
37
39
  get() {
38
40
  // Sum all node counts
@@ -45,7 +47,7 @@ export function createGCounter(nodeId) {
45
47
  if (n === 0) {
46
48
  return;
47
49
  }
48
- state.counts[nodeId] = (state.counts[nodeId] || 0) + n;
50
+ addToCount(state.counts, nodeId, n);
49
51
  state.version++;
50
52
  state.lastUpdated = Date.now();
51
53
  },
@@ -56,7 +58,7 @@ export function createGCounter(nodeId) {
56
58
  getState() {
57
59
  // Return a deep copy to prevent external mutation
58
60
  return {
59
- counts: { ...state.counts },
61
+ counts: Object.assign(createSafeRecord(), state.counts),
60
62
  version: state.version,
61
63
  lastUpdated: state.lastUpdated,
62
64
  };
@@ -65,9 +67,9 @@ export function createGCounter(nodeId) {
65
67
  let changed = false;
66
68
  // Merge counts: take max for each node
67
69
  for (const [incomingNodeId, incomingCount] of Object.entries(incoming.counts)) {
68
- const currentCount = state.counts[incomingNodeId] || 0;
70
+ const currentCount = getOwn(state.counts, incomingNodeId) ?? 0;
69
71
  if (incomingCount > currentCount) {
70
- state.counts[incomingNodeId] = incomingCount;
72
+ setOwn(state.counts, incomingNodeId, incomingCount);
71
73
  changed = true;
72
74
  }
73
75
  }
@@ -80,7 +82,7 @@ export function createGCounter(nodeId) {
80
82
  return nodeId;
81
83
  },
82
84
  getLocalCount() {
83
- return state.counts[nodeId] || 0;
85
+ return getOwn(state.counts, nodeId) ?? 0;
84
86
  },
85
87
  };
86
88
  }
@@ -123,7 +125,7 @@ export function isGCounterState(value) {
123
125
  * Get the count for a specific node from state
124
126
  */
125
127
  export function getNodeCountFromState(state, nodeId) {
126
- return state.counts[nodeId] || 0;
128
+ return getOwn(state.counts, nodeId) ?? 0;
127
129
  }
128
130
  /**
129
131
  * Get all contributing nodes from state
@@ -21,7 +21,7 @@ export declare class OllamaClient {
21
21
  */
22
22
  generateEmbedding(prompt: string): Promise<number[]>;
23
23
  /**
24
- * Fetch with timeout support
24
+ * Keep the request timeout active through required body consumption.
25
25
  */
26
26
  private fetchWithTimeout;
27
27
  /**
@@ -24,24 +24,24 @@ export class OllamaClient {
24
24
  */
25
25
  async healthCheck() {
26
26
  try {
27
- const response = await this.fetchWithTimeout(`${this.baseUrl}/api/tags`, {
27
+ return await this.fetchWithTimeout(`${this.baseUrl}/api/tags`, {
28
28
  method: 'GET',
29
29
  headers: { 'Content-Type': 'application/json' },
30
- }, 5000 // Shorter timeout for health check
31
- );
32
- if (!response.ok) {
30
+ }, 5000, // Shorter timeout for health check
31
+ async (response) => {
32
+ if (!response.ok)
33
+ return false;
34
+ const data = await response.json();
35
+ // Check if configured embedding model is available
36
+ // Match the configured model exactly, allowing its existing tag suffix.
37
+ if (data.models) {
38
+ return data.models.some((model) => model.name === EMBEDDING_CONFIG.MODEL ||
39
+ model.name?.startsWith(`${EMBEDDING_CONFIG.MODEL}:`) ||
40
+ model.model === EMBEDDING_CONFIG.MODEL ||
41
+ model.model?.startsWith(`${EMBEDDING_CONFIG.MODEL}:`));
42
+ }
33
43
  return false;
34
- }
35
- const data = await response.json();
36
- // Check if configured embedding model is available
37
- // Match the configured model exactly, allowing its existing tag suffix.
38
- if (data.models) {
39
- return data.models.some((model) => model.name === EMBEDDING_CONFIG.MODEL ||
40
- model.name?.startsWith(`${EMBEDDING_CONFIG.MODEL}:`) ||
41
- model.model === EMBEDDING_CONFIG.MODEL ||
42
- model.model?.startsWith(`${EMBEDDING_CONFIG.MODEL}:`));
43
- }
44
- return false;
44
+ });
45
45
  }
46
46
  catch {
47
47
  return false;
@@ -58,16 +58,17 @@ export class OllamaClient {
58
58
  let lastError = null;
59
59
  for (let attempt = 0; attempt < this.maxRetries; attempt++) {
60
60
  try {
61
- const response = await this.fetchWithTimeout(`${this.baseUrl}/api/embeddings`, {
61
+ const data = await this.fetchWithTimeout(`${this.baseUrl}/api/embeddings`, {
62
62
  method: 'POST',
63
63
  headers: { 'Content-Type': 'application/json' },
64
64
  body: JSON.stringify(request),
65
- }, this.timeoutMs);
66
- if (!response.ok) {
67
- const errorText = await response.text();
68
- throw new Error(`Ollama API error (${response.status}): ${errorText}`);
69
- }
70
- const data = await response.json();
65
+ }, this.timeoutMs, async (response) => {
66
+ if (!response.ok) {
67
+ const errorText = await response.text();
68
+ throw new Error(`Ollama API error (${response.status}): ${errorText}`);
69
+ }
70
+ return await response.json();
71
+ });
71
72
  // Validate embedding dimensions
72
73
  if (data.embedding.length !== EMBEDDING_CONFIG.DIMENSIONS) {
73
74
  throw new Error(`Invalid embedding dimensions: expected ${EMBEDDING_CONFIG.DIMENSIONS}, got ${data.embedding.length}`);
@@ -90,9 +91,9 @@ export class OllamaClient {
90
91
  throw new Error(`Failed to generate embedding after ${this.maxRetries} attempts: ${lastError?.message}`);
91
92
  }
92
93
  /**
93
- * Fetch with timeout support
94
+ * Keep the request timeout active through required body consumption.
94
95
  */
95
- async fetchWithTimeout(url, options, timeoutMs) {
96
+ async fetchWithTimeout(url, options, timeoutMs, consume) {
96
97
  const controller = new AbortController();
97
98
  const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
98
99
  try {
@@ -100,7 +101,7 @@ export class OllamaClient {
100
101
  ...options,
101
102
  signal: controller.signal,
102
103
  });
103
- return response;
104
+ return await consume(response);
104
105
  }
105
106
  finally {
106
107
  clearTimeout(timeoutId);
@@ -117,14 +118,12 @@ export class OllamaClient {
117
118
  */
118
119
  async getServerInfo() {
119
120
  try {
120
- const response = await this.fetchWithTimeout(`${this.baseUrl}/api/tags`, {
121
+ return await this.fetchWithTimeout(`${this.baseUrl}/api/tags`, {
121
122
  method: 'GET',
122
123
  headers: { 'Content-Type': 'application/json' },
123
- }, 5000);
124
- if (!response.ok) {
125
- return null;
126
- }
127
- return await response.json();
124
+ }, 5000, async (response) => response.ok
125
+ ? await response.json()
126
+ : null);
128
127
  }
129
128
  catch {
130
129
  return null;
@@ -102,8 +102,11 @@ export declare class GitAnalyzer {
102
102
  getChangedFiles(since?: Date): Promise<string[]>;
103
103
  /**
104
104
  * Get files changed in a specific commit
105
- * @param commitHash - Git commit hash (default: HEAD)
105
+ * @param commitHash - Git revision (SHA, `HEAD~3`, `origin/main`, tag; default: HEAD)
106
106
  * @returns Array of changed file paths relative to repo root
107
+ * @throws Error when `commitHash` is option-shaped (starts with "-") or otherwise
108
+ * not a safe revision argument; git would otherwise parse it as an option
109
+ * (e.g. `--output=<path>` writes an arbitrary file). See issue #960.
107
110
  */
108
111
  getCommitFiles(commitHash?: string): Promise<string[]>;
109
112
  /**
@@ -10,6 +10,7 @@
10
10
  */
11
11
  import { execFileSync } from 'child_process';
12
12
  import * as path from 'path';
13
+ import { assertSafeGitRef } from './ref-validation.js';
13
14
  /**
14
15
  * Sanitize a string for safe use in git arguments
15
16
  * Removes shell metacharacters that could enable injection
@@ -432,18 +433,22 @@ export class GitAnalyzer {
432
433
  }
433
434
  /**
434
435
  * Get files changed in a specific commit
435
- * @param commitHash - Git commit hash (default: HEAD)
436
+ * @param commitHash - Git revision (SHA, `HEAD~3`, `origin/main`, tag; default: HEAD)
436
437
  * @returns Array of changed file paths relative to repo root
438
+ * @throws Error when `commitHash` is option-shaped (starts with "-") or otherwise
439
+ * not a safe revision argument; git would otherwise parse it as an option
440
+ * (e.g. `--output=<path>` writes an arbitrary file). See issue #960.
437
441
  */
438
442
  async getCommitFiles(commitHash = 'HEAD') {
443
+ // Validate before touching git: execFileSync has no shell, so stripping
444
+ // metacharacters does not help, but a leading "-" is still parsed as an option.
445
+ assertSafeGitRef(commitHash, 'commit hash');
439
446
  if (!(await this.isGitRepository())) {
440
447
  return [];
441
448
  }
442
449
  try {
443
- // Sanitize commit hash to prevent injection
444
- const sanitizedHash = sanitizeGitArg(commitHash);
445
450
  const output = execFileSync('git', [
446
- 'diff-tree', '--no-commit-id', '--name-only', '-z', '-r', sanitizedHash
451
+ 'diff-tree', '--root', '--no-commit-id', '--name-only', '-z', '-r', commitHash
447
452
  ], {
448
453
  cwd: this.config.repoRoot,
449
454
  encoding: 'utf-8',