agentic-qe 3.15.2 → 3.15.4

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 (445) 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 +155 -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-T54G3TBK.js +2 -0
  10. package/dist/cli/chunks/{agent-booster-wasm-664M7426.js → agent-booster-wasm-MHJBRXMK.js} +2 -2
  11. package/dist/cli/chunks/{agent-handler-E47ITH45.js → agent-handler-G64SD7J2.js} +2 -2
  12. package/dist/cli/chunks/{agent-memory-branch-CFWVOJX3.js → agent-memory-branch-G4UXFPKH.js} +2 -2
  13. package/dist/cli/chunks/aqe-learning-engine-HLCJJ3JM.js +2 -0
  14. package/dist/cli/chunks/{arena-ZU5CGBGH.js → arena-63M3M6EW.js} +2 -2
  15. package/dist/cli/chunks/{arena-JM3OY263.js → arena-QJMKYPHS.js} +4 -4
  16. package/dist/cli/chunks/{audit-HVBRC5AS.js → audit-UDFVTWSX.js} +3 -3
  17. package/dist/cli/chunks/base-VLD755UU.js +2 -0
  18. package/dist/cli/chunks/{better-sqlite3-45JLBQX3.js → better-sqlite3-JLX2G56I.js} +2 -2
  19. package/dist/cli/chunks/{brain-handler-FKDONZYA.js → brain-handler-PWF32LLW.js} +3 -3
  20. package/dist/cli/chunks/{branch-enumerator-M3DPS3D5.js → branch-enumerator-PB7QWXDP.js} +2 -2
  21. package/dist/cli/chunks/{browser-TG2TV6NR.js → browser-CYNV2F3U.js} +2 -2
  22. package/dist/cli/chunks/browser-workflow-6M6VLWRF.js +2 -0
  23. package/dist/cli/chunks/{chunk-JFFVYCTV.js → chunk-2534PXIV.js} +2 -2
  24. package/dist/cli/chunks/{chunk-GHXNRF63.js → chunk-2DRMTRBM.js} +2 -2
  25. package/dist/cli/chunks/{chunk-L77Z3Q6L.js → chunk-2ICC4H6K.js} +2 -2
  26. package/dist/cli/chunks/{chunk-EATZW5T2.js → chunk-2LL35V3A.js} +2 -2
  27. package/dist/cli/chunks/{chunk-MEUJWTOX.js → chunk-2MU4WCMQ.js} +2 -2
  28. package/dist/cli/chunks/{chunk-3RC5UMRJ.js → chunk-33IUCP34.js} +2 -2
  29. package/dist/cli/chunks/{chunk-UX4BOI6K.js → chunk-35A22AUL.js} +1 -1
  30. package/dist/cli/chunks/{chunk-Z7XCXHEB.js → chunk-3BDDOFYW.js} +2 -2
  31. package/dist/cli/chunks/chunk-3C2BFLYC.js +54 -0
  32. package/dist/cli/chunks/{chunk-56CE7UO4.js → chunk-3MSBVOYW.js} +6 -6
  33. package/dist/cli/chunks/{chunk-EDRIROCG.js → chunk-3ZIVBTX6.js} +2 -2
  34. package/dist/cli/chunks/{chunk-CRYZXTSQ.js → chunk-4GLR2S2M.js} +2 -2
  35. package/dist/cli/chunks/{chunk-DHSGCI6H.js → chunk-54ITMOFM.js} +6 -6
  36. package/dist/cli/chunks/{chunk-2AWU2E6R.js → chunk-54XTJBHV.js} +1 -1
  37. package/dist/cli/chunks/{chunk-JSTKSPYT.js → chunk-5B5D5KCV.js} +1 -1
  38. package/dist/cli/chunks/{chunk-NP2WWIZ3.js → chunk-5GWTJJEO.js} +1 -1
  39. package/dist/cli/chunks/{chunk-D75HDHX3.js → chunk-5H7MR6HP.js} +1 -1
  40. package/dist/cli/chunks/{chunk-NWYAV2UG.js → chunk-5SS2Z7JC.js} +2 -2
  41. package/dist/cli/chunks/chunk-5XXLWJU7.js +2 -0
  42. package/dist/cli/chunks/{chunk-B4H66LPR.js → chunk-6EHVPFHW.js} +1 -1
  43. package/dist/cli/chunks/{chunk-HSXLHNSS.js → chunk-6HO3XRXE.js} +2 -2
  44. package/dist/cli/chunks/chunk-6HTO4BLV.js +2 -0
  45. package/dist/cli/chunks/{chunk-SVHFSOGT.js → chunk-6QPW4OVH.js} +1 -1
  46. package/dist/cli/chunks/{chunk-BKZSTZDB.js → chunk-6TMUZGM2.js} +1 -1
  47. package/dist/cli/chunks/{chunk-2AOAEMJG.js → chunk-73MTUM6F.js} +2 -2
  48. package/dist/cli/chunks/{chunk-ANI3KPB7.js → chunk-73PCVMGA.js} +2 -2
  49. package/dist/cli/chunks/{chunk-HADOG2PT.js → chunk-76PRW2KY.js} +2 -2
  50. package/dist/cli/chunks/{chunk-NL6HKEPR.js → chunk-7INP6HZH.js} +3 -3
  51. package/dist/cli/chunks/{chunk-QB7H62A4.js → chunk-7X2IVMXN.js} +2 -2
  52. package/dist/cli/chunks/{chunk-ZVQSIH7Y.js → chunk-A4OPQJ4A.js} +8 -8
  53. package/dist/cli/chunks/{chunk-SKQTRYE7.js → chunk-ADF6LGHZ.js} +2 -2
  54. package/dist/cli/chunks/{chunk-5YS2DF5G.js → chunk-AHVN3UQZ.js} +2 -2
  55. package/dist/cli/chunks/{chunk-3XF7YTQC.js → chunk-AOKSLWON.js} +54 -54
  56. package/dist/cli/chunks/{chunk-CFDIYZGA.js → chunk-ASKPTGUU.js} +2 -2
  57. package/dist/cli/chunks/{chunk-LH3H4V7C.js → chunk-B7GJXQD2.js} +2 -2
  58. package/dist/cli/chunks/{chunk-HOBBYORR.js → chunk-B7J3O2WM.js} +1 -1
  59. package/dist/cli/chunks/{chunk-J4EJMAH3.js → chunk-BBKLVHDQ.js} +1 -1
  60. package/dist/cli/chunks/{chunk-WMNVFCKY.js → chunk-BND6M2JX.js} +2 -2
  61. package/dist/cli/chunks/{chunk-LRVR56PD.js → chunk-BPGFCUDO.js} +1 -1
  62. package/dist/cli/chunks/{chunk-O6QTCUSL.js → chunk-BY3IL56R.js} +1 -1
  63. package/dist/cli/chunks/{chunk-3KXKJSKS.js → chunk-BY5PLEPZ.js} +32 -32
  64. package/dist/cli/chunks/{chunk-DGKPGRBT.js → chunk-BZWZTGMF.js} +2 -2
  65. package/dist/cli/chunks/{chunk-AS27JP67.js → chunk-C5EN5WB6.js} +1 -1
  66. package/dist/cli/chunks/chunk-CFXFGQEN.js +15 -0
  67. package/dist/cli/chunks/{chunk-X4CADOSD.js → chunk-CQ3WSTJ2.js} +2 -2
  68. package/dist/cli/chunks/{chunk-HFF5ERIE.js → chunk-D7RVZ5C2.js} +2 -2
  69. package/dist/cli/chunks/{chunk-HS3O763N.js → chunk-DAYMT7TH.js} +21 -21
  70. package/dist/cli/chunks/{chunk-W6PLBRRS.js → chunk-DBIK4OFX.js} +1 -1
  71. package/dist/cli/chunks/{chunk-OWZ3F7DJ.js → chunk-DEJM2P5K.js} +1 -1
  72. package/dist/cli/chunks/{chunk-TC4B5D4Z.js → chunk-DF4Y3HPO.js} +1 -1
  73. package/dist/cli/chunks/{chunk-7UA7SMM4.js → chunk-DFJGXXCL.js} +1 -1
  74. package/dist/cli/chunks/{chunk-SZYK5JL7.js → chunk-DPL4ZXTE.js} +1 -1
  75. package/dist/cli/chunks/{chunk-6WVEICL2.js → chunk-DVE5SM5G.js} +4 -4
  76. package/dist/cli/chunks/{chunk-QR5ILM34.js → chunk-EGHK6NMH.js} +2 -2
  77. package/dist/cli/chunks/{chunk-E6GANSLP.js → chunk-EWUFVWRT.js} +2 -2
  78. package/dist/cli/chunks/{chunk-HBMBO4FD.js → chunk-EY5IUF7U.js} +2 -2
  79. package/dist/cli/chunks/{chunk-JCB6K24D.js → chunk-FDK2GF4G.js} +2 -2
  80. package/dist/cli/chunks/{chunk-QZNFZ5IQ.js → chunk-FRBCX46J.js} +2 -2
  81. package/dist/cli/chunks/{chunk-FCMCQ6OX.js → chunk-G3ZUB3HD.js} +2 -2
  82. package/dist/cli/chunks/{chunk-QGCFMACF.js → chunk-GAXTPQCZ.js} +2 -2
  83. package/dist/cli/chunks/{chunk-6O4KVU4K.js → chunk-GJVRQBLI.js} +2 -2
  84. package/dist/cli/chunks/{chunk-NLY5NUHZ.js → chunk-GLKLEHK3.js} +2 -2
  85. package/dist/cli/chunks/{chunk-IM67YHDK.js → chunk-HCDTLV5J.js} +2 -2
  86. package/dist/cli/chunks/{chunk-MY2XZHW3.js → chunk-HEDLZWPM.js} +1 -1
  87. package/dist/cli/chunks/{chunk-WUSSZ2S6.js → chunk-HEKCN5XQ.js} +2 -2
  88. package/dist/cli/chunks/{chunk-FRZVLRVR.js → chunk-HFSBONCS.js} +2 -2
  89. package/dist/cli/chunks/{chunk-IAOB2G3X.js → chunk-HX5KQK7I.js} +2 -2
  90. package/dist/cli/chunks/{chunk-BT6TZTCL.js → chunk-I43QRLLB.js} +2 -2
  91. package/dist/cli/chunks/{chunk-QJN5RW2U.js → chunk-I53365HG.js} +3 -3
  92. package/dist/cli/chunks/{chunk-55T7PDYP.js → chunk-I5A3HGO6.js} +2 -2
  93. package/dist/cli/chunks/{chunk-AR5V7VNC.js → chunk-I6E4X3L3.js} +1 -1
  94. package/dist/cli/chunks/chunk-IKWAPHJA.js +2 -0
  95. package/dist/cli/chunks/{chunk-UKRK3IE3.js → chunk-ISASRHZP.js} +2 -2
  96. package/dist/cli/chunks/{chunk-IHKRKRAV.js → chunk-J3RNVHDH.js} +1 -1
  97. package/dist/cli/chunks/{chunk-T75PWWK4.js → chunk-JFQDWAU3.js} +2 -2
  98. package/dist/cli/chunks/{chunk-3KTAMNKI.js → chunk-JL3TI43V.js} +2 -2
  99. package/dist/cli/chunks/{chunk-3DCRAW43.js → chunk-K2VUYRMG.js} +2 -2
  100. package/dist/cli/chunks/{chunk-RIAKRZCZ.js → chunk-KOLHZSEC.js} +2 -2
  101. package/dist/cli/chunks/{chunk-HXT4XDQO.js → chunk-LGA6J4I4.js} +2 -2
  102. package/dist/cli/chunks/{chunk-MDDECCAC.js → chunk-LJRZAALA.js} +169 -168
  103. package/dist/cli/chunks/{chunk-2B2MGJ2W.js → chunk-LOLAEDZD.js} +2 -2
  104. package/dist/cli/chunks/{chunk-2JEPRQMT.js → chunk-LPSE6DOQ.js} +1 -1
  105. package/dist/cli/chunks/{chunk-6KEYA4EH.js → chunk-LRTF5RMG.js} +4 -4
  106. package/dist/cli/chunks/{chunk-CV7E627D.js → chunk-LXYTC62V.js} +2 -2
  107. package/dist/cli/chunks/{chunk-YYVLMW65.js → chunk-LY53L6NH.js} +2 -2
  108. package/dist/cli/chunks/{chunk-HMDSBWF6.js → chunk-LZSLJJII.js} +2 -2
  109. package/dist/cli/chunks/{chunk-IT753IPZ.js → chunk-M6SJALLA.js} +2 -2
  110. package/dist/cli/chunks/{chunk-GDSLQTJC.js → chunk-MBV57LKC.js} +2 -2
  111. package/dist/cli/chunks/{chunk-I7J2ESGR.js → chunk-MGH4XIHH.js} +2 -2
  112. package/dist/cli/chunks/{chunk-Q32UGPWK.js → chunk-MVTUFPM2.js} +2 -2
  113. package/dist/cli/chunks/{chunk-UZL4JYVW.js → chunk-N6CRIUTO.js} +2 -2
  114. package/dist/cli/chunks/{chunk-326V7N25.js → chunk-NBMQOP2R.js} +1 -1
  115. package/dist/cli/chunks/{chunk-ZIKH7U5A.js → chunk-NIJMLEAX.js} +2 -2
  116. package/dist/cli/chunks/{chunk-MYDZBABD.js → chunk-O7TMY4GS.js} +2 -2
  117. package/dist/cli/chunks/{chunk-LVDZ25VX.js → chunk-OFQDM73J.js} +2 -2
  118. package/dist/cli/chunks/{chunk-WBZIOTY6.js → chunk-OG4KHX7S.js} +2 -2
  119. package/dist/cli/chunks/{chunk-GJTH6VBH.js → chunk-OHH6BUZK.js} +1 -1
  120. package/dist/cli/chunks/{chunk-T5N2PIPS.js → chunk-OOK6GPJR.js} +2 -2
  121. package/dist/cli/chunks/{chunk-AXJ75X6I.js → chunk-P7GM3EE7.js} +1 -1
  122. package/dist/cli/chunks/{chunk-IQB5ZBYO.js → chunk-PB2WSCBW.js} +3 -3
  123. package/dist/cli/chunks/{chunk-M36DAETL.js → chunk-PCWZCXBD.js} +2 -2
  124. package/dist/cli/chunks/{chunk-Z3PANQUT.js → chunk-PEA4DVXW.js} +1 -1
  125. package/dist/cli/chunks/{chunk-WBCE6V2N.js → chunk-PJAXWCFC.js} +1 -1
  126. package/dist/cli/chunks/{chunk-V67UQRQN.js → chunk-PMXWDTDK.js} +2 -2
  127. package/dist/cli/chunks/chunk-QIAX3JJB.js +3 -0
  128. package/dist/cli/chunks/chunk-R47LNH5W.js +2 -0
  129. package/dist/cli/chunks/{chunk-A6L2OCMO.js → chunk-RA3MI5WK.js} +2 -2
  130. package/dist/cli/chunks/{chunk-ITM26I6O.js → chunk-RB2SL5GD.js} +2 -2
  131. package/dist/cli/chunks/{chunk-XQBH3366.js → chunk-RG67RZIX.js} +2 -2
  132. package/dist/cli/chunks/{chunk-NBV37CEK.js → chunk-RI4JPBZD.js} +2 -2
  133. package/dist/cli/chunks/{chunk-2Q4Y3VQ6.js → chunk-RJ5CZ7B6.js} +2 -2
  134. package/dist/cli/chunks/{chunk-ATGIGJSL.js → chunk-RJMBHZYL.js} +1 -1
  135. package/dist/cli/chunks/{chunk-MOSXT6AO.js → chunk-RWZ4F44Y.js} +2 -2
  136. package/dist/cli/chunks/{chunk-URWT3EQT.js → chunk-S5D3HCGN.js} +2 -2
  137. package/dist/cli/chunks/{chunk-KQMCCHPO.js → chunk-SCL2OYN7.js} +2 -2
  138. package/dist/cli/chunks/{chunk-Y5VPLOA7.js → chunk-SIUUAKCE.js} +1 -1
  139. package/dist/cli/chunks/{chunk-JIRX6KUR.js → chunk-SJB4KMZS.js} +3 -3
  140. package/dist/cli/chunks/{chunk-TZH2QAFZ.js → chunk-SOSJFEFB.js} +2 -2
  141. package/dist/cli/chunks/{chunk-IBAXNCR2.js → chunk-SZWXUG36.js} +2 -2
  142. package/dist/cli/chunks/{chunk-KTLYL3BS.js → chunk-T3BMCEQR.js} +2 -2
  143. package/dist/cli/chunks/chunk-TB22Y3WW.js +4 -0
  144. package/dist/cli/chunks/{chunk-GJ7DON5S.js → chunk-TVQPYP2Z.js} +3 -3
  145. package/dist/cli/chunks/chunk-U2E5F3VZ.js +14 -0
  146. package/dist/cli/chunks/{chunk-ZSKQPXRW.js → chunk-UK5HY6LC.js} +1 -1
  147. package/dist/cli/chunks/{chunk-RO6HAZLV.js → chunk-UORI2CZ4.js} +1 -1
  148. package/dist/cli/chunks/{chunk-VTGAPHJE.js → chunk-V3NZ23X6.js} +2 -2
  149. package/dist/cli/chunks/{chunk-W7P7EOJ4.js → chunk-VAXQUD5G.js} +1 -1
  150. package/dist/cli/chunks/{chunk-EQG3JYSV.js → chunk-VMSO6DMF.js} +2 -2
  151. package/dist/cli/chunks/{chunk-6UO5YSNN.js → chunk-W3PPYNHF.js} +2 -2
  152. package/dist/cli/chunks/{chunk-FH6N2LKG.js → chunk-W6TJXK5Y.js} +2 -2
  153. package/dist/cli/chunks/{chunk-WJ7657IX.js → chunk-WEDVLKRB.js} +2 -2
  154. package/dist/cli/chunks/{chunk-N653RGT3.js → chunk-WI5AEB7Q.js} +2 -2
  155. package/dist/cli/chunks/{chunk-W5EKSBS4.js → chunk-WO4NSPLX.js} +2 -2
  156. package/dist/cli/chunks/{chunk-YH7VOLBP.js → chunk-WW6WUMS7.js} +2 -2
  157. package/dist/cli/chunks/{chunk-6OL2WES5.js → chunk-WYO5VN2L.js} +1 -1
  158. package/dist/cli/chunks/{chunk-PZK7O445.js → chunk-X5S5UEM6.js} +2 -2
  159. package/dist/cli/chunks/{chunk-NKWMTXBL.js → chunk-XHCCH7UC.js} +3 -3
  160. package/dist/cli/chunks/{chunk-GSC6JXDE.js → chunk-XKIFNKHV.js} +1 -1
  161. package/dist/cli/chunks/{chunk-FNPZINHV.js → chunk-XZ5Z56OP.js} +1 -1
  162. package/dist/cli/chunks/{chunk-6XLCFDIB.js → chunk-YQ6BK7QC.js} +2 -2
  163. package/dist/cli/chunks/{chunk-DNS37AHW.js → chunk-YUWUFYHK.js} +1 -1
  164. package/dist/cli/chunks/{chunk-YJSKT6G6.js → chunk-YZ2AGC7O.js} +1 -1
  165. package/dist/cli/chunks/{chunk-5TEPPW4J.js → chunk-Z56QTRRB.js} +2 -2
  166. package/dist/cli/chunks/{chunk-4MCO43NX.js → chunk-ZAOQIVHG.js} +4 -4
  167. package/dist/cli/chunks/{chunk-TMYGGYRY.js → chunk-ZF5JTQEE.js} +1 -1
  168. package/dist/cli/chunks/{chunk-HYWW4A2E.js → chunk-ZKXZTIVF.js} +2 -2
  169. package/dist/cli/chunks/{chunk-N4MNSEKY.js → chunk-ZP6ANUP7.js} +1 -1
  170. package/dist/cli/chunks/{chunk-5DFPAJ5O.js → chunk-ZURYZEHX.js} +2 -2
  171. package/dist/cli/chunks/{ci-JNBOR6FP.js → ci-NGMGB43T.js} +3 -3
  172. package/dist/cli/chunks/{ci-output-FYNKONEQ.js → ci-output-BMJABAEX.js} +2 -2
  173. package/dist/cli/chunks/{circuit-breaker-KOIXRDAD.js → circuit-breaker-GYD5CMJQ.js} +2 -2
  174. package/dist/cli/chunks/{claude-flow-setup-4CO7KHRN.js → claude-flow-setup-MMOYVBVD.js} +2 -2
  175. package/dist/cli/chunks/client-FUHNNK5O.js +2 -0
  176. package/dist/cli/chunks/{cline-installer-CMYAPKK5.js → cline-installer-B2SOZ44R.js} +2 -2
  177. package/dist/cli/chunks/{code-WFIAEP3H.js → code-V3FIRAXD.js} +3 -3
  178. package/dist/cli/chunks/{code-index-extractor-IYM6HWJN.js → code-index-extractor-CV6A756Z.js} +2 -2
  179. package/dist/cli/chunks/{codex-installer-DORVWRSU.js → codex-installer-EUC6J47Y.js} +2 -2
  180. package/dist/cli/chunks/{completions-54VM2MX2.js → completions-DQQIBAHR.js} +2 -2
  181. package/dist/cli/chunks/{complexity-analyzer-EGZDP5N4.js → complexity-analyzer-HPXMXP5I.js} +2 -2
  182. package/dist/cli/chunks/{continuedev-installer-4SDVDD4T.js → continuedev-installer-RCIYXH6V.js} +2 -2
  183. package/dist/cli/chunks/{copilot-installer-7FJQ7PCL.js → copilot-installer-VUH32SHF.js} +2 -2
  184. package/dist/cli/chunks/core-handlers-F7TLX4LM.js +2 -0
  185. package/dist/cli/chunks/cost-tracker-YLCKLOAL.js +2 -0
  186. package/dist/cli/chunks/{coverage-DI5LDRJ7.js → coverage-IVKDV236.js} +3 -3
  187. package/dist/cli/chunks/cross-domain-router-EGWPY67O.js +2 -0
  188. package/dist/cli/chunks/{cursor-installer-RTSZP5YD.js → cursor-installer-B42FN62K.js} +2 -2
  189. package/dist/cli/chunks/{daemon-SP3APEZY.js → daemon-DECQRQII.js} +3 -3
  190. package/dist/cli/chunks/{daemon-LM7LETPV.js → daemon-IPTOSCHM.js} +4 -4
  191. package/dist/cli/chunks/{dag-attention-scheduler-C3QBODFE.js → dag-attention-scheduler-RY7CDYSC.js} +2 -2
  192. package/dist/cli/chunks/{detect-I4RBUFFJ.js → detect-NW53BMJN.js} +2 -2
  193. package/dist/cli/chunks/{dist-node-PT6TCBCO.js → dist-node-LE6KHXAB.js} +2 -2
  194. package/dist/cli/chunks/{domain-handler-MJMTMB5X.js → domain-handler-JGXFT4LW.js} +2 -2
  195. package/dist/cli/chunks/{domain-plugins-Y4A2WYJW.js → domain-plugins-GY3RYKKK.js} +2 -2
  196. package/dist/cli/chunks/{domain-transfer-DUO42TLA.js → domain-transfer-CGBRXNTC.js} +2 -2
  197. package/dist/cli/chunks/dream-V4QN6OF5.js +2 -0
  198. package/dist/cli/chunks/{embed-and-insert-pattern-66ZQK4AI.js → embed-and-insert-pattern-65H4XHWR.js} +2 -2
  199. package/dist/cli/chunks/{eval-NQ7H27UF.js → eval-YPYIZQUR.js} +2 -2
  200. package/dist/cli/chunks/{experience-capture-middleware-MHEYPTIG.js → experience-capture-middleware-4JXVF5PL.js} +3 -3
  201. package/dist/cli/chunks/{fast-paths-YYDGN6ZC.js → fast-paths-HYQTAF2S.js} +2 -2
  202. package/dist/cli/chunks/{feature-flags-FY4DOYS2.js → feature-flags-HNSAFFX2.js} +2 -2
  203. package/dist/cli/chunks/{feature-flags-YFGUORHY.js → feature-flags-YACUH6OW.js} +2 -2
  204. package/dist/cli/chunks/{file-discovery-TOMDY7TK.js → file-discovery-R73BYEXB.js} +2 -2
  205. package/dist/cli/chunks/{fleet-MO3UCWB4.js → fleet-6M3BP4OO.js} +3 -3
  206. package/dist/cli/chunks/{gnn-wrapper-SLW4PPXQ.js → gnn-wrapper-QLD7KHXV.js} +2 -2
  207. package/dist/cli/chunks/{heartbeat-handler-36RFCP4E.js → heartbeat-handler-EZP333X4.js} +4 -4
  208. package/dist/cli/chunks/heartbeat-scheduler-3N3L6CRM.js +2 -0
  209. package/dist/cli/chunks/hnsw-adapter-2BXJYDXI.js +2 -0
  210. package/dist/cli/chunks/hnsw-index-2DLI5OVO.js +2 -0
  211. package/dist/cli/chunks/{hnsw-legacy-bridge-BJLWBKHE.js → hnsw-legacy-bridge-47CUCSAU.js} +2 -2
  212. package/dist/cli/chunks/{hnswlib-node-RAYNVJCJ.js → hnswlib-node-SVNYDJZH.js} +2 -2
  213. package/dist/cli/chunks/{hooks-JMHFWVEQ.js → hooks-6V5LMWP6.js} +10 -10
  214. package/dist/cli/chunks/hybrid-backend-OW4J65YH.js +2 -0
  215. package/dist/cli/chunks/{hypergraph-engine-JUDBKPOX.js → hypergraph-engine-L2FOBIFF.js} +2 -2
  216. package/dist/cli/chunks/{hypergraph-handler-AXTWXOZU.js → hypergraph-handler-DU6Z57EE.js} +3 -3
  217. package/dist/cli/chunks/impact-analyzer-ZH5I2RG6.js +2 -0
  218. package/dist/cli/chunks/{init-handler-PARJNZFF.js → init-handler-HETPWU67.js} +6 -6
  219. package/dist/cli/chunks/init-wizard-NIKM3ZOK.js +2 -0
  220. package/dist/cli/chunks/kernel-2EOSVM6X.js +2 -0
  221. package/dist/cli/chunks/{kilocode-installer-22HX2E4V.js → kilocode-installer-NHKYGJ7Q.js} +2 -2
  222. package/dist/cli/chunks/{kiro-installer-OVPBLY7J.js → kiro-installer-24UK6GGR.js} +2 -2
  223. package/dist/cli/chunks/knowledge-graph-D3BPWNNO.js +2 -0
  224. package/dist/cli/chunks/{learning-DWXPJ3R6.js → learning-QLVRZNHT.js} +3 -3
  225. package/dist/cli/chunks/{llm-router-7PPVVKNG.js → llm-router-XRMI2VMG.js} +4 -4
  226. package/dist/cli/chunks/llm-router-service-TJPPZFUN.js +2 -0
  227. package/dist/cli/chunks/{load-VI5XHNZA.js → load-W5UWL5C7.js} +2 -2
  228. package/dist/cli/chunks/load-test-RFT7IDOL.js +2 -0
  229. package/dist/cli/chunks/{mcp-UW4Z3Z64.js → mcp-N7ALQ4BL.js} +2 -2
  230. package/dist/cli/chunks/{memory-UD2KCB5M.js → memory-WV52DLSA.js} +5 -5
  231. package/dist/cli/chunks/memory-backend-O2O4CFKZ.js +2 -0
  232. package/dist/cli/chunks/memory-handlers-DAEGUDBD.js +2 -0
  233. package/dist/cli/chunks/{multi-model-executor-5O4WWU5Z.js → multi-model-executor-3FVTZCSO.js} +2 -2
  234. package/dist/cli/chunks/{opencode-installer-DTRFDGM7.js → opencode-installer-NTPWGHUW.js} +2 -2
  235. package/dist/cli/chunks/{orchestrator-ENJIKV6Z.js → orchestrator-ORGJ6VAA.js} +85 -26
  236. package/dist/cli/chunks/pattern-null-store-TUBNXS34.js +2 -0
  237. package/dist/cli/chunks/{pattern-usage-recorder-QPNIU5PD.js → pattern-usage-recorder-WWXHUH5U.js} +2 -2
  238. package/dist/cli/chunks/{pipeline-G3JYDNPE.js → pipeline-ZOKZFXTH.js} +2 -2
  239. package/dist/cli/chunks/{platform-P4WR6N3D.js → platform-CDNL322F.js} +2 -2
  240. package/dist/cli/chunks/{plugin-C7763Q5W.js → plugin-ZVLFNZZ4.js} +2 -2
  241. package/dist/cli/chunks/{prime-radiant-advanced-wasm-DH6R3XSZ.js → prime-radiant-advanced-wasm-FVJDU2JY.js} +2 -2
  242. package/dist/cli/chunks/{project-root-7DTXDLEG.js → project-root-UCHQH3QL.js} +2 -2
  243. package/dist/cli/chunks/protocol-executor-6FQTTO3Y.js +2 -0
  244. package/dist/cli/chunks/{protocol-handler-EODULGOZ.js → protocol-handler-4YBN5R23.js} +2 -2
  245. package/dist/cli/chunks/{prove-A7G3SIOF.js → prove-BHDHY664.js} +2 -2
  246. package/dist/cli/chunks/qe-reasoning-bank-TKPND56C.js +2 -0
  247. package/dist/cli/chunks/{quality-JTURFUX3.js → quality-46AK277P.js} +2 -2
  248. package/dist/cli/chunks/{quality-gate-M2EI754V.js → quality-gate-WANE7TCN.js} +3 -3
  249. package/dist/cli/chunks/queen-coordinator-DWMXLPJG.js +2 -0
  250. package/dist/cli/chunks/{real-embeddings-DI7JMCG7.js → real-embeddings-56MNGJGJ.js} +2 -2
  251. package/dist/cli/chunks/{ref-validation-MSFMNKDR.js → ref-validation-S7UWXQIP.js} +2 -2
  252. package/dist/cli/chunks/{roocode-installer-XIMFFHOH.js → roocode-installer-TEYOQYL6.js} +2 -2
  253. package/dist/cli/chunks/router-QIMUYRCC.js +2 -0
  254. package/dist/cli/chunks/routing-feedback-4OH5ZNF4.js +2 -0
  255. package/dist/cli/chunks/{routing-handler-MCDKNBQW.js → routing-handler-KDTLMRWD.js} +2 -2
  256. package/dist/cli/chunks/{ruvector-commands-OBSYAK2X.js → ruvector-commands-AOUDXCYE.js} +2 -2
  257. package/dist/cli/chunks/rvf-dual-writer-S6JBZL54.js +2 -0
  258. package/dist/cli/chunks/rvf-migration-adapter-TSGMLMYR.js +2 -0
  259. package/dist/cli/chunks/{rvf-migration-coordinator-4DTRIHY6.js → rvf-migration-coordinator-V74MVBHS.js} +2 -2
  260. package/dist/cli/chunks/rvf-native-adapter-Z7QOW47S.js +2 -0
  261. package/dist/cli/chunks/{rvf-store-integrity-CWAVMRC4.js → rvf-store-integrity-QI47Y354.js} +2 -2
  262. package/dist/cli/chunks/safe-db-JLOVBJNC.js +2 -0
  263. package/dist/cli/chunks/schedule-IM6XOBGR.js +2 -0
  264. package/dist/cli/chunks/scheduler-XL2SVVK5.js +2 -0
  265. package/dist/cli/chunks/{security-74TWSO74.js → security-SN6MWOJT.js} +3 -3
  266. package/dist/cli/chunks/{shared-rvf-adapter-ZHNAGE5H.js → shared-rvf-adapter-2LB56LP4.js} +2 -2
  267. package/dist/cli/chunks/{shared-rvf-dual-writer-BS5WAVCC.js → shared-rvf-dual-writer-WU7PFKQM.js} +2 -2
  268. package/dist/cli/chunks/sqlite-persistence-LWMIIC4U.js +2 -0
  269. package/dist/cli/chunks/{standalone-memory-3HGHTE7S.js → standalone-memory-F6FSRFWC.js} +2 -2
  270. package/dist/cli/chunks/{status-handler-XWEEGNGH.js → status-handler-DHD5MS4G.js} +2 -2
  271. package/dist/cli/chunks/{structural-health-TB5JGMVS.js → structural-health-P6HPSQMR.js} +2 -2
  272. package/dist/cli/chunks/{sync-T4VLBURM.js → sync-LISJGDSE.js} +2 -2
  273. package/dist/cli/chunks/sync-SNAXAVCN.js +2 -0
  274. package/dist/cli/chunks/{task-handler-RQ65QKXX.js → task-handler-ZT44NT5Z.js} +2 -2
  275. package/dist/cli/chunks/{task-handlers-USYWJ4H2.js → task-handlers-R6DQ5324.js} +3 -3
  276. package/dist/cli/chunks/test-MUFHR4JQ.js +34 -0
  277. package/dist/cli/chunks/test-scheduling-TAUSLZJP.js +15 -0
  278. package/dist/cli/chunks/token-bootstrap-UGRH7OPU.js +2 -0
  279. package/dist/cli/chunks/{token-usage-CISTB5K5.js → token-usage-IX65ECBR.js} +2 -2
  280. package/dist/cli/chunks/{transformers-C7LV763N.js → transformers-QKPSVW2W.js} +2 -2
  281. package/dist/cli/chunks/{tree-sitter-wasm-parser-P26JC3YV.js → tree-sitter-wasm-parser-Z7PPA2JO.js} +2 -2
  282. package/dist/cli/chunks/{types-YMVMKIWB.js → types-ULNNGGGH.js} +2 -2
  283. package/dist/cli/chunks/unified-memory-F5IJY7W7.js +2 -0
  284. package/dist/cli/chunks/unified-memory-hnsw-C3WAMAQL.js +2 -0
  285. package/dist/cli/chunks/unified-persistence-EWXXOTCB.js +2 -0
  286. package/dist/cli/chunks/{upgrade-U2REOPAW.js → upgrade-ECI3YUYA.js} +2 -2
  287. package/dist/cli/chunks/{validate-NDTCKN7P.js → validate-3JKRUW2S.js} +2 -2
  288. package/dist/cli/chunks/{validate-swarm-OJUGVH5Q.js → validate-swarm-LZWANCIE.js} +2 -2
  289. package/dist/cli/chunks/visual-security-CKLTAIAB.js +2 -0
  290. package/dist/cli/chunks/{web-tree-sitter-2CLRSA7K.js → web-tree-sitter-N5V4A6XG.js} +2 -2
  291. package/dist/cli/chunks/{windsurf-installer-DSUJJ4PG.js → windsurf-installer-5TBM5B3C.js} +2 -2
  292. package/dist/cli/chunks/{witness-chain-TEGL4ZWB.js → witness-chain-MFP3HBWQ.js} +2 -2
  293. package/dist/cli/chunks/witness-chain-Z6LWFEZS.js +2 -0
  294. package/dist/cli/chunks/witness-chain-repair-5QWRFVUK.js +2 -0
  295. package/dist/cli/chunks/{witness-chain-verifier-SPXKFC67.js → witness-chain-verifier-SRAT7LVY.js} +2 -2
  296. package/dist/cli/chunks/{witness-key-manager-EALOV4OV.js → witness-key-manager-FYZXQTLJ.js} +2 -2
  297. package/dist/cli/chunks/{workflow-PYI6HCAG.js → workflow-M7TUYYXY.js} +5 -5
  298. package/dist/cli/chunks/workflow-orchestrator-OFTAR2NA.js +2 -0
  299. package/dist/cli/chunks/wrappers-COU73OQ6.js +2 -0
  300. package/dist/cli/commands/test.js +30 -12
  301. package/dist/cli/commands/workflow.js +3 -0
  302. package/dist/cli/scheduler/persistent-scheduler.d.ts +2 -0
  303. package/dist/cli/scheduler/persistent-scheduler.js +12 -2
  304. package/dist/cli/utils/generated-test-writer.d.ts +35 -0
  305. package/dist/cli/utils/generated-test-writer.js +44 -0
  306. package/dist/context/compiler.js +4 -1
  307. package/dist/coordination/consensus/providers/ollama-provider.js +16 -27
  308. package/dist/coordination/consensus/providers/openrouter-provider.js +13 -24
  309. package/dist/coordination/handlers/test-execution-handlers.js +4 -2
  310. package/dist/coordination/protocols/defect-investigation.js +4 -1
  311. package/dist/domains/code-intelligence/services/metric-collector/listing-process-owner.d.ts +3 -0
  312. package/dist/domains/code-intelligence/services/metric-collector/listing-process-owner.js +57 -0
  313. package/dist/domains/code-intelligence/services/metric-collector/test-counter.js +127 -39
  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/phases/07-hooks.js +30 -4
  323. package/dist/init/phases/10-workers.js +42 -6
  324. package/dist/integrations/agentic-flow/onnx-embeddings/embedding-generator.d.ts +4 -1
  325. package/dist/integrations/agentic-flow/onnx-embeddings/embedding-generator.js +6 -2
  326. package/dist/integrations/browser/qe-dashboard/wasm-vector-store.js +2 -1
  327. package/dist/integrations/ruvector/coverage-router.d.ts +3 -1
  328. package/dist/integrations/ruvector/coverage-router.js +7 -6
  329. package/dist/integrations/ruvector/diff-risk-classifier.js +5 -4
  330. package/dist/integrations/ruvector/rvf-dual-writer.js +10 -1
  331. package/dist/integrations/vibium/runtime.js +2 -6
  332. package/dist/learning/dream/dream-engine.d.ts +5 -0
  333. package/dist/learning/dream/dream-engine.js +20 -3
  334. package/dist/learning/embedding-space.d.ts +18 -0
  335. package/dist/learning/embedding-space.js +33 -0
  336. package/dist/learning/rvf-pattern-store.js +19 -5
  337. package/dist/mcp/bundle.js +442 -441
  338. package/dist/mcp/handlers/domain-handler-configs.d.ts +42 -0
  339. package/dist/mcp/handlers/handler-factory.js +3 -1
  340. package/dist/mcp/handlers/save-results-option.d.ts +62 -0
  341. package/dist/mcp/handlers/save-results-option.js +35 -0
  342. package/dist/mcp/protocol-server.js +22 -11
  343. package/dist/mcp/security/rate-limiter.d.ts +8 -1
  344. package/dist/mcp/security/rate-limiter.js +33 -4
  345. package/dist/mcp/services/session-resume.js +11 -0
  346. package/dist/mcp/services/session-store.d.ts +31 -2
  347. package/dist/mcp/services/session-store.js +95 -16
  348. package/dist/mcp/services/session-write-buffer.d.ts +55 -0
  349. package/dist/mcp/services/session-write-buffer.js +144 -0
  350. package/dist/mcp/types.d.ts +18 -0
  351. package/dist/memory/crdt/convergence-tracker.js +14 -24
  352. package/dist/memory/crdt/crdt-store.js +15 -0
  353. package/dist/memory/crdt/g-counter.js +10 -8
  354. package/dist/memory/crdt/lww-register.js +3 -3
  355. package/dist/memory/crdt/or-set.js +18 -0
  356. package/dist/planning/goap-planner.js +18 -10
  357. package/dist/shared/embeddings/embedding-cache.d.ts +3 -3
  358. package/dist/shared/embeddings/embedding-cache.js +8 -8
  359. package/dist/shared/embeddings/nomic-embedder.js +9 -6
  360. package/dist/shared/embeddings/ollama-client.d.ts +1 -1
  361. package/dist/shared/embeddings/ollama-client.js +30 -31
  362. package/dist/shared/git/git-analyzer.d.ts +4 -1
  363. package/dist/shared/git/git-analyzer.js +9 -4
  364. package/dist/shared/llm/cache.js +1 -1
  365. package/dist/shared/llm/cost-tracker.js +8 -6
  366. package/dist/shared/llm/providers/azure-openai.js +5 -21
  367. package/dist/shared/llm/providers/bedrock.js +5 -21
  368. package/dist/shared/llm/providers/claude.js +5 -21
  369. package/dist/shared/llm/providers/cognitum.js +5 -17
  370. package/dist/shared/llm/providers/gemini.js +9 -23
  371. package/dist/shared/llm/providers/ollama.js +5 -21
  372. package/dist/shared/llm/providers/openai.js +5 -21
  373. package/dist/shared/llm/providers/openrouter.js +9 -23
  374. package/dist/shared/llm/providers/response-deadline.d.ts +3 -0
  375. package/dist/shared/llm/providers/response-deadline.js +100 -0
  376. package/dist/shared/llm/spend-ledger.js +3 -2
  377. package/dist/shared/metrics/code-metrics.d.ts +1 -0
  378. package/dist/shared/metrics/code-metrics.js +3 -44
  379. package/dist/shared/metrics/cognitive-complexity.d.ts +17 -0
  380. package/dist/shared/metrics/cognitive-complexity.js +108 -0
  381. package/dist/shared/npm-cli-invocation.d.ts +21 -0
  382. package/dist/shared/npm-cli-invocation.js +28 -0
  383. package/dist/shared/optional-module.js +24 -0
  384. package/dist/shared/test-runner-args.d.ts +42 -0
  385. package/dist/shared/test-runner-args.js +74 -0
  386. package/dist/shared/utils/safe-record.d.ts +18 -0
  387. package/dist/shared/utils/safe-record.js +28 -0
  388. package/dist/test-scheduling/executors/vitest-executor.js +23 -5
  389. package/dist/workers/quality-daemon/git-watcher.js +5 -0
  390. package/package.json +1 -1
  391. package/dist/adapters/ag-ui/json-patch-utils.d.ts +0 -136
  392. package/dist/adapters/ag-ui/json-patch-utils.js +0 -575
  393. package/dist/cli/chunks/adapter-EUIELRLI.js +0 -2
  394. package/dist/cli/chunks/aqe-learning-engine-LXRKHASR.js +0 -2
  395. package/dist/cli/chunks/base-4DSLX33Y.js +0 -2
  396. package/dist/cli/chunks/browser-workflow-AWCQLQZK.js +0 -2
  397. package/dist/cli/chunks/chunk-E2QHUMCR.js +0 -2
  398. package/dist/cli/chunks/chunk-I7ECEOFV.js +0 -2
  399. package/dist/cli/chunks/chunk-LW4BCFIV.js +0 -15
  400. package/dist/cli/chunks/chunk-QJGKL67W.js +0 -54
  401. package/dist/cli/chunks/chunk-RLQ4MYB6.js +0 -3
  402. package/dist/cli/chunks/chunk-X43HA3RF.js +0 -14
  403. package/dist/cli/chunks/chunk-Z3K4JZXQ.js +0 -4
  404. package/dist/cli/chunks/client-UJVHZXNQ.js +0 -2
  405. package/dist/cli/chunks/core-handlers-AFXZOSH3.js +0 -2
  406. package/dist/cli/chunks/cost-tracker-D6YSKTQC.js +0 -2
  407. package/dist/cli/chunks/cross-domain-router-ZLNVKLIR.js +0 -2
  408. package/dist/cli/chunks/dream-4OPJXXEG.js +0 -2
  409. package/dist/cli/chunks/heartbeat-scheduler-J5KLHO6C.js +0 -2
  410. package/dist/cli/chunks/hnsw-adapter-56P6XSFR.js +0 -2
  411. package/dist/cli/chunks/hnsw-index-GFZ6XCEW.js +0 -2
  412. package/dist/cli/chunks/hybrid-backend-TUBWJDDN.js +0 -2
  413. package/dist/cli/chunks/impact-analyzer-FXVGKS6B.js +0 -2
  414. package/dist/cli/chunks/init-wizard-LK73HQ7W.js +0 -2
  415. package/dist/cli/chunks/kernel-TCZDKRSI.js +0 -2
  416. package/dist/cli/chunks/knowledge-graph-TWMB2GH2.js +0 -2
  417. package/dist/cli/chunks/llm-router-service-HPDH3P77.js +0 -2
  418. package/dist/cli/chunks/load-test-HTYOUYSN.js +0 -2
  419. package/dist/cli/chunks/memory-backend-X5BE2MPK.js +0 -2
  420. package/dist/cli/chunks/memory-handlers-SQXMFX5X.js +0 -2
  421. package/dist/cli/chunks/pattern-null-store-OCQGQZU6.js +0 -2
  422. package/dist/cli/chunks/protocol-executor-CYEQHQCL.js +0 -2
  423. package/dist/cli/chunks/qe-reasoning-bank-GSTA5WJ4.js +0 -2
  424. package/dist/cli/chunks/queen-coordinator-Y2Q5RQL7.js +0 -2
  425. package/dist/cli/chunks/router-4QB5L4IW.js +0 -2
  426. package/dist/cli/chunks/routing-feedback-YBVHJY5L.js +0 -2
  427. package/dist/cli/chunks/rvf-dual-writer-T5B456SW.js +0 -2
  428. package/dist/cli/chunks/rvf-migration-adapter-2O2NL7ZF.js +0 -2
  429. package/dist/cli/chunks/rvf-native-adapter-RDB3GWTW.js +0 -2
  430. package/dist/cli/chunks/safe-db-YXVMLFU4.js +0 -2
  431. package/dist/cli/chunks/schedule-K6XWCCSK.js +0 -2
  432. package/dist/cli/chunks/scheduler-4MW22D6Q.js +0 -2
  433. package/dist/cli/chunks/sqlite-persistence-UVDHUSAU.js +0 -2
  434. package/dist/cli/chunks/sync-LSPNSVDI.js +0 -2
  435. package/dist/cli/chunks/test-M2XTKD62.js +0 -33
  436. package/dist/cli/chunks/test-scheduling-GYXJQHJL.js +0 -15
  437. package/dist/cli/chunks/token-bootstrap-OTEMRUFR.js +0 -2
  438. package/dist/cli/chunks/unified-memory-UUK77NSE.js +0 -2
  439. package/dist/cli/chunks/unified-memory-hnsw-JOUE6WNF.js +0 -2
  440. package/dist/cli/chunks/unified-persistence-3DRJGNQE.js +0 -2
  441. package/dist/cli/chunks/visual-security-EM7FQG5X.js +0 -2
  442. package/dist/cli/chunks/witness-chain-7NZ6IIUN.js +0 -2
  443. package/dist/cli/chunks/witness-chain-repair-ZWS5WXFL.js +0 -2
  444. package/dist/cli/chunks/workflow-orchestrator-3C3S5FIM.js +0 -2
  445. package/dist/cli/chunks/wrappers-NXJHGK3W.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,11 +209,43 @@ 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(() => {
168
237
  this.flushTimer = null;
169
- this.flush();
238
+ try {
239
+ this.flush();
240
+ }
241
+ catch {
242
+ // #983: a throw here has no caller and reaches 'uncaughtException',
243
+ // which the MCP entry logs as "[AQE] FATAL" on every tick while the
244
+ // disk stays full. The unwritten entries stay buffered for the next
245
+ // append or flush(), and the buffer's one-time WARN reports a
246
+ // persistent failure once it reaches its cap. An explicit flush() or
247
+ // close() still throws to its caller.
248
+ }
170
249
  }, BATCH_FLUSH_MS);
171
250
  }
172
251
  }
@@ -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
@@ -199,6 +199,8 @@ export interface TestExecuteParams {
199
199
  timeout?: number;
200
200
  collectCoverage?: boolean;
201
201
  reportFormat?: 'json' | 'junit' | 'html' | 'markdown';
202
+ /** #933: write result files under .agentic-qe/results/ (default true). false skips them. */
203
+ saveResults?: boolean;
202
204
  }
203
205
  /**
204
206
  * Coverage analysis parameters
@@ -209,6 +211,8 @@ export interface CoverageAnalyzeParams {
209
211
  detectGaps?: boolean;
210
212
  mlPowered?: boolean;
211
213
  prioritization?: 'complexity' | 'criticality' | 'change-frequency' | 'ml-confidence';
214
+ /** #933: write result files under .agentic-qe/results/ (default true). false skips them. */
215
+ saveResults?: boolean;
212
216
  }
213
217
  /**
214
218
  * Quality assessment parameters
@@ -217,6 +221,8 @@ export interface QualityAssessParams {
217
221
  runGate?: boolean;
218
222
  threshold?: number;
219
223
  metrics?: string[];
224
+ /** #933: write result files under .agentic-qe/results/ (default true). false skips them. */
225
+ saveResults?: boolean;
220
226
  }
221
227
  /**
222
228
  * Security scan parameters
@@ -228,6 +234,8 @@ export interface SecurityScanParams {
228
234
  target?: string;
229
235
  /** URL for explicitly requested dynamic scanning. */
230
236
  targetUrl?: string;
237
+ /** #933: write result files under .agentic-qe/results/ (default true). false skips them. */
238
+ saveResults?: boolean;
231
239
  }
232
240
  /**
233
241
  * Contract validation parameters
@@ -237,6 +245,8 @@ export interface ContractValidateParams {
237
245
  providerUrl?: string;
238
246
  consumerName?: string;
239
247
  checkBreakingChanges?: boolean;
248
+ /** #933: write result files under .agentic-qe/results/ (default true). false skips them. */
249
+ saveResults?: boolean;
240
250
  }
241
251
  /**
242
252
  * Accessibility test parameters
@@ -245,6 +255,8 @@ export interface AccessibilityTestParams {
245
255
  url?: string;
246
256
  standard?: 'wcag21-aa' | 'wcag21-aaa' | 'wcag22-aa' | 'section508';
247
257
  includeScreenReader?: boolean;
258
+ /** #933: write result files under .agentic-qe/results/ (default true). false skips them. */
259
+ saveResults?: boolean;
248
260
  }
249
261
  /**
250
262
  * Chaos test parameters
@@ -255,6 +267,8 @@ export interface ChaosTestParams {
255
267
  duration?: number;
256
268
  intensity?: number;
257
269
  dryRun?: boolean;
270
+ /** #933: write result files under .agentic-qe/results/ (default true). false skips them. */
271
+ saveResults?: boolean;
258
272
  }
259
273
  /**
260
274
  * Protocol execute parameters
@@ -528,6 +542,10 @@ export interface CoverageAnalyzeResult {
528
542
  gaps?: CoverageGap[];
529
543
  riskScore?: number;
530
544
  savedFiles?: string[];
545
+ /** #933: true when result files were written; see savedFiles for their paths. */
546
+ resultsSaved?: boolean;
547
+ /** #933: plain statement of what was (or was not) written to disk. */
548
+ resultsNote?: string;
531
549
  /** #569: `null` when no figure was produced — see `lineCoverage`. */
532
550
  statementCoverage?: number | null;
533
551
  totalFiles?: number;
@@ -7,6 +7,7 @@
7
7
  *
8
8
  * @module memory/crdt/convergence-tracker
9
9
  */
10
+ import { createHash } from 'node:crypto';
10
11
  // =============================================================================
11
12
  // Default Configuration
12
13
  // =============================================================================
@@ -23,7 +24,7 @@ const DEFAULT_CONFIG = {
23
24
  * not the internal representations, so that stores with equivalent data produce
24
25
  * the same hash regardless of how they arrived at that state.
25
26
  *
26
- * Not cryptographic - just for detecting differences.
27
+ * Fingerprints structured semantic entries; this is not authentication.
27
28
  */
28
29
  function hashState(state) {
29
30
  const parts = [];
@@ -31,7 +32,7 @@ function hashState(state) {
31
32
  // compare the result - if both have same winner, they have same value)
32
33
  for (const [key, reg] of Object.entries(state.registers)) {
33
34
  // Include value, timestamp, and nodeId - these together determine the LWW winner
34
- parts.push(`r:${key}:${JSON.stringify(reg.value)}:${reg.timestamp}:${reg.nodeId}`);
35
+ parts.push(JSON.stringify(['r', key, JSON.stringify(reg.value), reg.timestamp, reg.nodeId]));
35
36
  }
36
37
  // Hash G-Counters by their TOTAL value (not per-node breakdown)
37
38
  // Two stores are converged if they produce the same sum, even if the internal
@@ -41,10 +42,9 @@ function hashState(state) {
41
42
  // Also include non-zero counts to detect semantic differences
42
43
  const nonZeroCounts = Object.entries(counter.counts)
43
44
  .filter(([_, count]) => count > 0)
44
- .sort(([a], [b]) => a.localeCompare(b))
45
- .map(([nodeId, count]) => `${nodeId}=${count}`)
46
- .join(',');
47
- parts.push(`g:${key}:${total}:{${nonZeroCounts}}`);
45
+ .sort(([a], [b]) => a === b ? 0 : a < b ? -1 : 1)
46
+ .map(([nodeId, count]) => [nodeId, count]);
47
+ parts.push(JSON.stringify(['g', key, total, nonZeroCounts]));
48
48
  }
49
49
  // Hash PN-Counters by their NET value (positive - negative)
50
50
  // Two stores are converged if they evaluate to the same number
@@ -55,15 +55,13 @@ function hashState(state) {
55
55
  // Include non-zero contributions for semantic comparison
56
56
  const nonZeroPos = Object.entries(counter.positive.counts)
57
57
  .filter(([_, count]) => count > 0)
58
- .sort(([a], [b]) => a.localeCompare(b))
59
- .map(([nodeId, count]) => `${nodeId}=+${count}`)
60
- .join(',');
58
+ .sort(([a], [b]) => a === b ? 0 : a < b ? -1 : 1)
59
+ .map(([nodeId, count]) => [nodeId, count]);
61
60
  const nonZeroNeg = Object.entries(counter.negative.counts)
62
61
  .filter(([_, count]) => count > 0)
63
- .sort(([a], [b]) => a.localeCompare(b))
64
- .map(([nodeId, count]) => `${nodeId}=-${count}`)
65
- .join(',');
66
- parts.push(`p:${key}:${netValue}:{${nonZeroPos}|${nonZeroNeg}}`);
62
+ .sort(([a], [b]) => a === b ? 0 : a < b ? -1 : 1)
63
+ .map(([nodeId, count]) => [nodeId, count]);
64
+ parts.push(JSON.stringify(['p', key, netValue, nonZeroPos, nonZeroNeg]));
67
65
  }
68
66
  // Hash OR-Sets by their active elements (elements with at least one non-tombstoned tag)
69
67
  for (const [key, set] of Object.entries(state.sets)) {
@@ -77,20 +75,12 @@ function hashState(state) {
77
75
  }
78
76
  }
79
77
  activeElements.sort();
80
- parts.push(`s:${key}:[${activeElements.join(',')}]`);
78
+ parts.push(JSON.stringify(['s', key, activeElements]));
81
79
  }
82
80
  // Sort for consistency
83
81
  parts.sort();
84
- // Simple hash: join and get a fingerprint
85
- const joined = parts.join('|');
86
- let hash = 0;
87
- for (let i = 0; i < joined.length; i++) {
88
- const char = joined.charCodeAt(i);
89
- hash = ((hash << 5) - hash) + char;
90
- hash = hash & hash; // Convert to 32-bit integer
91
- }
92
- // Return hash without version - version is per-node and shouldn't affect convergence check
93
- return hash.toString(16);
82
+ // Version is per-node and does not affect semantic convergence.
83
+ return createHash('sha256').update(JSON.stringify(parts)).digest('hex');
94
84
  }
95
85
  // =============================================================================
96
86
  // Convergence Tracker Implementation
@@ -365,6 +365,21 @@ export function createCRDTStore(config) {
365
365
  // For initial state, need full state - caller should use getState instead
366
366
  return null;
367
367
  }
368
+ // A retained suffix cannot cover an older checkpoint. Send complete CRDT
369
+ // state (including OR-set tombstones) through the existing delta merge API.
370
+ if (sinceVersion < deltaHistory[0].fromVersion) {
371
+ const snapshot = store.getState();
372
+ return {
373
+ fromVersion: sinceVersion,
374
+ toVersion: version,
375
+ timestamp: Date.now(),
376
+ nodeId,
377
+ registers: snapshot.registers,
378
+ gCounters: snapshot.gCounters,
379
+ pnCounters: snapshot.pnCounters,
380
+ sets: snapshot.sets,
381
+ };
382
+ }
368
383
  // Find deltas that contain changes after the requested version
369
384
  // A delta is relevant if its toVersion > sinceVersion
370
385
  const relevantDeltas = deltaHistory.filter((d) => d.toVersion > sinceVersion);
@@ -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
@@ -43,7 +43,7 @@ export function createLWWRegister(nodeId, initialValue, initialTimestamp) {
43
43
  return timestampA - timestampB;
44
44
  }
45
45
  // Tiebreaker: lexicographic comparison of node IDs
46
- return nodeIdA.localeCompare(nodeIdB);
46
+ return nodeIdA === nodeIdB ? 0 : nodeIdA > nodeIdB ? 1 : -1;
47
47
  }
48
48
  return {
49
49
  get() {
@@ -52,7 +52,7 @@ export function createLWWRegister(nodeId, initialValue, initialTimestamp) {
52
52
  set(value, timestamp) {
53
53
  const ts = timestamp ?? Date.now();
54
54
  // Only update if new timestamp wins
55
- if (state.timestamp === 0 ||
55
+ if (state.version === 0 ||
56
56
  compareTimestamps(ts, nodeId, state.timestamp, state.nodeId) > 0) {
57
57
  state = {
58
58
  value,
@@ -79,7 +79,7 @@ export function createLWWRegister(nodeId, initialValue, initialTimestamp) {
79
79
  },
80
80
  applyState(incoming) {
81
81
  // Only update if incoming timestamp wins
82
- if (state.timestamp === 0 ||
82
+ if (state.version === 0 ||
83
83
  compareTimestamps(incoming.timestamp, incoming.nodeId, state.timestamp, state.nodeId) > 0) {
84
84
  state = {
85
85
  value: incoming.value,