agentic-qe 3.15.13 → 3.15.15

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 (426) hide show
  1. package/.claude/agents/v3/templates/qx-report-template.html +1 -1
  2. package/.claude/helpers/brain-checkpoint.cjs +124 -5
  3. package/.claude/skills/skills-manifest.json +1 -1
  4. package/CHANGELOG.md +124 -0
  5. package/assets/agents/v3/templates/qx-report-template.html +1 -1
  6. package/assets/skills/skills-manifest.json +1 -1
  7. package/dist/cli/bundle.js +6 -6
  8. package/dist/cli/chunks/adapter-QU6INSKP.js +2 -0
  9. package/dist/cli/chunks/agent-booster-wasm-EUF4XVUC.js +2 -0
  10. package/dist/cli/chunks/{agent-handler-AOH6TV7W.js → agent-handler-MOX6PSIQ.js} +2 -2
  11. package/dist/cli/chunks/{agent-memory-branch-2P54SF5N.js → agent-memory-branch-AEXKIGDG.js} +2 -2
  12. package/dist/cli/chunks/aqe-learning-engine-PAJPENJD.js +2 -0
  13. package/dist/cli/chunks/{arena-NSVFCAF5.js → arena-IQ5ZZDRF.js} +2 -2
  14. package/dist/cli/chunks/{arena-X6MOGQHA.js → arena-M7GA3CVG.js} +4 -4
  15. package/dist/cli/chunks/{audit-27DJLQNM.js → audit-4IPBMKWB.js} +3 -3
  16. package/dist/cli/chunks/base-OTGSN6IC.js +2 -0
  17. package/dist/cli/chunks/{better-sqlite3-BU5GXILS.js → better-sqlite3-IKDKJ2IE.js} +2 -2
  18. package/dist/cli/chunks/brain-handler-5NQUDH4W.js +95 -0
  19. package/dist/cli/chunks/{branch-enumerator-5CLULOCU.js → branch-enumerator-KSXELWRC.js} +2 -2
  20. package/dist/cli/chunks/{browser-R4DMU3LN.js → browser-6LACARWE.js} +2 -2
  21. package/dist/cli/chunks/browser-workflow-WLZGR6SB.js +2 -0
  22. package/dist/cli/chunks/{chunk-LUZNKJE6.js → chunk-22UKJGGN.js} +3 -3
  23. package/dist/cli/chunks/{chunk-BLSLEVDI.js → chunk-27HE2BHC.js} +2 -2
  24. package/dist/cli/chunks/{chunk-K4CZA77U.js → chunk-2CKERSMB.js} +2 -2
  25. package/dist/cli/chunks/{chunk-YSZ5OE3Z.js → chunk-2IIXCEMS.js} +2 -2
  26. package/dist/cli/chunks/{chunk-F3YS57NF.js → chunk-2LUTPMBO.js} +2 -2
  27. package/dist/cli/chunks/{chunk-GHM6MQNK.js → chunk-2ZFLULL4.js} +2 -2
  28. package/dist/cli/chunks/{chunk-7CMTY45A.js → chunk-337Z52QM.js} +2 -2
  29. package/dist/cli/chunks/{chunk-W26B7ERY.js → chunk-3CYNZFKH.js} +1 -1
  30. package/dist/cli/chunks/chunk-3HVFIITW.js +2 -0
  31. package/dist/cli/chunks/{chunk-K3TLLJMX.js → chunk-3J3RNJNX.js} +1 -1
  32. package/dist/cli/chunks/{chunk-MAMQA43L.js → chunk-4ATQP3PR.js} +1 -1
  33. package/dist/cli/chunks/{chunk-YXRASAPI.js → chunk-4D4CWP72.js} +2 -2
  34. package/dist/cli/chunks/{chunk-GHY6Z6KO.js → chunk-4HKAD25N.js} +3 -3
  35. package/dist/cli/chunks/{chunk-XNBOGCF3.js → chunk-4X3SWKBA.js} +2 -2
  36. package/dist/cli/chunks/{chunk-IJUHSJ2U.js → chunk-5AFVEWMT.js} +2 -2
  37. package/dist/cli/chunks/{chunk-SE4VNN4I.js → chunk-5C62XMJR.js} +3 -3
  38. package/dist/cli/chunks/{chunk-KDNJ4F3P.js → chunk-5G4UFTV4.js} +2 -2
  39. package/dist/cli/chunks/{chunk-DVGRPK7A.js → chunk-5I7357KS.js} +2 -2
  40. package/dist/cli/chunks/{chunk-YZWBNBTW.js → chunk-5KA5TVPR.js} +2 -2
  41. package/dist/cli/chunks/{chunk-JGZ722G3.js → chunk-5PTAFGJT.js} +2 -2
  42. package/dist/cli/chunks/{chunk-SVLQRAMF.js → chunk-6BRQPHMZ.js} +1 -1
  43. package/dist/cli/chunks/{chunk-KDVZND5Q.js → chunk-6KCSKGVY.js} +1 -1
  44. package/dist/cli/chunks/{chunk-LWR3FV3Y.js → chunk-6LE362LZ.js} +2 -2
  45. package/dist/cli/chunks/{chunk-WKGTGOYS.js → chunk-6NBRMD25.js} +3 -3
  46. package/dist/cli/chunks/{chunk-HQZGPJYG.js → chunk-6RBTS3NF.js} +2 -2
  47. package/dist/cli/chunks/{chunk-WOCGL4QP.js → chunk-6YVMX2TC.js} +2 -2
  48. package/dist/cli/chunks/{chunk-I3C7JOXC.js → chunk-73PBAWAF.js} +2 -2
  49. package/dist/cli/chunks/{chunk-75RDHBAX.js → chunk-74YG72NQ.js} +3 -3
  50. package/dist/cli/chunks/{chunk-O6FGXMHD.js → chunk-76P32JVU.js} +1 -1
  51. package/dist/cli/chunks/{chunk-LL7LDPXS.js → chunk-7ACCBHRB.js} +1 -1
  52. package/dist/cli/chunks/{chunk-3LJ7LQMV.js → chunk-7BLZHFKD.js} +1 -1
  53. package/dist/cli/chunks/{chunk-CM4LSLKR.js → chunk-7O45RQHF.js} +2 -2
  54. package/dist/cli/chunks/{chunk-NU3W5WFT.js → chunk-7XB3FCKM.js} +2 -2
  55. package/dist/cli/chunks/{chunk-E56B6IDX.js → chunk-AHMWD6JG.js} +2 -2
  56. package/dist/cli/chunks/{chunk-G2Q66Z23.js → chunk-AJPROCDW.js} +2 -2
  57. package/dist/cli/chunks/{chunk-NW7IBHJA.js → chunk-AKZO6GGG.js} +13 -13
  58. package/dist/cli/chunks/{chunk-IC3TQEOA.js → chunk-AOKKUB5F.js} +1 -1
  59. package/dist/cli/chunks/{chunk-4OVC4RIL.js → chunk-AP2W7Z3A.js} +1 -1
  60. package/dist/cli/chunks/{chunk-PHP5UBT4.js → chunk-BBRROA3Z.js} +2 -2
  61. package/dist/cli/chunks/{chunk-5FKWCZNF.js → chunk-BDKEAGQ2.js} +2 -2
  62. package/dist/cli/chunks/{chunk-BTVEYBW2.js → chunk-BFQTLF5X.js} +2 -2
  63. package/dist/cli/chunks/{chunk-HZ5NXFXH.js → chunk-BLL2XU7A.js} +2 -2
  64. package/dist/cli/chunks/{chunk-UTRV7T2N.js → chunk-BP5T3OEV.js} +2 -2
  65. package/dist/cli/chunks/{chunk-GB6HBNH2.js → chunk-BQ47GQPK.js} +2 -2
  66. package/dist/cli/chunks/{chunk-RFNW2LGD.js → chunk-BU4UQR36.js} +2 -2
  67. package/dist/cli/chunks/{chunk-WO274FRI.js → chunk-BZULJMGH.js} +2 -2
  68. package/dist/cli/chunks/{chunk-GU5HNCWI.js → chunk-C4KLXFJP.js} +1 -1
  69. package/dist/cli/chunks/{chunk-LFJALJOA.js → chunk-C4RTAVC6.js} +2 -2
  70. package/dist/cli/chunks/{chunk-WNQS4WTS.js → chunk-C5CXL3JP.js} +2 -2
  71. package/dist/cli/chunks/{chunk-MGZ5FJUW.js → chunk-CAOUV5GZ.js} +2 -2
  72. package/dist/cli/chunks/{chunk-XPRVF4YE.js → chunk-CBK5CT6T.js} +2 -2
  73. package/dist/cli/chunks/{chunk-JRRXCODW.js → chunk-DEKR3CTS.js} +2 -2
  74. package/dist/cli/chunks/{chunk-AQSVJNEH.js → chunk-DKX4GNRU.js} +2 -2
  75. package/dist/cli/chunks/{chunk-6KATY3KS.js → chunk-DUKE27HC.js} +2 -2
  76. package/dist/cli/chunks/{chunk-W2QWSQVE.js → chunk-DURD37JZ.js} +2 -2
  77. package/dist/cli/chunks/{chunk-KCW47QR5.js → chunk-E3MRDIZF.js} +1 -1
  78. package/dist/cli/chunks/{chunk-6Z7PRBSG.js → chunk-E56PVVWC.js} +2 -2
  79. package/dist/cli/chunks/{chunk-WQL7WCIZ.js → chunk-E5G4WZ2T.js} +1 -1
  80. package/dist/cli/chunks/{chunk-PB6J6HAA.js → chunk-EBTNMQSS.js} +2 -2
  81. package/dist/cli/chunks/{chunk-KADFXPPN.js → chunk-EFUJDMNC.js} +2 -2
  82. package/dist/cli/chunks/{chunk-QPNG5ZN2.js → chunk-EKP2SC77.js} +2 -2
  83. package/dist/cli/chunks/{chunk-U2FUXDDJ.js → chunk-EMSZVUYA.js} +3 -3
  84. package/dist/cli/chunks/{chunk-XEAEYC6Y.js → chunk-ERN56H6S.js} +1 -1
  85. package/dist/cli/chunks/{chunk-DNDL7SOS.js → chunk-FOOW4JVS.js} +2 -2
  86. package/dist/cli/chunks/{chunk-HOAJUIBQ.js → chunk-FTRSS64D.js} +2 -2
  87. package/dist/cli/chunks/{chunk-TOQWL2ZF.js → chunk-G242G224.js} +2 -2
  88. package/dist/cli/chunks/{chunk-VTDFVFST.js → chunk-G6RDCCFV.js} +2 -2
  89. package/dist/cli/chunks/{chunk-TWDW32W2.js → chunk-GCHYOPRZ.js} +2 -2
  90. package/dist/cli/chunks/{chunk-MFW5HSG4.js → chunk-GGQGCT4Y.js} +2 -2
  91. package/dist/cli/chunks/{chunk-G6WDYBLQ.js → chunk-GKSMRBHU.js} +1 -1
  92. package/dist/cli/chunks/{chunk-CCMKSHAT.js → chunk-GQABPCQE.js} +2 -2
  93. package/dist/cli/chunks/{chunk-G77ERMUD.js → chunk-GV2QE5TO.js} +1 -1
  94. package/dist/cli/chunks/{chunk-756CGMEH.js → chunk-H5DER3JY.js} +1 -1
  95. package/dist/cli/chunks/{chunk-W3PPFHI5.js → chunk-HH4ED4F7.js} +52 -50
  96. package/dist/cli/chunks/{chunk-3Y2ROSCL.js → chunk-HL2ANKN3.js} +2 -2
  97. package/dist/cli/chunks/{chunk-T3PGQFDI.js → chunk-HTZSRMHW.js} +2 -2
  98. package/dist/cli/chunks/{chunk-3QZEGE67.js → chunk-IXL5ZHWJ.js} +1 -1
  99. package/dist/cli/chunks/{chunk-5ZGM3RMH.js → chunk-J3FP5UGL.js} +1 -1
  100. package/dist/cli/chunks/{chunk-FZ76G4QJ.js → chunk-JCQGJGGZ.js} +1 -1
  101. package/dist/cli/chunks/chunk-JCZCJE6X.js +86 -0
  102. package/dist/cli/chunks/{chunk-YZEXYO4W.js → chunk-JKJOB65O.js} +1 -1
  103. package/dist/cli/chunks/{chunk-A64JFBWI.js → chunk-JUDUBQHA.js} +2 -2
  104. package/dist/cli/chunks/{chunk-PIDQVU3L.js → chunk-JW74KRBC.js} +2 -2
  105. package/dist/cli/chunks/{chunk-EXGMJFAT.js → chunk-K3WZICFA.js} +1 -1
  106. package/dist/cli/chunks/{chunk-ASQYASNV.js → chunk-K3XBQC3R.js} +1 -1
  107. package/dist/cli/chunks/{chunk-E7CLYGS7.js → chunk-KCQNFBBR.js} +1 -1
  108. package/dist/cli/chunks/chunk-KJBPB7P5.js +3 -0
  109. package/dist/cli/chunks/chunk-KLTMOXIK.js +3 -0
  110. package/dist/cli/chunks/{chunk-5MDERQH3.js → chunk-L32JNNKL.js} +1 -1
  111. package/dist/cli/chunks/{chunk-32ZMWEP3.js → chunk-LB2LGEDP.js} +2 -2
  112. package/dist/cli/chunks/{chunk-42J34YG4.js → chunk-LHMQIZ6B.js} +2 -2
  113. package/dist/cli/chunks/{chunk-NURIILUB.js → chunk-LJMYRTJ7.js} +1 -1
  114. package/dist/cli/chunks/{chunk-M6AAGIG7.js → chunk-LNX74WHQ.js} +1 -1
  115. package/dist/cli/chunks/{chunk-P7A4NKTZ.js → chunk-LTQVUAPH.js} +2 -2
  116. package/dist/cli/chunks/{chunk-3YNLWPBF.js → chunk-LVABQNRF.js} +2 -2
  117. package/dist/cli/chunks/{chunk-2G7TVT6W.js → chunk-LYJHUNBK.js} +2 -2
  118. package/dist/cli/chunks/{chunk-DLD7RUZ4.js → chunk-M4CJCPCQ.js} +2 -2
  119. package/dist/cli/chunks/{chunk-Q3UDLV5Z.js → chunk-M4WMSCAE.js} +1 -1
  120. package/dist/cli/chunks/{chunk-UDQSYWVF.js → chunk-MIA447GY.js} +1 -1
  121. package/dist/cli/chunks/{chunk-RF7HWBHN.js → chunk-MPFPWJTH.js} +2 -2
  122. package/dist/cli/chunks/{chunk-BK577VL7.js → chunk-MV55NXTD.js} +2 -2
  123. package/dist/cli/chunks/{chunk-JQGMW45H.js → chunk-NQS3BWS6.js} +1 -1
  124. package/dist/cli/chunks/{chunk-BEGR4D6N.js → chunk-NWIIYHT6.js} +2 -2
  125. package/dist/cli/chunks/{chunk-SSU73QAX.js → chunk-O6EWL5DQ.js} +2 -2
  126. package/dist/cli/chunks/chunk-OBDONJQM.js +2 -0
  127. package/dist/cli/chunks/chunk-OLZH5LRT.js +141 -0
  128. package/dist/cli/chunks/{chunk-W3INMZZ6.js → chunk-OQG3UQQ7.js} +1 -1
  129. package/dist/cli/chunks/{chunk-72ASBE35.js → chunk-PFQCV6YS.js} +3 -3
  130. package/dist/cli/chunks/{chunk-7YTGHGK4.js → chunk-PS6UMZVK.js} +2 -2
  131. package/dist/cli/chunks/{chunk-OCAEXYFA.js → chunk-PXATBHWN.js} +2 -2
  132. package/dist/cli/chunks/{chunk-ARJW4I2O.js → chunk-PYPS65P7.js} +2 -2
  133. package/dist/cli/chunks/{chunk-SYV2V3PL.js → chunk-Q6I4SIUU.js} +4 -4
  134. package/dist/cli/chunks/{chunk-H4H2YSFH.js → chunk-QFGYH6HD.js} +1 -1
  135. package/dist/cli/chunks/{chunk-526QYFJU.js → chunk-QGBGSQ2E.js} +2 -2
  136. package/dist/cli/chunks/{chunk-YBQH2VOP.js → chunk-QRKTBSZT.js} +2 -2
  137. package/dist/cli/chunks/{chunk-C7JM7CD3.js → chunk-R6LHJ7ME.js} +2 -2
  138. package/dist/cli/chunks/{chunk-TSQC2KKZ.js → chunk-RBKUU7WF.js} +2 -2
  139. package/dist/cli/chunks/{chunk-CE7B5LU7.js → chunk-RDMRY7CT.js} +1 -1
  140. package/dist/cli/chunks/chunk-RIRZHOS2.js +8 -0
  141. package/dist/cli/chunks/{chunk-CRWPZT74.js → chunk-SHRI7TKJ.js} +2 -2
  142. package/dist/cli/chunks/{chunk-KWYH3FI4.js → chunk-SJCKCSN3.js} +1 -1
  143. package/dist/cli/chunks/{chunk-DFUASIKA.js → chunk-SON6ZRH3.js} +2 -2
  144. package/dist/cli/chunks/{chunk-J2ZIFFM6.js → chunk-SZAZQZWI.js} +2 -2
  145. package/dist/cli/chunks/{chunk-HD7YIFOI.js → chunk-T4GE7MPI.js} +2 -2
  146. package/dist/cli/chunks/{chunk-3Y7TJFHU.js → chunk-T66PPF4D.js} +2 -2
  147. package/dist/cli/chunks/{chunk-3RZV5DGO.js → chunk-T67R2MUN.js} +2 -2
  148. package/dist/cli/chunks/{chunk-H4GG2NLO.js → chunk-TDQWTSBS.js} +2 -2
  149. package/dist/cli/chunks/{chunk-TWJTK4CC.js → chunk-TODNOP7C.js} +2 -2
  150. package/dist/cli/chunks/{chunk-NZ3GUMB2.js → chunk-TX2CHQD7.js} +2 -2
  151. package/dist/cli/chunks/{chunk-AL6FBH3E.js → chunk-TZIHDJZD.js} +2 -2
  152. package/dist/cli/chunks/{chunk-GII6UM3F.js → chunk-U62OUXBF.js} +1 -1
  153. package/dist/cli/chunks/{chunk-YQFLQE53.js → chunk-UAQZI6N4.js} +2 -2
  154. package/dist/cli/chunks/{chunk-R7SYRCRP.js → chunk-UE2J6MA5.js} +1 -1
  155. package/dist/cli/chunks/{chunk-VRHRBAEM.js → chunk-UGYM4U44.js} +1 -1
  156. package/dist/cli/chunks/{chunk-NT4DBXSX.js → chunk-UJABDXST.js} +2 -2
  157. package/dist/cli/chunks/{chunk-OFACHK5O.js → chunk-UORB2QDU.js} +9 -9
  158. package/dist/cli/chunks/{chunk-QDEJ4CI2.js → chunk-UQPA33UK.js} +2 -2
  159. package/dist/cli/chunks/{chunk-TCBBNUBP.js → chunk-UUBIQR6A.js} +3 -3
  160. package/dist/cli/chunks/{chunk-NZD4DPSU.js → chunk-UXIY4IAI.js} +2 -2
  161. package/dist/cli/chunks/{chunk-SG3NX7QE.js → chunk-VCXI4XC4.js} +2 -2
  162. package/dist/cli/chunks/{chunk-PSFSPGUD.js → chunk-VMAM46HQ.js} +2 -2
  163. package/dist/cli/chunks/{chunk-3AN5TNGD.js → chunk-VY4U6DPO.js} +3 -3
  164. package/dist/cli/chunks/{chunk-X7N2JF2X.js → chunk-W27AJ5B4.js} +2 -2
  165. package/dist/cli/chunks/{chunk-CT6SAVXQ.js → chunk-W5ZJG2OU.js} +2 -2
  166. package/dist/cli/chunks/{chunk-KV4T4MXK.js → chunk-W62OOK7A.js} +2 -2
  167. package/dist/cli/chunks/{chunk-5K26BEYB.js → chunk-WNTA4YKE.js} +2 -2
  168. package/dist/cli/chunks/{chunk-LZYQHVD4.js → chunk-WUOOX7UG.js} +2 -2
  169. package/dist/cli/chunks/{chunk-7NA7JXNB.js → chunk-WVXJ2QIG.js} +2 -2
  170. package/dist/cli/chunks/{chunk-KB56CPU4.js → chunk-X33CWRDF.js} +2 -2
  171. package/dist/cli/chunks/{chunk-7JUC2MVZ.js → chunk-XG4F4XH4.js} +2 -2
  172. package/dist/cli/chunks/{chunk-ZAKQLAHT.js → chunk-XH4JMX5O.js} +1 -1
  173. package/dist/cli/chunks/{chunk-X2Z7F4EU.js → chunk-XHHWABJV.js} +2 -2
  174. package/dist/cli/chunks/{chunk-7PLIEBY7.js → chunk-XHLYGXYE.js} +2 -2
  175. package/dist/cli/chunks/{chunk-UXZSUMEA.js → chunk-XIVVTYM2.js} +2 -2
  176. package/dist/cli/chunks/{chunk-MVVB7C2E.js → chunk-XM6ZVFM5.js} +156 -156
  177. package/dist/cli/chunks/{chunk-VTOBUZL6.js → chunk-XWIAZG3C.js} +2 -2
  178. package/dist/cli/chunks/{chunk-CV77DMDQ.js → chunk-Y2OX6KGN.js} +2 -2
  179. package/dist/cli/chunks/{chunk-VRVMIPTM.js → chunk-YUS6TWAL.js} +2 -2
  180. package/dist/cli/chunks/{chunk-VU5TBX2V.js → chunk-ZIPAB5J6.js} +2 -2
  181. package/dist/cli/chunks/{chunk-KUAKV3IW.js → chunk-ZSOMUTNL.js} +1 -1
  182. package/dist/cli/chunks/{chunk-UOC3O6RP.js → chunk-ZWBGYJ7K.js} +2 -2
  183. package/dist/cli/chunks/{chunk-5VMAV6T6.js → chunk-ZYJB6FML.js} +1 -1
  184. package/dist/cli/chunks/{ci-ENOASTYB.js → ci-UCUJOSBW.js} +2 -2
  185. package/dist/cli/chunks/{ci-config-B26OXHQM.js → ci-config-2XILD3XG.js} +2 -2
  186. package/dist/cli/chunks/{ci-output-JTCLLNOQ.js → ci-output-BL6KWOHW.js} +2 -2
  187. package/dist/cli/chunks/{circuit-breaker-23JMFNM5.js → circuit-breaker-5XLIOXE5.js} +2 -2
  188. package/dist/cli/chunks/{claude-flow-setup-ON6L462G.js → claude-flow-setup-4IMP6ACS.js} +2 -2
  189. package/dist/cli/chunks/client-KKRNPX4F.js +2 -0
  190. package/dist/cli/chunks/{cline-installer-OWQ4D2FQ.js → cline-installer-RYLHCDK7.js} +2 -2
  191. package/dist/cli/chunks/{code-2ZRL7SEU.js → code-WY3GJXHX.js} +3 -3
  192. package/dist/cli/chunks/{code-index-extractor-JXSQVM67.js → code-index-extractor-Y4MZBZCW.js} +2 -2
  193. package/dist/cli/chunks/{codex-installer-7LXZYBSQ.js → codex-installer-SCJ3T3DX.js} +4 -4
  194. package/dist/cli/chunks/{completions-C2LR623C.js → completions-CN2DXQFU.js} +2 -2
  195. package/dist/cli/chunks/{complexity-analyzer-TGQLHCYJ.js → complexity-analyzer-7MDPPIBH.js} +2 -2
  196. package/dist/cli/chunks/{continuedev-installer-RUGD24D2.js → continuedev-installer-GCEJRK34.js} +2 -2
  197. package/dist/cli/chunks/{copilot-installer-ZLFVLEJP.js → copilot-installer-BHPDSELY.js} +2 -2
  198. package/dist/cli/chunks/core-handlers-47MPMED7.js +2 -0
  199. package/dist/cli/chunks/{cost-tracker-RT4QL745.js → cost-tracker-VO5MFWR6.js} +2 -2
  200. package/dist/cli/chunks/coverage-LYFQYNH6.js +51 -0
  201. package/dist/cli/chunks/cross-domain-router-U6MBFHEC.js +2 -0
  202. package/dist/cli/chunks/{cursor-installer-LJKLNFF6.js → cursor-installer-KP4HA7TV.js} +2 -2
  203. package/dist/cli/chunks/{daemon-BMDXCQT5.js → daemon-7RC7TS57.js} +3 -3
  204. package/dist/cli/chunks/{daemon-FBH3IRYN.js → daemon-AXLVPKVO.js} +4 -4
  205. package/dist/cli/chunks/{dag-attention-scheduler-JGDED55I.js → dag-attention-scheduler-NKA44RSR.js} +2 -2
  206. package/dist/cli/chunks/{detect-SZIHIVCJ.js → detect-CMYAJWYF.js} +2 -2
  207. package/dist/cli/chunks/{dist-node-FV3KWXQ6.js → dist-node-EN3PYEGW.js} +2 -2
  208. package/dist/cli/chunks/{domain-handler-GI5JWQOV.js → domain-handler-EXSZCX7A.js} +2 -2
  209. package/dist/cli/chunks/{domain-plugins-BUWY36TL.js → domain-plugins-HCQFSNL7.js} +2 -2
  210. package/dist/cli/chunks/{domain-transfer-GCY7W5DA.js → domain-transfer-3LGSNTPO.js} +2 -2
  211. package/dist/cli/chunks/dream-76L6EEN7.js +2 -0
  212. package/dist/cli/chunks/{embed-and-insert-pattern-GPRR3ZGD.js → embed-and-insert-pattern-B6MNHICW.js} +2 -2
  213. package/dist/cli/chunks/{eval-XPB3IGAP.js → eval-OQELIWJK.js} +2 -2
  214. package/dist/cli/chunks/{experience-capture-middleware-2E554UB3.js → experience-capture-middleware-SUFILYPW.js} +3 -3
  215. package/dist/cli/chunks/{fast-paths-ZSMWZPUC.js → fast-paths-UV4NDEWM.js} +2 -2
  216. package/dist/cli/chunks/{feature-flags-GIWVDVVC.js → feature-flags-CKTYX67J.js} +2 -2
  217. package/dist/cli/chunks/{feature-flags-N7EOGE5P.js → feature-flags-H7H33B6C.js} +2 -2
  218. package/dist/cli/chunks/file-discovery-VSFKZ3LJ.js +2 -0
  219. package/dist/cli/chunks/{fleet-HCHDOUCX.js → fleet-ZJBCAKRG.js} +3 -3
  220. package/dist/cli/chunks/{gnn-wrapper-CZNCNXXZ.js → gnn-wrapper-RUE2QZRG.js} +2 -2
  221. package/dist/cli/chunks/{heartbeat-handler-6YUIF2YQ.js → heartbeat-handler-XRV327M7.js} +4 -4
  222. package/dist/cli/chunks/heartbeat-scheduler-NIK3KKEH.js +2 -0
  223. package/dist/cli/chunks/hnsw-adapter-WJG7LUJJ.js +2 -0
  224. package/dist/cli/chunks/hnsw-index-D6PRI5HC.js +2 -0
  225. package/dist/cli/chunks/{hnsw-legacy-bridge-J3M3IK24.js → hnsw-legacy-bridge-UJID6ZZ4.js} +2 -2
  226. package/dist/cli/chunks/{hnswlib-node-ULGTGDZW.js → hnswlib-node-WS43R4AX.js} +2 -2
  227. package/dist/cli/chunks/{hooks-C4BUGYUQ.js → hooks-YZNJKXAJ.js} +10 -10
  228. package/dist/cli/chunks/hybrid-backend-RIUR3I7F.js +2 -0
  229. package/dist/cli/chunks/{hypergraph-engine-WINGVMPG.js → hypergraph-engine-XQJSIMTS.js} +2 -2
  230. package/dist/cli/chunks/{hypergraph-handler-GADMWKAU.js → hypergraph-handler-ZD2NYXMR.js} +3 -3
  231. package/dist/cli/chunks/impact-analyzer-C36YYTJ5.js +2 -0
  232. package/dist/cli/chunks/{init-guard-K2T4QWAO.js → init-guard-DSRUAVRT.js} +2 -2
  233. package/dist/cli/chunks/{init-handler-PCZTDZYI.js → init-handler-RJU5QMAP.js} +6 -6
  234. package/dist/cli/chunks/init-wizard-JCKNGIGT.js +2 -0
  235. package/dist/cli/chunks/kernel-F7ILJTYD.js +2 -0
  236. package/dist/cli/chunks/{kilocode-installer-XENXNEIU.js → kilocode-installer-BCPOCVMC.js} +2 -2
  237. package/dist/cli/chunks/{kiro-installer-3PG2TJ67.js → kiro-installer-GFCWCB2S.js} +2 -2
  238. package/dist/cli/chunks/knowledge-graph-VTXDBHB2.js +2 -0
  239. package/dist/cli/chunks/learning-FZTD72CF.js +131 -0
  240. package/dist/cli/chunks/{llm-router-RKVDEWU2.js → llm-router-GJVKGRJL.js} +4 -4
  241. package/dist/cli/chunks/llm-router-service-TNOWQINA.js +2 -0
  242. package/dist/cli/chunks/{load-ITHC564X.js → load-YKTPOYBE.js} +2 -2
  243. package/dist/cli/chunks/load-test-FPVBK2EV.js +2 -0
  244. package/dist/cli/chunks/{mcp-TCL5UW3N.js → mcp-LT6R2IKS.js} +2 -2
  245. package/dist/cli/chunks/{memory-BKDAY2N2.js → memory-4HKKOLRY.js} +5 -5
  246. package/dist/cli/chunks/memory-backend-2QE7O67A.js +2 -0
  247. package/dist/cli/chunks/{memory-handlers-WN4FXFOA.js → memory-handlers-X4CMVBXB.js} +2 -2
  248. package/dist/cli/chunks/{multi-model-executor-VHAT7ZPF.js → multi-model-executor-2YPM2WTK.js} +2 -2
  249. package/dist/cli/chunks/{opencode-installer-E3VM3EEY.js → opencode-installer-WBAJMH5K.js} +2 -2
  250. package/dist/cli/chunks/{orchestrator-BMQ6X762.js → orchestrator-5W5WVMVJ.js} +109 -25
  251. package/dist/cli/chunks/pattern-null-store-UI35ORHW.js +2 -0
  252. package/dist/cli/chunks/{pattern-usage-recorder-GOOR2BV5.js → pattern-usage-recorder-GXRMNPAZ.js} +2 -2
  253. package/dist/cli/chunks/{pipeline-5NSFQQIX.js → pipeline-2NA4DRDA.js} +2 -2
  254. package/dist/cli/chunks/{platform-SQM34J5G.js → platform-BGERNQ5V.js} +2 -2
  255. package/dist/cli/chunks/{plugin-UQJZRMZG.js → plugin-L4EPVENR.js} +2 -2
  256. package/dist/cli/chunks/{prime-radiant-advanced-wasm-WMDJOL4S.js → prime-radiant-advanced-wasm-RTQRTPTM.js} +2 -2
  257. package/dist/cli/chunks/project-root-S7WDFTMU.js +2 -0
  258. package/dist/cli/chunks/protocol-executor-OPANXQVB.js +2 -0
  259. package/dist/cli/chunks/{protocol-handler-OBDCVY6X.js → protocol-handler-SYQXM6JK.js} +2 -2
  260. package/dist/cli/chunks/{prove-XDC7I4XT.js → prove-5O7GPJCU.js} +2 -2
  261. package/dist/cli/chunks/qe-reasoning-bank-3OTF4DYQ.js +2 -0
  262. package/dist/cli/chunks/{quality-L4GQ6WX4.js → quality-KIIDHGNF.js} +2 -2
  263. package/dist/cli/chunks/{quality-gate-MJG66LKN.js → quality-gate-H65VECD3.js} +3 -3
  264. package/dist/cli/chunks/queen-coordinator-WTYH4TAN.js +2 -0
  265. package/dist/cli/chunks/{real-embeddings-HW4G2LWL.js → real-embeddings-DYIOLKQ3.js} +2 -2
  266. package/dist/cli/chunks/{ref-validation-FC7JOJ2C.js → ref-validation-CSBJOMZM.js} +2 -2
  267. package/dist/cli/chunks/{roocode-installer-KWS4CEIC.js → roocode-installer-G7OVYXEN.js} +2 -2
  268. package/dist/cli/chunks/router-DBBW4NC2.js +2 -0
  269. package/dist/cli/chunks/routing-feedback-W35QHCL4.js +2 -0
  270. package/dist/cli/chunks/{routing-handler-QF4WVB2S.js → routing-handler-ZNZPPI5Y.js} +2 -2
  271. package/dist/cli/chunks/{ruvector-commands-2MTCOUK6.js → ruvector-commands-C6IG3OY3.js} +2 -2
  272. package/dist/cli/chunks/rvf-dual-writer-X3NSL25Z.js +2 -0
  273. package/dist/cli/chunks/rvf-migration-adapter-TZR7GDOK.js +2 -0
  274. package/dist/cli/chunks/{rvf-migration-coordinator-BREJCXWN.js → rvf-migration-coordinator-4ATTHGHD.js} +2 -2
  275. package/dist/cli/chunks/rvf-native-adapter-HD25ZYV5.js +2 -0
  276. package/dist/cli/chunks/{rvf-store-integrity-KKC6HOJD.js → rvf-store-integrity-3G6LFLT3.js} +2 -2
  277. package/dist/cli/chunks/safe-db-ZS2QKANY.js +2 -0
  278. package/dist/cli/chunks/schedule-ZH6VNA32.js +2 -0
  279. package/dist/cli/chunks/scheduler-T6CD74B6.js +2 -0
  280. package/dist/cli/chunks/{security-OSAE7VAP.js → security-A3IMVLFM.js} +3 -3
  281. package/dist/cli/chunks/{shared-rvf-adapter-COUOS665.js → shared-rvf-adapter-VHWQ6US5.js} +2 -2
  282. package/dist/cli/chunks/{shared-rvf-dual-writer-YXMPZKQE.js → shared-rvf-dual-writer-JB3QS7IG.js} +2 -2
  283. package/dist/cli/chunks/sqlite-persistence-47WU5EKZ.js +2 -0
  284. package/dist/cli/chunks/{standalone-memory-E6JBMOIL.js → standalone-memory-DDNXCSBD.js} +2 -2
  285. package/dist/cli/chunks/{status-handler-AFTCIYIX.js → status-handler-2HK7XPEK.js} +2 -2
  286. package/dist/cli/chunks/{structural-health-2FROCEI4.js → structural-health-DSJVLEPV.js} +2 -2
  287. package/dist/cli/chunks/{sync-VAYTOWDC.js → sync-3MUV6S5E.js} +2 -2
  288. package/dist/cli/chunks/{sync-YIQYOFGW.js → sync-NTUR53PI.js} +2 -2
  289. package/dist/cli/chunks/{task-handler-KVQHDEX3.js → task-handler-74MZN2EO.js} +2 -2
  290. package/dist/cli/chunks/{task-handlers-MVVECQA6.js → task-handlers-VJR6EHRZ.js} +3 -3
  291. package/dist/cli/chunks/{test-5JSVTOMY.js → test-O6FK3FVF.js} +4 -4
  292. package/dist/cli/chunks/test-runner-process-2NPW3UDQ.js +2 -0
  293. package/dist/cli/chunks/{test-scheduling-HBOHVLI3.js → test-scheduling-Q6QEEOS6.js} +3 -3
  294. package/dist/cli/chunks/{token-bootstrap-5VEPTPFA.js → token-bootstrap-TTRCECLP.js} +2 -2
  295. package/dist/cli/chunks/{token-usage-TBJHDLY6.js → token-usage-YEEFWSSI.js} +2 -2
  296. package/dist/cli/chunks/{transformers-VAWYMHMZ.js → transformers-BZCHJJJT.js} +2 -2
  297. package/dist/cli/chunks/tree-sitter-wasm-parser-RZAND65G.js +2 -0
  298. package/dist/cli/chunks/{types-R5SDZU2E.js → types-4AOKZYOX.js} +2 -2
  299. package/dist/cli/chunks/unified-memory-FZ5K2C7W.js +2 -0
  300. package/dist/cli/chunks/unified-memory-hnsw-VREWX56M.js +2 -0
  301. package/dist/cli/chunks/unified-persistence-YZGMKX6B.js +2 -0
  302. package/dist/cli/chunks/{upgrade-K5PIHXRB.js → upgrade-2MWW6BT2.js} +2 -2
  303. package/dist/cli/chunks/{validate-RPTS7RYJ.js → validate-PAEV3GT5.js} +2 -2
  304. package/dist/cli/chunks/{validate-swarm-B2ZL556X.js → validate-swarm-ZIXACK5K.js} +2 -2
  305. package/dist/cli/chunks/visual-security-GXGSFBVA.js +2 -0
  306. package/dist/cli/chunks/{web-tree-sitter-K4DUJC32.js → web-tree-sitter-VLTXZFAB.js} +2 -2
  307. package/dist/cli/chunks/{windsurf-installer-OK2AJN35.js → windsurf-installer-VELMLOZF.js} +2 -2
  308. package/dist/cli/chunks/witness-chain-MRJKVCOW.js +2 -0
  309. package/dist/cli/chunks/witness-chain-WWHJKITG.js +2 -0
  310. package/dist/cli/chunks/{witness-chain-repair-L6Y5RFXR.js → witness-chain-repair-5SAXPETG.js} +2 -2
  311. package/dist/cli/chunks/{witness-chain-verifier-N4CW7FZX.js → witness-chain-verifier-MIDWD4JS.js} +2 -2
  312. package/dist/cli/chunks/{witness-key-manager-TDNPS3WD.js → witness-key-manager-OSVCWOB2.js} +2 -2
  313. package/dist/cli/chunks/{workflow-XRZA3YCY.js → workflow-MK7A7QCX.js} +4 -4
  314. package/dist/cli/chunks/workflow-orchestrator-SG7DV72E.js +2 -0
  315. package/dist/cli/chunks/{wrappers-5JIFWKN6.js → wrappers-5QFMCKXL.js} +2 -2
  316. package/dist/cli/commands/coverage.js +6 -0
  317. package/dist/cli/commands/learning-prune.d.ts +14 -0
  318. package/dist/cli/commands/learning-prune.js +105 -0
  319. package/dist/cli/commands/learning.js +9 -0
  320. package/dist/cli/handlers/brain-handler.js +12 -1
  321. package/dist/cli/utils/coverage-verdict.js +14 -3
  322. package/dist/context/compaction/index.d.ts +7 -0
  323. package/dist/context/compaction/index.js +30 -6
  324. package/dist/coordination/handlers/coverage-evidence.d.ts +19 -0
  325. package/dist/coordination/handlers/coverage-evidence.js +31 -2
  326. package/dist/coordination/handlers/coverage-handlers.js +5 -1
  327. package/dist/coordination/handlers/coverage-target.js +8 -1
  328. package/dist/coordination/handlers/quality-handlers.js +9 -1
  329. package/dist/coordination/result-saver-adapters.js +1 -0
  330. package/dist/coordination/result-saver.js +9 -5
  331. package/dist/domains/chaos-resilience/services/chaos-engineer.d.ts +1 -0
  332. package/dist/domains/chaos-resilience/services/chaos-engineer.js +23 -45
  333. package/dist/domains/coverage-analysis/collected-metrics.d.ts +22 -6
  334. package/dist/domains/coverage-analysis/collected-metrics.js +37 -12
  335. package/dist/domains/coverage-analysis/services/coverage-analyzer.js +2 -0
  336. package/dist/domains/defect-intelligence/services/defect-predictor.js +3 -6
  337. package/dist/domains/quality-assessment/coverage-report-event.d.ts +8 -0
  338. package/dist/domains/quality-assessment/coverage-report-event.js +22 -1
  339. package/dist/domains/quality-assessment/interfaces.d.ts +6 -0
  340. package/dist/domains/quality-assessment/services/quality-analyzer.d.ts +4 -0
  341. package/dist/domains/quality-assessment/services/quality-analyzer.js +63 -17
  342. package/dist/domains/test-execution/interfaces.d.ts +5 -0
  343. package/dist/domains/test-execution/services/test-executor.js +6 -0
  344. package/dist/init/init-wizard-hooks.d.ts +1 -1
  345. package/dist/init/init-wizard-hooks.js +7 -8
  346. package/dist/init/phases/07-hooks.js +90 -6
  347. package/dist/init/phases/08-mcp.js +9 -0
  348. package/dist/init/settings-merge.d.ts +13 -0
  349. package/dist/init/settings-merge.js +49 -2
  350. package/dist/integrations/agent-booster-wasm/agent_booster_wasm.js +849 -0
  351. package/dist/integrations/agent-booster-wasm/agent_booster_wasm_bg.wasm +0 -0
  352. package/dist/integrations/agent-booster-wasm/index.d.ts +8 -0
  353. package/dist/integrations/agent-booster-wasm/index.js +25 -2
  354. package/dist/integrations/agent-booster-wasm/package.json +16 -0
  355. package/dist/integrations/ruvector/brain-rvf-exporter.d.ts +25 -0
  356. package/dist/integrations/ruvector/brain-rvf-exporter.js +154 -61
  357. package/dist/learning/dream/dream-engine.d.ts +27 -3
  358. package/dist/learning/dream/dream-engine.js +97 -28
  359. package/dist/learning/dream/dream-lock-retry.d.ts +38 -0
  360. package/dist/learning/dream/dream-lock-retry.js +66 -0
  361. package/dist/learning/dream/speculative-dreamer.js +1 -1
  362. package/dist/learning/learning-retention.d.ts +103 -0
  363. package/dist/learning/learning-retention.js +213 -0
  364. package/dist/mcp/bundle.js +501 -496
  365. package/dist/mcp/handlers/domain-handler-configs.d.ts +9 -1
  366. package/dist/mcp/handlers/domain-handler-configs.js +24 -14
  367. package/dist/mcp/protocol-server.js +1 -1
  368. package/dist/mcp/tools/chaos-resilience/inject.d.ts +3 -4
  369. package/dist/mcp/tools/chaos-resilience/inject.js +11 -81
  370. package/dist/mcp/tools/learning-optimization/dream.d.ts +8 -0
  371. package/dist/mcp/tools/learning-optimization/dream.js +4 -0
  372. package/package.json +4 -2
  373. package/dist/cli/chunks/adapter-KCQDVYY2.js +0 -2
  374. package/dist/cli/chunks/agent-booster-wasm-6RRQWMNE.js +0 -2
  375. package/dist/cli/chunks/aqe-learning-engine-SAQOHSGN.js +0 -2
  376. package/dist/cli/chunks/base-WCACU3FN.js +0 -2
  377. package/dist/cli/chunks/brain-handler-GTQNHHZS.js +0 -94
  378. package/dist/cli/chunks/browser-workflow-G6IASEAP.js +0 -2
  379. package/dist/cli/chunks/chunk-C6JTLKG7.js +0 -141
  380. package/dist/cli/chunks/chunk-K65CGKLD.js +0 -8
  381. package/dist/cli/chunks/chunk-MB46UBGY.js +0 -3
  382. package/dist/cli/chunks/chunk-N4CYAKOX.js +0 -79
  383. package/dist/cli/chunks/chunk-PT4FMJPQ.js +0 -3
  384. package/dist/cli/chunks/chunk-S5AZCIZS.js +0 -2
  385. package/dist/cli/chunks/chunk-UT2VZ33P.js +0 -2
  386. package/dist/cli/chunks/client-TV3V2YZ5.js +0 -2
  387. package/dist/cli/chunks/core-handlers-PZT4OLWR.js +0 -2
  388. package/dist/cli/chunks/coverage-NV3C4IMM.js +0 -50
  389. package/dist/cli/chunks/cross-domain-router-QOFCZ7G4.js +0 -2
  390. package/dist/cli/chunks/dream-TRFBGDSQ.js +0 -2
  391. package/dist/cli/chunks/file-discovery-WCKGMSPZ.js +0 -2
  392. package/dist/cli/chunks/heartbeat-scheduler-P44A2OX3.js +0 -2
  393. package/dist/cli/chunks/hnsw-adapter-ZJQIQJKC.js +0 -2
  394. package/dist/cli/chunks/hnsw-index-HMG2GH3Z.js +0 -2
  395. package/dist/cli/chunks/hybrid-backend-B7M74PZG.js +0 -2
  396. package/dist/cli/chunks/impact-analyzer-PZYOVKQO.js +0 -2
  397. package/dist/cli/chunks/init-wizard-TZDJQK3U.js +0 -2
  398. package/dist/cli/chunks/kernel-Y6RRIOKW.js +0 -2
  399. package/dist/cli/chunks/knowledge-graph-BVD5Z66M.js +0 -2
  400. package/dist/cli/chunks/learning-6KDH7FK4.js +0 -122
  401. package/dist/cli/chunks/llm-router-service-KHCAMSUU.js +0 -2
  402. package/dist/cli/chunks/load-test-RUF7DZA5.js +0 -2
  403. package/dist/cli/chunks/memory-backend-7ZLFOVGG.js +0 -2
  404. package/dist/cli/chunks/pattern-null-store-RY6CVYHP.js +0 -2
  405. package/dist/cli/chunks/project-root-IO5KRNGL.js +0 -2
  406. package/dist/cli/chunks/protocol-executor-U2CUDWDE.js +0 -2
  407. package/dist/cli/chunks/qe-reasoning-bank-DQSSX2IP.js +0 -2
  408. package/dist/cli/chunks/queen-coordinator-6FN4BZIX.js +0 -2
  409. package/dist/cli/chunks/router-YUO3I7RU.js +0 -2
  410. package/dist/cli/chunks/routing-feedback-36SLQGJE.js +0 -2
  411. package/dist/cli/chunks/rvf-dual-writer-FRYZH3WZ.js +0 -2
  412. package/dist/cli/chunks/rvf-migration-adapter-XXNITL5I.js +0 -2
  413. package/dist/cli/chunks/rvf-native-adapter-D2WWKJIV.js +0 -2
  414. package/dist/cli/chunks/safe-db-4RRIGRXD.js +0 -2
  415. package/dist/cli/chunks/schedule-25RTO4DQ.js +0 -2
  416. package/dist/cli/chunks/scheduler-BPIOJZ5P.js +0 -2
  417. package/dist/cli/chunks/sqlite-persistence-EDF47DDX.js +0 -2
  418. package/dist/cli/chunks/test-runner-process-LEPF2OSS.js +0 -2
  419. package/dist/cli/chunks/tree-sitter-wasm-parser-TSZTCMFV.js +0 -2
  420. package/dist/cli/chunks/unified-memory-TLGSSLMI.js +0 -2
  421. package/dist/cli/chunks/unified-memory-hnsw-MSUR7ZOO.js +0 -2
  422. package/dist/cli/chunks/unified-persistence-VFFOTWK7.js +0 -2
  423. package/dist/cli/chunks/visual-security-6Q44XNLB.js +0 -2
  424. package/dist/cli/chunks/witness-chain-KDOMXDQX.js +0 -2
  425. package/dist/cli/chunks/witness-chain-N3OY2RMH.js +0 -2
  426. package/dist/cli/chunks/workflow-orchestrator-CVNNT2RJ.js +0 -2
@@ -19,14 +19,24 @@ import { toErrorMessage } from '../../shared/error-utils.js';
19
19
  import { PatternMutationError } from '../pattern-mutation-error.js';
20
20
  import { LoggerFactory } from '../../logging/index.js';
21
21
  const dreamLogger = LoggerFactory.create('dream-engine');
22
+ /** #1239: an unreadable retention setting is reported once per process. */
23
+ let retentionWarningsLogged = false;
24
+ /**
25
+ * #1239: how long retention waits for a locked database. better-sqlite3 waits
26
+ * synchronously, and retention is optional (the next dream retries), so it
27
+ * gives up quickly instead of using the engine's 60 s commit wait.
28
+ */
29
+ export const RETENTION_BUSY_TIMEOUT_MS = 1000;
22
30
  import { v4 as uuidv4 } from 'uuid';
23
31
  import { getUnifiedPersistence } from '../../kernel/unified-persistence.js';
24
32
  import { registerStoreCloser } from '../../kernel/process-lifecycle.js';
25
33
  import { ConceptGraph } from './concept-graph.js';
34
+ import { DREAM_LOCK_WAIT_MS, DREAM_SHUTDOWN_LOCK_WAIT_MS, isBusyError, retryWhileBusy, withBusyTimeout, } from './dream-lock-retry.js';
26
35
  import { SpreadingActivation, } from './spreading-activation.js';
27
36
  import { InsightGenerator, } from './insight-generator.js';
28
37
  import { DEFAULT_VALIDATION_THRESHOLDS, } from './rvcow-branch-manager.js';
29
38
  import { commitDream, markAbandonedCycles, ABANDONED_CYCLE_GRACE_MS, } from './dream-commit.js';
39
+ import { describeRetention, resolveDefaultRetention, runDreamRetention, } from '../learning-retention.js';
30
40
  /**
31
41
  * Default DreamEngine configuration
32
42
  */
@@ -268,16 +278,14 @@ export class DreamEngine {
268
278
  await this.persistence.initialize();
269
279
  }
270
280
  this.db = this.persistence.getDatabase();
271
- // ADR-001 Option C: dynamic-import paths in checkAndTriggerDream() open
272
- // a fresh handle that the hook/worker busy_timeout pragmas never reach.
273
- // 60s patient timeout here keeps dream cycles from failing under WAL
274
- // contention from MCP workers (was 71% failure rate observed).
275
- try {
276
- this.db.pragma('busy_timeout = 60000');
277
- }
278
- catch { /* fail-soft */ }
279
- // Migrate legacy schema: rename 'duration' → 'duration_ms' if needed
280
- this.migrateSchema();
281
+ // #1253: no 60 s busy_timeout on this shared connection. better-sqlite3
282
+ // waits synchronously, so it froze the whole process (the MCP event loop)
283
+ // while another writer held the database. Dream writes instead wait
284
+ // briefly per attempt and retry asynchronously (dream-lock-retry.ts),
285
+ // which keeps the patience that avoided failures under contention (#1060).
286
+ // Migrate legacy schema: rename 'duration' → 'duration_ms' if needed.
287
+ // #1253: a short lock wait only; migrateSchema() logs and carries on.
288
+ withBusyTimeout(this.db, DREAM_LOCK_WAIT_MS, () => this.migrateSchema());
281
289
  // Initialize concept graph (shares same unified persistence)
282
290
  this.graph = new ConceptGraph();
283
291
  await this.graph.initialize();
@@ -287,9 +295,19 @@ export class DreamEngine {
287
295
  'committed in one short transaction instead of a SAVEPOINT held across the dream');
288
296
  }
289
297
  // #1060: a process that exited mid-dream left its cycle 'running'.
290
- const abandoned = markAbandonedCycles(this.db, Math.max(this.config.maxDurationMs, MAX_TOOL_DREAM_MS) + ABANDONED_CYCLE_GRACE_MS);
291
- if (abandoned > 0) {
292
- dreamLogger.info('Marked abandoned dream cycles as interrupted', { abandoned });
298
+ // #1253: housekeeping, so a locked database skips it after a short
299
+ // wait instead of blocking the process; the next initialize() retries.
300
+ const db = this.db;
301
+ try {
302
+ const abandoned = withBusyTimeout(db, DREAM_LOCK_WAIT_MS, () => markAbandonedCycles(db, Math.max(this.config.maxDurationMs, MAX_TOOL_DREAM_MS) + ABANDONED_CYCLE_GRACE_MS));
303
+ if (abandoned > 0) {
304
+ dreamLogger.info('Marked abandoned dream cycles as interrupted', { abandoned });
305
+ }
306
+ }
307
+ catch (error) {
308
+ if (!isBusyError(error))
309
+ throw error;
310
+ dreamLogger.warn('Abandoned dream cycle sweep skipped: database is locked', { error: toErrorMessage(error) });
293
311
  }
294
312
  this.initialized = true;
295
313
  this.closing = false;
@@ -424,7 +442,7 @@ export class DreamEngine {
424
442
  let committed = false;
425
443
  try {
426
444
  if (commitResults)
427
- await this.saveCycle(cycle);
445
+ await this.saveCycle(cycle, live);
428
446
  if (!live())
429
447
  throw new Error('Dream cycle cancelled');
430
448
  // 1. Check we have enough concepts
@@ -474,8 +492,10 @@ export class DreamEngine {
474
492
  committed = true; // nothing to record: the caller decides
475
493
  return { ...result, pending: computed };
476
494
  }
477
- result.commitDurationMs = this.commitComputed(db, computed);
495
+ const commit = await this.commitComputed(db, computed, live);
478
496
  committed = true;
497
+ result.commitDurationMs = commit.durationMs;
498
+ result.retention = commit.retention;
479
499
  return result;
480
500
  }
481
501
  catch (error) {
@@ -488,7 +508,7 @@ export class DreamEngine {
488
508
  cycle.durationMs = Date.now() - startTime;
489
509
  if (commitResults && this.db === db) {
490
510
  try {
491
- this.updateCycleSync(cycle);
511
+ await retryWhileBusy(db, () => this.updateCycleSync(cycle), { shouldContinue: () => this.db === db });
492
512
  }
493
513
  catch { /* best effort */ }
494
514
  }
@@ -517,9 +537,10 @@ export class DreamEngine {
517
537
  * #1060: write the results of a `dream(…, { commit: false })` run, in the
518
538
  * same single transaction a normal dream uses. Returns the commit duration
519
539
  * in ms. Throws (and writes nothing) if the engine is closed or the write
520
- * fails.
540
+ * fails. #1253: async, because a locked database is retried without
541
+ * blocking the process.
521
542
  */
522
- commitDreamResult(result) {
543
+ async commitDreamResult(result) {
523
544
  this.ensureInitialized();
524
545
  if (this.closing) {
525
546
  throw new Error('Dream engine is closing; nothing is committed');
@@ -527,14 +548,23 @@ export class DreamEngine {
527
548
  if (!result.pending) {
528
549
  throw new Error('Dream result has nothing pending to commit (it was already committed)');
529
550
  }
530
- const duration = this.commitComputed(this.db, result.pending);
551
+ const db = this.db;
552
+ const commit = await this.commitComputed(db, result.pending, () => !this.closing && this.db === db);
531
553
  result.pending = undefined;
532
- result.commitDurationMs = duration;
533
- return duration;
554
+ result.commitDurationMs = commit.durationMs;
555
+ result.retention = commit.retention;
556
+ return commit.durationMs;
534
557
  }
535
- /** Commit a computed dream, then record it in the witness chain (#1060). */
536
- commitComputed(db, computed) {
537
- const commit = commitDream(db, computed);
558
+ /**
559
+ * Commit a computed dream, then record it in the witness chain (#1060) and
560
+ * run the default retention steps (#1239).
561
+ */
562
+ async commitComputed(db, computed, live) {
563
+ // #1253: retry a locked database asynchronously; each attempt is short.
564
+ const commit = await retryWhileBusy(db, () => commitDream(db, computed), {
565
+ shouldContinue: live,
566
+ cancelledError: () => new Error('Dream cycle cancelled'),
567
+ });
538
568
  try {
539
569
  this._witnessChain?.append('DREAM_COMMIT', {
540
570
  cycleId: computed.cycle.id,
@@ -544,7 +574,43 @@ export class DreamEngine {
544
574
  }, 'dream-engine');
545
575
  }
546
576
  catch { /* best-effort witness */ }
547
- return commit.commitDurationMs;
577
+ return { durationMs: commit.commitDurationMs, retention: this.runDefaultRetention(db) };
578
+ }
579
+ /**
580
+ * #1239: after a committed dream, drop failed cycles past their retention
581
+ * window and outcome concepts beyond the cap when AQE_DREAM_RETENTION=on;
582
+ * otherwise only count what that would remove. The dream is already
583
+ * committed, so a failure here (a locked database, say) is only logged.
584
+ */
585
+ runDefaultRetention(db) {
586
+ const settings = resolveDefaultRetention();
587
+ if (settings.warnings.length > 0 && !retentionWarningsLogged) {
588
+ retentionWarningsLogged = true;
589
+ for (const warning of settings.warnings)
590
+ dreamLogger.warn(warning);
591
+ }
592
+ const previousBusyTimeout = db.pragma('busy_timeout', { simple: true });
593
+ try {
594
+ db.pragma(`busy_timeout = ${RETENTION_BUSY_TIMEOUT_MS}`);
595
+ const report = runDreamRetention(db, settings);
596
+ if (report.enabled) {
597
+ for (const step of report.steps) {
598
+ if (step.affected > 0)
599
+ dreamLogger.info(`Retention ${describeRetention(step)}`);
600
+ }
601
+ }
602
+ return report;
603
+ }
604
+ catch (error) {
605
+ dreamLogger.warn('Dream retention skipped after dream commit', { error: toErrorMessage(error) });
606
+ return { enabled: settings.enabled, steps: [], error: toErrorMessage(error) };
607
+ }
608
+ finally {
609
+ try {
610
+ db.pragma(`busy_timeout = ${previousBusyTimeout}`);
611
+ }
612
+ catch { /* connection gone */ }
613
+ }
548
614
  }
549
615
  /**
550
616
  * #1060: build a synchronous handler that stops a still-running dream and
@@ -562,7 +628,9 @@ export class DreamEngine {
562
628
  cycle.endTime = new Date();
563
629
  cycle.durationMs = Date.now() - startTime;
564
630
  try {
565
- this.updateCycleSync(cycle);
631
+ // #1253: a short wait only; if the database stays locked, the
632
+ // abandoned-cycle sweep marks the cycle interrupted later.
633
+ withBusyTimeout(this.db, DREAM_SHUTDOWN_LOCK_WAIT_MS, () => this.updateCycleSync(cycle));
566
634
  }
567
635
  catch {
568
636
  // Best effort during shutdown
@@ -861,16 +929,17 @@ export class DreamEngine {
861
929
  // ==========================================================================
862
930
  // Persistence
863
931
  // ==========================================================================
864
- async saveCycle(cycle) {
932
+ async saveCycle(cycle, live) {
865
933
  if (!this.db)
866
934
  return;
935
+ const db = this.db;
867
936
  const stmt = this.db.prepare(`
868
937
  INSERT INTO dream_cycles
869
938
  (id, start_time, end_time, duration_ms, concepts_processed, associations_found,
870
939
  insights_generated, status, error, created_at)
871
940
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
872
941
  `);
873
- stmt.run(cycle.id, cycle.startTime.toISOString(), cycle.endTime?.toISOString() ?? null, cycle.durationMs ?? null, cycle.conceptsProcessed, cycle.associationsFound, cycle.insightsGenerated, cycle.status, cycle.error ?? null, cycle.startTime.toISOString());
942
+ await retryWhileBusy(db, () => stmt.run(cycle.id, cycle.startTime.toISOString(), cycle.endTime?.toISOString() ?? null, cycle.durationMs ?? null, cycle.conceptsProcessed, cycle.associationsFound, cycle.insightsGenerated, cycle.status, cycle.error ?? null, cycle.startTime.toISOString()), { shouldContinue: live, cancelledError: () => new Error('Dream cycle cancelled') });
874
943
  }
875
944
  updateCycleSync(cycle) {
876
945
  if (!this.db)
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Lock waits for dream writes (#1253).
3
+ *
4
+ * better-sqlite3 waits for a locked database synchronously, so a long
5
+ * busy_timeout freezes the whole process: in the MCP server that is the event
6
+ * loop and every tool call. Dream writes therefore wait only briefly per
7
+ * attempt and retry asynchronously, so other work runs between attempts.
8
+ */
9
+ import type { Database as DatabaseType } from 'better-sqlite3';
10
+ /** Longest a single dream write attempt blocks the process on a locked database. */
11
+ export declare const DREAM_LOCK_WAIT_MS = 200;
12
+ /** Total time a dream write keeps retrying a locked database before it fails. */
13
+ export declare const DREAM_LOCK_RETRY_BUDGET_MS = 60000;
14
+ /** True for SQLite "database is locked" / "busy" failures. */
15
+ export declare function isBusyError(error: unknown): boolean;
16
+ /** Run `fn` with a temporary busy_timeout, restoring the connection's previous value. */
17
+ export declare function withBusyTimeout<T>(db: DatabaseType, timeoutMs: number, fn: () => T): T;
18
+ export interface RetryWhileBusyOptions {
19
+ /** Synchronous wait per attempt (default DREAM_LOCK_WAIT_MS). */
20
+ waitMs?: number;
21
+ /** Total retry time before the busy error is thrown (default DREAM_LOCK_RETRY_BUDGET_MS). */
22
+ budgetMs?: number;
23
+ /** Checked before every attempt; when false, `cancelledError` is thrown instead of retrying. */
24
+ shouldContinue?: () => boolean;
25
+ cancelledError?: () => Error;
26
+ /** Injectable for tests. */
27
+ sleep?: (ms: number) => Promise<void>;
28
+ now?: () => number;
29
+ }
30
+ /**
31
+ * Run a synchronous write, retrying while the database is locked. Each attempt
32
+ * blocks for at most `waitMs`; between attempts the event loop is free. Errors
33
+ * other than a busy database are thrown at once.
34
+ */
35
+ export declare function retryWhileBusy<T>(db: DatabaseType, fn: () => T, options?: RetryWhileBusyOptions): Promise<T>;
36
+ /** Wait for the synchronous best-effort write made while a dream is interrupted at shutdown. */
37
+ export declare const DREAM_SHUTDOWN_LOCK_WAIT_MS = 1000;
38
+ //# sourceMappingURL=dream-lock-retry.d.ts.map
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Lock waits for dream writes (#1253).
3
+ *
4
+ * better-sqlite3 waits for a locked database synchronously, so a long
5
+ * busy_timeout freezes the whole process: in the MCP server that is the event
6
+ * loop and every tool call. Dream writes therefore wait only briefly per
7
+ * attempt and retry asynchronously, so other work runs between attempts.
8
+ */
9
+ /** Longest a single dream write attempt blocks the process on a locked database. */
10
+ export const DREAM_LOCK_WAIT_MS = 200;
11
+ /** Total time a dream write keeps retrying a locked database before it fails. */
12
+ export const DREAM_LOCK_RETRY_BUDGET_MS = 60_000;
13
+ /** Longest pause between attempts; the pause doubles from 25 ms up to this. */
14
+ const MAX_BACKOFF_MS = 1000;
15
+ /** True for SQLite "database is locked" / "busy" failures. */
16
+ export function isBusyError(error) {
17
+ const code = error?.code;
18
+ if (typeof code === 'string' && /^SQLITE_(BUSY|LOCKED)/.test(code))
19
+ return true;
20
+ const message = error instanceof Error ? error.message : String(error);
21
+ return /database is locked|database table is locked|SQLITE_BUSY/i.test(message);
22
+ }
23
+ /** Run `fn` with a temporary busy_timeout, restoring the connection's previous value. */
24
+ export function withBusyTimeout(db, timeoutMs, fn) {
25
+ const previous = db.pragma('busy_timeout', { simple: true });
26
+ db.pragma(`busy_timeout = ${timeoutMs}`);
27
+ try {
28
+ return fn();
29
+ }
30
+ finally {
31
+ try {
32
+ db.pragma(`busy_timeout = ${previous}`);
33
+ }
34
+ catch { /* connection closed */ }
35
+ }
36
+ }
37
+ /**
38
+ * Run a synchronous write, retrying while the database is locked. Each attempt
39
+ * blocks for at most `waitMs`; between attempts the event loop is free. Errors
40
+ * other than a busy database are thrown at once.
41
+ */
42
+ export async function retryWhileBusy(db, fn, options = {}) {
43
+ const waitMs = options.waitMs ?? DREAM_LOCK_WAIT_MS;
44
+ const budgetMs = options.budgetMs ?? DREAM_LOCK_RETRY_BUDGET_MS;
45
+ const sleep = options.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
46
+ const now = options.now ?? Date.now;
47
+ const started = now();
48
+ let backoff = 25;
49
+ for (;;) {
50
+ if (options.shouldContinue && !options.shouldContinue()) {
51
+ throw options.cancelledError?.() ?? new Error('Cancelled while waiting for a locked database');
52
+ }
53
+ try {
54
+ return withBusyTimeout(db, waitMs, fn);
55
+ }
56
+ catch (error) {
57
+ if (!isBusyError(error) || now() - started + backoff >= budgetMs)
58
+ throw error;
59
+ }
60
+ await sleep(backoff);
61
+ backoff = Math.min(backoff * 2, MAX_BACKOFF_MS);
62
+ }
63
+ }
64
+ /** Wait for the synchronous best-effort write made while a dream is interrupted at shutdown. */
65
+ export const DREAM_SHUTDOWN_LOCK_WAIT_MS = 1000;
66
+ //# sourceMappingURL=dream-lock-retry.js.map
@@ -117,7 +117,7 @@ export class SpeculativeDreamer {
117
117
  let commitDurationMs;
118
118
  if (winner?.result) {
119
119
  try {
120
- commitDurationMs = this.engine.commitDreamResult(winner.result);
120
+ commitDurationMs = await this.engine.commitDreamResult(winner.result);
121
121
  winner.selected = true;
122
122
  }
123
123
  catch (error) {
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Learning Retention (#1239)
3
+ *
4
+ * Bounds the learning tables that otherwise grow for as long as a project
5
+ * lives. Two kinds of step, kept apart on purpose:
6
+ *
7
+ * - Dream retention steps remove only rows that carry no learning value.
8
+ * They are off by default. With `AQE_DREAM_RETENTION=on` they run after
9
+ * each committed dream cycle; while off, the dream reports what they
10
+ * would remove (COUNT queries only, nothing is written):
11
+ * - failed/interrupted `dream_cycles` past a retention window. A cycle
12
+ * that did not commit wrote no insights, and any cycle that still has
13
+ * an insight is kept.
14
+ * - `outcome` concept nodes beyond a cap, with their edges. They are
15
+ * derived from `qe_pattern_usage`, which is not touched, and only the
16
+ * newest 100 usage rows are ever loaded back, so a cap >= 100 does not
17
+ * churn.
18
+ *
19
+ * - Opt-in steps drop data that could still matter to someone, so they run
20
+ * only from `aqe learning prune`, which defaults to a dry run:
21
+ * - compacting soft-archived and merged experiences: `result_json` and the
22
+ * embedding are cleared, the row and its counters stay (the experience
23
+ * count stays monotonic, v3.9.22).
24
+ * - `routing_outcomes` older than a number of days.
25
+ *
26
+ * Every step reports the row counts it measured before and after, or, in a
27
+ * dry run, the counts it would change.
28
+ */
29
+ import type { Database as DatabaseType } from 'better-sqlite3';
30
+ export interface TableCount {
31
+ readonly table: string;
32
+ readonly before: number;
33
+ readonly after: number;
34
+ }
35
+ export interface RetentionStepResult {
36
+ readonly step: RetentionStep;
37
+ readonly dryRun: boolean;
38
+ /** Rows deleted, or for compaction rows whose payload was cleared. */
39
+ readonly affected: number;
40
+ /**
41
+ * Row counts per table. `after` is read back after the write; in a dry run
42
+ * it is the projection (`before` minus the rows the step would delete).
43
+ */
44
+ readonly tables: readonly TableCount[];
45
+ /** Bytes of payload removed (compaction only), measured with length(). */
46
+ readonly payloadBytes?: number;
47
+ }
48
+ export type RetentionStep = 'failed-dream-cycles' | 'outcome-concepts' | 'compact-experiences' | 'routing-outcomes';
49
+ export declare const DEFAULT_FAILED_DREAM_CYCLE_RETENTION_DAYS = 7;
50
+ export declare const DEFAULT_OUTCOME_CONCEPT_CAP = 2000;
51
+ /** Below this the cap would delete outcome nodes that the next dream reloads. */
52
+ export declare const MIN_OUTCOME_CONCEPT_CAP = 100;
53
+ /** Failed or interrupted cycles older than `retentionDays` that have no insight. */
54
+ export declare function pruneFailedDreamCycles(db: DatabaseType, options?: {
55
+ retentionDays?: number;
56
+ dryRun?: boolean;
57
+ }): RetentionStepResult;
58
+ /** Keep the newest `maxNodes` outcome concept nodes; delete the rest and their edges. */
59
+ export declare function capOutcomeConcepts(db: DatabaseType, options?: {
60
+ maxNodes?: number;
61
+ dryRun?: boolean;
62
+ }): RetentionStepResult;
63
+ /** Clear `result_json` and the embedding of archived and merged experiences. */
64
+ export declare function compactConsolidatedExperiences(db: DatabaseType, options?: {
65
+ dryRun?: boolean;
66
+ }): RetentionStepResult;
67
+ /** Delete routing outcomes older than `olderThanDays`. */
68
+ export declare function pruneRoutingOutcomes(db: DatabaseType, options: {
69
+ olderThanDays: number;
70
+ dryRun?: boolean;
71
+ }): RetentionStepResult;
72
+ export interface DefaultRetentionSettings {
73
+ /** AQE_DREAM_RETENTION: false (the default) previews the steps instead of running them. */
74
+ readonly enabled: boolean;
75
+ /** null = off */
76
+ readonly failedDreamCycleRetentionDays: number | null;
77
+ /** null = off */
78
+ readonly outcomeConceptCap: number | null;
79
+ readonly warnings: readonly string[];
80
+ }
81
+ /**
82
+ * Read `AQE_DREAM_RETENTION` (off by default) and the per-step settings
83
+ * `AQE_FAILED_DREAM_CYCLE_RETENTION_DAYS` (default 7) and
84
+ * `AQE_OUTCOME_CONCEPT_CAP` (default 2000). Each step setting accepts "off".
85
+ */
86
+ export declare function resolveDefaultRetention(env?: Readonly<Record<string, string | undefined>>): DefaultRetentionSettings;
87
+ export interface DreamRetentionReport {
88
+ /** False: the steps ran as a dry run and wrote nothing. */
89
+ readonly enabled: boolean;
90
+ readonly steps: readonly RetentionStepResult[];
91
+ /** Set when retention could not run (a locked database, say); nothing was deleted. */
92
+ readonly error?: string;
93
+ }
94
+ /**
95
+ * The dream retention steps that are not switched off individually: run
96
+ * when retention is enabled, otherwise previewed as a dry run.
97
+ */
98
+ export declare function runDreamRetention(db: DatabaseType, settings?: DefaultRetentionSettings): DreamRetentionReport;
99
+ /** Lines for a dream's output: what retention removed, or would remove while off. */
100
+ export declare function describeDreamRetention(report: DreamRetentionReport): string[];
101
+ /** One line per step, for logs: "outcome-concepts: 3000 removed (concept_nodes 5000 -> 2000, ...)". */
102
+ export declare function describeRetention(result: RetentionStepResult): string;
103
+ //# sourceMappingURL=learning-retention.d.ts.map
@@ -0,0 +1,213 @@
1
+ /**
2
+ * Learning Retention (#1239)
3
+ *
4
+ * Bounds the learning tables that otherwise grow for as long as a project
5
+ * lives. Two kinds of step, kept apart on purpose:
6
+ *
7
+ * - Dream retention steps remove only rows that carry no learning value.
8
+ * They are off by default. With `AQE_DREAM_RETENTION=on` they run after
9
+ * each committed dream cycle; while off, the dream reports what they
10
+ * would remove (COUNT queries only, nothing is written):
11
+ * - failed/interrupted `dream_cycles` past a retention window. A cycle
12
+ * that did not commit wrote no insights, and any cycle that still has
13
+ * an insight is kept.
14
+ * - `outcome` concept nodes beyond a cap, with their edges. They are
15
+ * derived from `qe_pattern_usage`, which is not touched, and only the
16
+ * newest 100 usage rows are ever loaded back, so a cap >= 100 does not
17
+ * churn.
18
+ *
19
+ * - Opt-in steps drop data that could still matter to someone, so they run
20
+ * only from `aqe learning prune`, which defaults to a dry run:
21
+ * - compacting soft-archived and merged experiences: `result_json` and the
22
+ * embedding are cleared, the row and its counters stay (the experience
23
+ * count stays monotonic, v3.9.22).
24
+ * - `routing_outcomes` older than a number of days.
25
+ *
26
+ * Every step reports the row counts it measured before and after, or, in a
27
+ * dry run, the counts it would change.
28
+ */
29
+ export const DEFAULT_FAILED_DREAM_CYCLE_RETENTION_DAYS = 7;
30
+ export const DEFAULT_OUTCOME_CONCEPT_CAP = 2000;
31
+ /** Below this the cap would delete outcome nodes that the next dream reloads. */
32
+ export const MIN_OUTCOME_CONCEPT_CAP = 100;
33
+ function tableExists(db, table) {
34
+ return !!db.prepare(`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?`).get(table);
35
+ }
36
+ function count(db, sql, ...params) {
37
+ return db.prepare(sql).get(...params).n;
38
+ }
39
+ function rowCount(db, table) {
40
+ return count(db, `SELECT COUNT(*) AS n FROM ${table}`);
41
+ }
42
+ /**
43
+ * Measure, then apply, in one transaction, reading the table counts around
44
+ * it. A real run is IMMEDIATE (waits on busy_timeout instead of failing on
45
+ * lock upgrade); a dry run only reads.
46
+ */
47
+ function runStep(db, step, tables, dryRun, measure, apply) {
48
+ if (!tables.every(t => tableExists(db, t))) {
49
+ return { step, dryRun, affected: 0, tables: [] };
50
+ }
51
+ const run = db.transaction(() => {
52
+ const before = tables.map(t => rowCount(db, t));
53
+ const { affected, deletes, payloadBytes } = measure();
54
+ if (!dryRun && affected > 0)
55
+ apply();
56
+ const after = dryRun
57
+ ? tables.map((t, i) => before[i] - (deletes[t] ?? 0))
58
+ : tables.map(t => rowCount(db, t));
59
+ return {
60
+ step,
61
+ dryRun,
62
+ affected,
63
+ tables: tables.map((table, i) => ({ table, before: before[i], after: after[i] })),
64
+ ...(payloadBytes !== undefined ? { payloadBytes } : {}),
65
+ };
66
+ });
67
+ return dryRun ? run() : run.immediate();
68
+ }
69
+ // ---------------------------------------------------------------------------
70
+ // Default steps
71
+ // ---------------------------------------------------------------------------
72
+ /** Failed or interrupted cycles older than `retentionDays` that have no insight. */
73
+ export function pruneFailedDreamCycles(db, options = {}) {
74
+ const retentionDays = options.retentionDays ?? DEFAULT_FAILED_DREAM_CYCLE_RETENTION_DAYS;
75
+ assertWholeNumber('retentionDays', retentionDays, 1);
76
+ // julianday() reads both the ISO strings the engine writes and SQLite's own
77
+ // datetime('now') format, which a plain string comparison would mix up.
78
+ const where = `status IN ('failed', 'interrupted')
79
+ AND julianday(COALESCE(end_time, start_time, created_at)) < julianday('now', ?)
80
+ AND NOT EXISTS (SELECT 1 FROM dream_insights i WHERE i.cycle_id = dream_cycles.id)`;
81
+ const window = `-${retentionDays} days`;
82
+ return runStep(db, 'failed-dream-cycles', ['dream_cycles', 'dream_insights'], options.dryRun ?? false, () => {
83
+ const n = count(db, `SELECT COUNT(*) AS n FROM dream_cycles WHERE ${where}`, window);
84
+ return { affected: n, deletes: { dream_cycles: n } };
85
+ }, () => { db.prepare(`DELETE FROM dream_cycles WHERE ${where}`).run(window); });
86
+ }
87
+ /** Keep the newest `maxNodes` outcome concept nodes; delete the rest and their edges. */
88
+ export function capOutcomeConcepts(db, options = {}) {
89
+ const maxNodes = options.maxNodes ?? DEFAULT_OUTCOME_CONCEPT_CAP;
90
+ assertWholeNumber('maxNodes', maxNodes, MIN_OUTCOME_CONCEPT_CAP);
91
+ const doomed = `SELECT id FROM concept_nodes WHERE concept_type = 'outcome'
92
+ ORDER BY created_at DESC, id DESC LIMIT -1 OFFSET ?`;
93
+ return runStep(db, 'outcome-concepts', ['concept_nodes', 'concept_edges'], options.dryRun ?? false, () => {
94
+ const nodes = count(db, `SELECT COUNT(*) AS n FROM (${doomed})`, maxNodes);
95
+ const edges = count(db, `SELECT COUNT(*) AS n FROM concept_edges WHERE source IN (${doomed}) OR target IN (${doomed})`, maxNodes, maxNodes);
96
+ return { affected: nodes, deletes: { concept_nodes: nodes, concept_edges: edges } };
97
+ }, () => {
98
+ // Edges first and explicitly: the ON DELETE CASCADE only fires when the
99
+ // connection has foreign_keys on, which not every caller sets.
100
+ db.prepare(`DELETE FROM concept_edges WHERE source IN (${doomed}) OR target IN (${doomed})`)
101
+ .run(maxNodes, maxNodes);
102
+ db.prepare(`DELETE FROM concept_nodes WHERE id IN (${doomed})`).run(maxNodes);
103
+ });
104
+ }
105
+ // ---------------------------------------------------------------------------
106
+ // Opt-in steps (aqe learning prune)
107
+ // ---------------------------------------------------------------------------
108
+ /** Soft-archived ('archived') and merged (survivor id) rows; 'contradicted' is left alone. */
109
+ const CONSOLIDATED = `consolidated_into IS NOT NULL AND consolidated_into <> 'contradicted'`;
110
+ const HAS_PAYLOAD = `(result_json IS NOT NULL OR embedding IS NOT NULL)`;
111
+ /** Clear `result_json` and the embedding of archived and merged experiences. */
112
+ export function compactConsolidatedExperiences(db, options = {}) {
113
+ const where = `${CONSOLIDATED} AND ${HAS_PAYLOAD}`;
114
+ return runStep(db, 'compact-experiences', ['captured_experiences'], options.dryRun ?? false, () => {
115
+ const row = db.prepare(`SELECT COUNT(*) AS n,
116
+ COALESCE(SUM(COALESCE(length(result_json), 0) + COALESCE(length(embedding), 0)), 0) AS bytes
117
+ FROM captured_experiences WHERE ${where}`).get();
118
+ return { affected: row.n, deletes: {}, payloadBytes: row.bytes };
119
+ }, () => {
120
+ db.prepare(`UPDATE captured_experiences
121
+ SET result_json = NULL, embedding = NULL, embedding_dimension = NULL
122
+ WHERE ${where}`).run();
123
+ });
124
+ }
125
+ /** Delete routing outcomes older than `olderThanDays`. */
126
+ export function pruneRoutingOutcomes(db, options) {
127
+ assertWholeNumber('olderThanDays', options.olderThanDays, 1);
128
+ const where = `julianday(created_at) < julianday('now', ?)`;
129
+ const window = `-${options.olderThanDays} days`;
130
+ return runStep(db, 'routing-outcomes', ['routing_outcomes'], options.dryRun ?? false, () => {
131
+ const n = count(db, `SELECT COUNT(*) AS n FROM routing_outcomes WHERE ${where}`, window);
132
+ return { affected: n, deletes: { routing_outcomes: n } };
133
+ }, () => { db.prepare(`DELETE FROM routing_outcomes WHERE ${where}`).run(window); });
134
+ }
135
+ const OFF_VALUES = new Set(['off', 'false', 'no', '0']);
136
+ function parseSetting(name, raw, fallback, min, warnings) {
137
+ if (raw === undefined || raw.trim() === '')
138
+ return fallback;
139
+ const value = raw.trim().toLowerCase();
140
+ if (OFF_VALUES.has(value))
141
+ return null;
142
+ if (/^\d+$/.test(value) && Number(value) >= min)
143
+ return Number(value);
144
+ // These settings delete rows, so a value that cannot be read turns the step off.
145
+ warnings.push(`Invalid ${name}=${JSON.stringify(raw)}; expected a whole number >= ${min} or "off". ` +
146
+ 'That retention step is off until this is fixed; nothing is deleted by it.');
147
+ return null;
148
+ }
149
+ const ON_VALUES = new Set(['on', 'true', 'yes', '1']);
150
+ /** Unset or "off" disables; "on" enables; anything else disables with a warning. */
151
+ function parseSwitch(name, raw, warnings) {
152
+ if (raw === undefined || raw.trim() === '')
153
+ return false;
154
+ const value = raw.trim().toLowerCase();
155
+ if (ON_VALUES.has(value))
156
+ return true;
157
+ if (!OFF_VALUES.has(value)) {
158
+ warnings.push(`Invalid ${name}=${JSON.stringify(raw)}; expected "on" or "off". ` +
159
+ 'Dream retention stays off until this is fixed; nothing is deleted.');
160
+ }
161
+ return false;
162
+ }
163
+ /**
164
+ * Read `AQE_DREAM_RETENTION` (off by default) and the per-step settings
165
+ * `AQE_FAILED_DREAM_CYCLE_RETENTION_DAYS` (default 7) and
166
+ * `AQE_OUTCOME_CONCEPT_CAP` (default 2000). Each step setting accepts "off".
167
+ */
168
+ export function resolveDefaultRetention(env = process.env) {
169
+ const warnings = [];
170
+ return {
171
+ enabled: parseSwitch('AQE_DREAM_RETENTION', env.AQE_DREAM_RETENTION, warnings),
172
+ failedDreamCycleRetentionDays: parseSetting('AQE_FAILED_DREAM_CYCLE_RETENTION_DAYS', env.AQE_FAILED_DREAM_CYCLE_RETENTION_DAYS, DEFAULT_FAILED_DREAM_CYCLE_RETENTION_DAYS, 1, warnings),
173
+ outcomeConceptCap: parseSetting('AQE_OUTCOME_CONCEPT_CAP', env.AQE_OUTCOME_CONCEPT_CAP, DEFAULT_OUTCOME_CONCEPT_CAP, MIN_OUTCOME_CONCEPT_CAP, warnings),
174
+ warnings,
175
+ };
176
+ }
177
+ /**
178
+ * The dream retention steps that are not switched off individually: run
179
+ * when retention is enabled, otherwise previewed as a dry run.
180
+ */
181
+ export function runDreamRetention(db, settings = resolveDefaultRetention()) {
182
+ const dryRun = !settings.enabled;
183
+ const steps = [];
184
+ if (settings.failedDreamCycleRetentionDays !== null) {
185
+ steps.push(pruneFailedDreamCycles(db, { retentionDays: settings.failedDreamCycleRetentionDays, dryRun }));
186
+ }
187
+ if (settings.outcomeConceptCap !== null) {
188
+ steps.push(capOutcomeConcepts(db, { maxNodes: settings.outcomeConceptCap, dryRun }));
189
+ }
190
+ return { enabled: settings.enabled, steps };
191
+ }
192
+ /** Lines for a dream's output: what retention removed, or would remove while off. */
193
+ export function describeDreamRetention(report) {
194
+ if (report.error)
195
+ return [`skipped: ${report.error}`];
196
+ const lines = report.steps.filter(s => s.affected > 0).map(describeRetention);
197
+ return report.enabled ? lines : lines.map(l => `${l} [off: set AQE_DREAM_RETENTION=on]`);
198
+ }
199
+ /** One line per step, for logs: "outcome-concepts: 3000 removed (concept_nodes 5000 -> 2000, ...)". */
200
+ export function describeRetention(result) {
201
+ const verb = result.step === 'compact-experiences' ? 'compacted' : 'removed';
202
+ const counts = result.tables
203
+ .map(t => `${t.table} ${t.before} -> ${t.after}${result.dryRun ? ' projected' : ''}`)
204
+ .join(', ');
205
+ return `${result.step}: ${result.affected} ${result.dryRun ? `would be ${verb}` : verb}` +
206
+ (counts ? ` (${counts})` : '');
207
+ }
208
+ function assertWholeNumber(name, value, min) {
209
+ if (!Number.isInteger(value) || value < min) {
210
+ throw new Error(`${name} must be a whole number >= ${min}, got ${value}`);
211
+ }
212
+ }
213
+ //# sourceMappingURL=learning-retention.js.map