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.
- package/.claude/agents/v3/templates/qx-report-template.html +1 -1
- package/.claude/helpers/brain-checkpoint.cjs +124 -5
- package/.claude/skills/skills-manifest.json +1 -1
- package/CHANGELOG.md +124 -0
- package/assets/agents/v3/templates/qx-report-template.html +1 -1
- package/assets/skills/skills-manifest.json +1 -1
- package/dist/cli/bundle.js +6 -6
- package/dist/cli/chunks/adapter-QU6INSKP.js +2 -0
- package/dist/cli/chunks/agent-booster-wasm-EUF4XVUC.js +2 -0
- package/dist/cli/chunks/{agent-handler-AOH6TV7W.js → agent-handler-MOX6PSIQ.js} +2 -2
- package/dist/cli/chunks/{agent-memory-branch-2P54SF5N.js → agent-memory-branch-AEXKIGDG.js} +2 -2
- package/dist/cli/chunks/aqe-learning-engine-PAJPENJD.js +2 -0
- package/dist/cli/chunks/{arena-NSVFCAF5.js → arena-IQ5ZZDRF.js} +2 -2
- package/dist/cli/chunks/{arena-X6MOGQHA.js → arena-M7GA3CVG.js} +4 -4
- package/dist/cli/chunks/{audit-27DJLQNM.js → audit-4IPBMKWB.js} +3 -3
- package/dist/cli/chunks/base-OTGSN6IC.js +2 -0
- package/dist/cli/chunks/{better-sqlite3-BU5GXILS.js → better-sqlite3-IKDKJ2IE.js} +2 -2
- package/dist/cli/chunks/brain-handler-5NQUDH4W.js +95 -0
- package/dist/cli/chunks/{branch-enumerator-5CLULOCU.js → branch-enumerator-KSXELWRC.js} +2 -2
- package/dist/cli/chunks/{browser-R4DMU3LN.js → browser-6LACARWE.js} +2 -2
- package/dist/cli/chunks/browser-workflow-WLZGR6SB.js +2 -0
- package/dist/cli/chunks/{chunk-LUZNKJE6.js → chunk-22UKJGGN.js} +3 -3
- package/dist/cli/chunks/{chunk-BLSLEVDI.js → chunk-27HE2BHC.js} +2 -2
- package/dist/cli/chunks/{chunk-K4CZA77U.js → chunk-2CKERSMB.js} +2 -2
- package/dist/cli/chunks/{chunk-YSZ5OE3Z.js → chunk-2IIXCEMS.js} +2 -2
- package/dist/cli/chunks/{chunk-F3YS57NF.js → chunk-2LUTPMBO.js} +2 -2
- package/dist/cli/chunks/{chunk-GHM6MQNK.js → chunk-2ZFLULL4.js} +2 -2
- package/dist/cli/chunks/{chunk-7CMTY45A.js → chunk-337Z52QM.js} +2 -2
- package/dist/cli/chunks/{chunk-W26B7ERY.js → chunk-3CYNZFKH.js} +1 -1
- package/dist/cli/chunks/chunk-3HVFIITW.js +2 -0
- package/dist/cli/chunks/{chunk-K3TLLJMX.js → chunk-3J3RNJNX.js} +1 -1
- package/dist/cli/chunks/{chunk-MAMQA43L.js → chunk-4ATQP3PR.js} +1 -1
- package/dist/cli/chunks/{chunk-YXRASAPI.js → chunk-4D4CWP72.js} +2 -2
- package/dist/cli/chunks/{chunk-GHY6Z6KO.js → chunk-4HKAD25N.js} +3 -3
- package/dist/cli/chunks/{chunk-XNBOGCF3.js → chunk-4X3SWKBA.js} +2 -2
- package/dist/cli/chunks/{chunk-IJUHSJ2U.js → chunk-5AFVEWMT.js} +2 -2
- package/dist/cli/chunks/{chunk-SE4VNN4I.js → chunk-5C62XMJR.js} +3 -3
- package/dist/cli/chunks/{chunk-KDNJ4F3P.js → chunk-5G4UFTV4.js} +2 -2
- package/dist/cli/chunks/{chunk-DVGRPK7A.js → chunk-5I7357KS.js} +2 -2
- package/dist/cli/chunks/{chunk-YZWBNBTW.js → chunk-5KA5TVPR.js} +2 -2
- package/dist/cli/chunks/{chunk-JGZ722G3.js → chunk-5PTAFGJT.js} +2 -2
- package/dist/cli/chunks/{chunk-SVLQRAMF.js → chunk-6BRQPHMZ.js} +1 -1
- package/dist/cli/chunks/{chunk-KDVZND5Q.js → chunk-6KCSKGVY.js} +1 -1
- package/dist/cli/chunks/{chunk-LWR3FV3Y.js → chunk-6LE362LZ.js} +2 -2
- package/dist/cli/chunks/{chunk-WKGTGOYS.js → chunk-6NBRMD25.js} +3 -3
- package/dist/cli/chunks/{chunk-HQZGPJYG.js → chunk-6RBTS3NF.js} +2 -2
- package/dist/cli/chunks/{chunk-WOCGL4QP.js → chunk-6YVMX2TC.js} +2 -2
- package/dist/cli/chunks/{chunk-I3C7JOXC.js → chunk-73PBAWAF.js} +2 -2
- package/dist/cli/chunks/{chunk-75RDHBAX.js → chunk-74YG72NQ.js} +3 -3
- package/dist/cli/chunks/{chunk-O6FGXMHD.js → chunk-76P32JVU.js} +1 -1
- package/dist/cli/chunks/{chunk-LL7LDPXS.js → chunk-7ACCBHRB.js} +1 -1
- package/dist/cli/chunks/{chunk-3LJ7LQMV.js → chunk-7BLZHFKD.js} +1 -1
- package/dist/cli/chunks/{chunk-CM4LSLKR.js → chunk-7O45RQHF.js} +2 -2
- package/dist/cli/chunks/{chunk-NU3W5WFT.js → chunk-7XB3FCKM.js} +2 -2
- package/dist/cli/chunks/{chunk-E56B6IDX.js → chunk-AHMWD6JG.js} +2 -2
- package/dist/cli/chunks/{chunk-G2Q66Z23.js → chunk-AJPROCDW.js} +2 -2
- package/dist/cli/chunks/{chunk-NW7IBHJA.js → chunk-AKZO6GGG.js} +13 -13
- package/dist/cli/chunks/{chunk-IC3TQEOA.js → chunk-AOKKUB5F.js} +1 -1
- package/dist/cli/chunks/{chunk-4OVC4RIL.js → chunk-AP2W7Z3A.js} +1 -1
- package/dist/cli/chunks/{chunk-PHP5UBT4.js → chunk-BBRROA3Z.js} +2 -2
- package/dist/cli/chunks/{chunk-5FKWCZNF.js → chunk-BDKEAGQ2.js} +2 -2
- package/dist/cli/chunks/{chunk-BTVEYBW2.js → chunk-BFQTLF5X.js} +2 -2
- package/dist/cli/chunks/{chunk-HZ5NXFXH.js → chunk-BLL2XU7A.js} +2 -2
- package/dist/cli/chunks/{chunk-UTRV7T2N.js → chunk-BP5T3OEV.js} +2 -2
- package/dist/cli/chunks/{chunk-GB6HBNH2.js → chunk-BQ47GQPK.js} +2 -2
- package/dist/cli/chunks/{chunk-RFNW2LGD.js → chunk-BU4UQR36.js} +2 -2
- package/dist/cli/chunks/{chunk-WO274FRI.js → chunk-BZULJMGH.js} +2 -2
- package/dist/cli/chunks/{chunk-GU5HNCWI.js → chunk-C4KLXFJP.js} +1 -1
- package/dist/cli/chunks/{chunk-LFJALJOA.js → chunk-C4RTAVC6.js} +2 -2
- package/dist/cli/chunks/{chunk-WNQS4WTS.js → chunk-C5CXL3JP.js} +2 -2
- package/dist/cli/chunks/{chunk-MGZ5FJUW.js → chunk-CAOUV5GZ.js} +2 -2
- package/dist/cli/chunks/{chunk-XPRVF4YE.js → chunk-CBK5CT6T.js} +2 -2
- package/dist/cli/chunks/{chunk-JRRXCODW.js → chunk-DEKR3CTS.js} +2 -2
- package/dist/cli/chunks/{chunk-AQSVJNEH.js → chunk-DKX4GNRU.js} +2 -2
- package/dist/cli/chunks/{chunk-6KATY3KS.js → chunk-DUKE27HC.js} +2 -2
- package/dist/cli/chunks/{chunk-W2QWSQVE.js → chunk-DURD37JZ.js} +2 -2
- package/dist/cli/chunks/{chunk-KCW47QR5.js → chunk-E3MRDIZF.js} +1 -1
- package/dist/cli/chunks/{chunk-6Z7PRBSG.js → chunk-E56PVVWC.js} +2 -2
- package/dist/cli/chunks/{chunk-WQL7WCIZ.js → chunk-E5G4WZ2T.js} +1 -1
- package/dist/cli/chunks/{chunk-PB6J6HAA.js → chunk-EBTNMQSS.js} +2 -2
- package/dist/cli/chunks/{chunk-KADFXPPN.js → chunk-EFUJDMNC.js} +2 -2
- package/dist/cli/chunks/{chunk-QPNG5ZN2.js → chunk-EKP2SC77.js} +2 -2
- package/dist/cli/chunks/{chunk-U2FUXDDJ.js → chunk-EMSZVUYA.js} +3 -3
- package/dist/cli/chunks/{chunk-XEAEYC6Y.js → chunk-ERN56H6S.js} +1 -1
- package/dist/cli/chunks/{chunk-DNDL7SOS.js → chunk-FOOW4JVS.js} +2 -2
- package/dist/cli/chunks/{chunk-HOAJUIBQ.js → chunk-FTRSS64D.js} +2 -2
- package/dist/cli/chunks/{chunk-TOQWL2ZF.js → chunk-G242G224.js} +2 -2
- package/dist/cli/chunks/{chunk-VTDFVFST.js → chunk-G6RDCCFV.js} +2 -2
- package/dist/cli/chunks/{chunk-TWDW32W2.js → chunk-GCHYOPRZ.js} +2 -2
- package/dist/cli/chunks/{chunk-MFW5HSG4.js → chunk-GGQGCT4Y.js} +2 -2
- package/dist/cli/chunks/{chunk-G6WDYBLQ.js → chunk-GKSMRBHU.js} +1 -1
- package/dist/cli/chunks/{chunk-CCMKSHAT.js → chunk-GQABPCQE.js} +2 -2
- package/dist/cli/chunks/{chunk-G77ERMUD.js → chunk-GV2QE5TO.js} +1 -1
- package/dist/cli/chunks/{chunk-756CGMEH.js → chunk-H5DER3JY.js} +1 -1
- package/dist/cli/chunks/{chunk-W3PPFHI5.js → chunk-HH4ED4F7.js} +52 -50
- package/dist/cli/chunks/{chunk-3Y2ROSCL.js → chunk-HL2ANKN3.js} +2 -2
- package/dist/cli/chunks/{chunk-T3PGQFDI.js → chunk-HTZSRMHW.js} +2 -2
- package/dist/cli/chunks/{chunk-3QZEGE67.js → chunk-IXL5ZHWJ.js} +1 -1
- package/dist/cli/chunks/{chunk-5ZGM3RMH.js → chunk-J3FP5UGL.js} +1 -1
- package/dist/cli/chunks/{chunk-FZ76G4QJ.js → chunk-JCQGJGGZ.js} +1 -1
- package/dist/cli/chunks/chunk-JCZCJE6X.js +86 -0
- package/dist/cli/chunks/{chunk-YZEXYO4W.js → chunk-JKJOB65O.js} +1 -1
- package/dist/cli/chunks/{chunk-A64JFBWI.js → chunk-JUDUBQHA.js} +2 -2
- package/dist/cli/chunks/{chunk-PIDQVU3L.js → chunk-JW74KRBC.js} +2 -2
- package/dist/cli/chunks/{chunk-EXGMJFAT.js → chunk-K3WZICFA.js} +1 -1
- package/dist/cli/chunks/{chunk-ASQYASNV.js → chunk-K3XBQC3R.js} +1 -1
- package/dist/cli/chunks/{chunk-E7CLYGS7.js → chunk-KCQNFBBR.js} +1 -1
- package/dist/cli/chunks/chunk-KJBPB7P5.js +3 -0
- package/dist/cli/chunks/chunk-KLTMOXIK.js +3 -0
- package/dist/cli/chunks/{chunk-5MDERQH3.js → chunk-L32JNNKL.js} +1 -1
- package/dist/cli/chunks/{chunk-32ZMWEP3.js → chunk-LB2LGEDP.js} +2 -2
- package/dist/cli/chunks/{chunk-42J34YG4.js → chunk-LHMQIZ6B.js} +2 -2
- package/dist/cli/chunks/{chunk-NURIILUB.js → chunk-LJMYRTJ7.js} +1 -1
- package/dist/cli/chunks/{chunk-M6AAGIG7.js → chunk-LNX74WHQ.js} +1 -1
- package/dist/cli/chunks/{chunk-P7A4NKTZ.js → chunk-LTQVUAPH.js} +2 -2
- package/dist/cli/chunks/{chunk-3YNLWPBF.js → chunk-LVABQNRF.js} +2 -2
- package/dist/cli/chunks/{chunk-2G7TVT6W.js → chunk-LYJHUNBK.js} +2 -2
- package/dist/cli/chunks/{chunk-DLD7RUZ4.js → chunk-M4CJCPCQ.js} +2 -2
- package/dist/cli/chunks/{chunk-Q3UDLV5Z.js → chunk-M4WMSCAE.js} +1 -1
- package/dist/cli/chunks/{chunk-UDQSYWVF.js → chunk-MIA447GY.js} +1 -1
- package/dist/cli/chunks/{chunk-RF7HWBHN.js → chunk-MPFPWJTH.js} +2 -2
- package/dist/cli/chunks/{chunk-BK577VL7.js → chunk-MV55NXTD.js} +2 -2
- package/dist/cli/chunks/{chunk-JQGMW45H.js → chunk-NQS3BWS6.js} +1 -1
- package/dist/cli/chunks/{chunk-BEGR4D6N.js → chunk-NWIIYHT6.js} +2 -2
- package/dist/cli/chunks/{chunk-SSU73QAX.js → chunk-O6EWL5DQ.js} +2 -2
- package/dist/cli/chunks/chunk-OBDONJQM.js +2 -0
- package/dist/cli/chunks/chunk-OLZH5LRT.js +141 -0
- package/dist/cli/chunks/{chunk-W3INMZZ6.js → chunk-OQG3UQQ7.js} +1 -1
- package/dist/cli/chunks/{chunk-72ASBE35.js → chunk-PFQCV6YS.js} +3 -3
- package/dist/cli/chunks/{chunk-7YTGHGK4.js → chunk-PS6UMZVK.js} +2 -2
- package/dist/cli/chunks/{chunk-OCAEXYFA.js → chunk-PXATBHWN.js} +2 -2
- package/dist/cli/chunks/{chunk-ARJW4I2O.js → chunk-PYPS65P7.js} +2 -2
- package/dist/cli/chunks/{chunk-SYV2V3PL.js → chunk-Q6I4SIUU.js} +4 -4
- package/dist/cli/chunks/{chunk-H4H2YSFH.js → chunk-QFGYH6HD.js} +1 -1
- package/dist/cli/chunks/{chunk-526QYFJU.js → chunk-QGBGSQ2E.js} +2 -2
- package/dist/cli/chunks/{chunk-YBQH2VOP.js → chunk-QRKTBSZT.js} +2 -2
- package/dist/cli/chunks/{chunk-C7JM7CD3.js → chunk-R6LHJ7ME.js} +2 -2
- package/dist/cli/chunks/{chunk-TSQC2KKZ.js → chunk-RBKUU7WF.js} +2 -2
- package/dist/cli/chunks/{chunk-CE7B5LU7.js → chunk-RDMRY7CT.js} +1 -1
- package/dist/cli/chunks/chunk-RIRZHOS2.js +8 -0
- package/dist/cli/chunks/{chunk-CRWPZT74.js → chunk-SHRI7TKJ.js} +2 -2
- package/dist/cli/chunks/{chunk-KWYH3FI4.js → chunk-SJCKCSN3.js} +1 -1
- package/dist/cli/chunks/{chunk-DFUASIKA.js → chunk-SON6ZRH3.js} +2 -2
- package/dist/cli/chunks/{chunk-J2ZIFFM6.js → chunk-SZAZQZWI.js} +2 -2
- package/dist/cli/chunks/{chunk-HD7YIFOI.js → chunk-T4GE7MPI.js} +2 -2
- package/dist/cli/chunks/{chunk-3Y7TJFHU.js → chunk-T66PPF4D.js} +2 -2
- package/dist/cli/chunks/{chunk-3RZV5DGO.js → chunk-T67R2MUN.js} +2 -2
- package/dist/cli/chunks/{chunk-H4GG2NLO.js → chunk-TDQWTSBS.js} +2 -2
- package/dist/cli/chunks/{chunk-TWJTK4CC.js → chunk-TODNOP7C.js} +2 -2
- package/dist/cli/chunks/{chunk-NZ3GUMB2.js → chunk-TX2CHQD7.js} +2 -2
- package/dist/cli/chunks/{chunk-AL6FBH3E.js → chunk-TZIHDJZD.js} +2 -2
- package/dist/cli/chunks/{chunk-GII6UM3F.js → chunk-U62OUXBF.js} +1 -1
- package/dist/cli/chunks/{chunk-YQFLQE53.js → chunk-UAQZI6N4.js} +2 -2
- package/dist/cli/chunks/{chunk-R7SYRCRP.js → chunk-UE2J6MA5.js} +1 -1
- package/dist/cli/chunks/{chunk-VRHRBAEM.js → chunk-UGYM4U44.js} +1 -1
- package/dist/cli/chunks/{chunk-NT4DBXSX.js → chunk-UJABDXST.js} +2 -2
- package/dist/cli/chunks/{chunk-OFACHK5O.js → chunk-UORB2QDU.js} +9 -9
- package/dist/cli/chunks/{chunk-QDEJ4CI2.js → chunk-UQPA33UK.js} +2 -2
- package/dist/cli/chunks/{chunk-TCBBNUBP.js → chunk-UUBIQR6A.js} +3 -3
- package/dist/cli/chunks/{chunk-NZD4DPSU.js → chunk-UXIY4IAI.js} +2 -2
- package/dist/cli/chunks/{chunk-SG3NX7QE.js → chunk-VCXI4XC4.js} +2 -2
- package/dist/cli/chunks/{chunk-PSFSPGUD.js → chunk-VMAM46HQ.js} +2 -2
- package/dist/cli/chunks/{chunk-3AN5TNGD.js → chunk-VY4U6DPO.js} +3 -3
- package/dist/cli/chunks/{chunk-X7N2JF2X.js → chunk-W27AJ5B4.js} +2 -2
- package/dist/cli/chunks/{chunk-CT6SAVXQ.js → chunk-W5ZJG2OU.js} +2 -2
- package/dist/cli/chunks/{chunk-KV4T4MXK.js → chunk-W62OOK7A.js} +2 -2
- package/dist/cli/chunks/{chunk-5K26BEYB.js → chunk-WNTA4YKE.js} +2 -2
- package/dist/cli/chunks/{chunk-LZYQHVD4.js → chunk-WUOOX7UG.js} +2 -2
- package/dist/cli/chunks/{chunk-7NA7JXNB.js → chunk-WVXJ2QIG.js} +2 -2
- package/dist/cli/chunks/{chunk-KB56CPU4.js → chunk-X33CWRDF.js} +2 -2
- package/dist/cli/chunks/{chunk-7JUC2MVZ.js → chunk-XG4F4XH4.js} +2 -2
- package/dist/cli/chunks/{chunk-ZAKQLAHT.js → chunk-XH4JMX5O.js} +1 -1
- package/dist/cli/chunks/{chunk-X2Z7F4EU.js → chunk-XHHWABJV.js} +2 -2
- package/dist/cli/chunks/{chunk-7PLIEBY7.js → chunk-XHLYGXYE.js} +2 -2
- package/dist/cli/chunks/{chunk-UXZSUMEA.js → chunk-XIVVTYM2.js} +2 -2
- package/dist/cli/chunks/{chunk-MVVB7C2E.js → chunk-XM6ZVFM5.js} +156 -156
- package/dist/cli/chunks/{chunk-VTOBUZL6.js → chunk-XWIAZG3C.js} +2 -2
- package/dist/cli/chunks/{chunk-CV77DMDQ.js → chunk-Y2OX6KGN.js} +2 -2
- package/dist/cli/chunks/{chunk-VRVMIPTM.js → chunk-YUS6TWAL.js} +2 -2
- package/dist/cli/chunks/{chunk-VU5TBX2V.js → chunk-ZIPAB5J6.js} +2 -2
- package/dist/cli/chunks/{chunk-KUAKV3IW.js → chunk-ZSOMUTNL.js} +1 -1
- package/dist/cli/chunks/{chunk-UOC3O6RP.js → chunk-ZWBGYJ7K.js} +2 -2
- package/dist/cli/chunks/{chunk-5VMAV6T6.js → chunk-ZYJB6FML.js} +1 -1
- package/dist/cli/chunks/{ci-ENOASTYB.js → ci-UCUJOSBW.js} +2 -2
- package/dist/cli/chunks/{ci-config-B26OXHQM.js → ci-config-2XILD3XG.js} +2 -2
- package/dist/cli/chunks/{ci-output-JTCLLNOQ.js → ci-output-BL6KWOHW.js} +2 -2
- package/dist/cli/chunks/{circuit-breaker-23JMFNM5.js → circuit-breaker-5XLIOXE5.js} +2 -2
- package/dist/cli/chunks/{claude-flow-setup-ON6L462G.js → claude-flow-setup-4IMP6ACS.js} +2 -2
- package/dist/cli/chunks/client-KKRNPX4F.js +2 -0
- package/dist/cli/chunks/{cline-installer-OWQ4D2FQ.js → cline-installer-RYLHCDK7.js} +2 -2
- package/dist/cli/chunks/{code-2ZRL7SEU.js → code-WY3GJXHX.js} +3 -3
- package/dist/cli/chunks/{code-index-extractor-JXSQVM67.js → code-index-extractor-Y4MZBZCW.js} +2 -2
- package/dist/cli/chunks/{codex-installer-7LXZYBSQ.js → codex-installer-SCJ3T3DX.js} +4 -4
- package/dist/cli/chunks/{completions-C2LR623C.js → completions-CN2DXQFU.js} +2 -2
- package/dist/cli/chunks/{complexity-analyzer-TGQLHCYJ.js → complexity-analyzer-7MDPPIBH.js} +2 -2
- package/dist/cli/chunks/{continuedev-installer-RUGD24D2.js → continuedev-installer-GCEJRK34.js} +2 -2
- package/dist/cli/chunks/{copilot-installer-ZLFVLEJP.js → copilot-installer-BHPDSELY.js} +2 -2
- package/dist/cli/chunks/core-handlers-47MPMED7.js +2 -0
- package/dist/cli/chunks/{cost-tracker-RT4QL745.js → cost-tracker-VO5MFWR6.js} +2 -2
- package/dist/cli/chunks/coverage-LYFQYNH6.js +51 -0
- package/dist/cli/chunks/cross-domain-router-U6MBFHEC.js +2 -0
- package/dist/cli/chunks/{cursor-installer-LJKLNFF6.js → cursor-installer-KP4HA7TV.js} +2 -2
- package/dist/cli/chunks/{daemon-BMDXCQT5.js → daemon-7RC7TS57.js} +3 -3
- package/dist/cli/chunks/{daemon-FBH3IRYN.js → daemon-AXLVPKVO.js} +4 -4
- package/dist/cli/chunks/{dag-attention-scheduler-JGDED55I.js → dag-attention-scheduler-NKA44RSR.js} +2 -2
- package/dist/cli/chunks/{detect-SZIHIVCJ.js → detect-CMYAJWYF.js} +2 -2
- package/dist/cli/chunks/{dist-node-FV3KWXQ6.js → dist-node-EN3PYEGW.js} +2 -2
- package/dist/cli/chunks/{domain-handler-GI5JWQOV.js → domain-handler-EXSZCX7A.js} +2 -2
- package/dist/cli/chunks/{domain-plugins-BUWY36TL.js → domain-plugins-HCQFSNL7.js} +2 -2
- package/dist/cli/chunks/{domain-transfer-GCY7W5DA.js → domain-transfer-3LGSNTPO.js} +2 -2
- package/dist/cli/chunks/dream-76L6EEN7.js +2 -0
- package/dist/cli/chunks/{embed-and-insert-pattern-GPRR3ZGD.js → embed-and-insert-pattern-B6MNHICW.js} +2 -2
- package/dist/cli/chunks/{eval-XPB3IGAP.js → eval-OQELIWJK.js} +2 -2
- package/dist/cli/chunks/{experience-capture-middleware-2E554UB3.js → experience-capture-middleware-SUFILYPW.js} +3 -3
- package/dist/cli/chunks/{fast-paths-ZSMWZPUC.js → fast-paths-UV4NDEWM.js} +2 -2
- package/dist/cli/chunks/{feature-flags-GIWVDVVC.js → feature-flags-CKTYX67J.js} +2 -2
- package/dist/cli/chunks/{feature-flags-N7EOGE5P.js → feature-flags-H7H33B6C.js} +2 -2
- package/dist/cli/chunks/file-discovery-VSFKZ3LJ.js +2 -0
- package/dist/cli/chunks/{fleet-HCHDOUCX.js → fleet-ZJBCAKRG.js} +3 -3
- package/dist/cli/chunks/{gnn-wrapper-CZNCNXXZ.js → gnn-wrapper-RUE2QZRG.js} +2 -2
- package/dist/cli/chunks/{heartbeat-handler-6YUIF2YQ.js → heartbeat-handler-XRV327M7.js} +4 -4
- package/dist/cli/chunks/heartbeat-scheduler-NIK3KKEH.js +2 -0
- package/dist/cli/chunks/hnsw-adapter-WJG7LUJJ.js +2 -0
- package/dist/cli/chunks/hnsw-index-D6PRI5HC.js +2 -0
- package/dist/cli/chunks/{hnsw-legacy-bridge-J3M3IK24.js → hnsw-legacy-bridge-UJID6ZZ4.js} +2 -2
- package/dist/cli/chunks/{hnswlib-node-ULGTGDZW.js → hnswlib-node-WS43R4AX.js} +2 -2
- package/dist/cli/chunks/{hooks-C4BUGYUQ.js → hooks-YZNJKXAJ.js} +10 -10
- package/dist/cli/chunks/hybrid-backend-RIUR3I7F.js +2 -0
- package/dist/cli/chunks/{hypergraph-engine-WINGVMPG.js → hypergraph-engine-XQJSIMTS.js} +2 -2
- package/dist/cli/chunks/{hypergraph-handler-GADMWKAU.js → hypergraph-handler-ZD2NYXMR.js} +3 -3
- package/dist/cli/chunks/impact-analyzer-C36YYTJ5.js +2 -0
- package/dist/cli/chunks/{init-guard-K2T4QWAO.js → init-guard-DSRUAVRT.js} +2 -2
- package/dist/cli/chunks/{init-handler-PCZTDZYI.js → init-handler-RJU5QMAP.js} +6 -6
- package/dist/cli/chunks/init-wizard-JCKNGIGT.js +2 -0
- package/dist/cli/chunks/kernel-F7ILJTYD.js +2 -0
- package/dist/cli/chunks/{kilocode-installer-XENXNEIU.js → kilocode-installer-BCPOCVMC.js} +2 -2
- package/dist/cli/chunks/{kiro-installer-3PG2TJ67.js → kiro-installer-GFCWCB2S.js} +2 -2
- package/dist/cli/chunks/knowledge-graph-VTXDBHB2.js +2 -0
- package/dist/cli/chunks/learning-FZTD72CF.js +131 -0
- package/dist/cli/chunks/{llm-router-RKVDEWU2.js → llm-router-GJVKGRJL.js} +4 -4
- package/dist/cli/chunks/llm-router-service-TNOWQINA.js +2 -0
- package/dist/cli/chunks/{load-ITHC564X.js → load-YKTPOYBE.js} +2 -2
- package/dist/cli/chunks/load-test-FPVBK2EV.js +2 -0
- package/dist/cli/chunks/{mcp-TCL5UW3N.js → mcp-LT6R2IKS.js} +2 -2
- package/dist/cli/chunks/{memory-BKDAY2N2.js → memory-4HKKOLRY.js} +5 -5
- package/dist/cli/chunks/memory-backend-2QE7O67A.js +2 -0
- package/dist/cli/chunks/{memory-handlers-WN4FXFOA.js → memory-handlers-X4CMVBXB.js} +2 -2
- package/dist/cli/chunks/{multi-model-executor-VHAT7ZPF.js → multi-model-executor-2YPM2WTK.js} +2 -2
- package/dist/cli/chunks/{opencode-installer-E3VM3EEY.js → opencode-installer-WBAJMH5K.js} +2 -2
- package/dist/cli/chunks/{orchestrator-BMQ6X762.js → orchestrator-5W5WVMVJ.js} +109 -25
- package/dist/cli/chunks/pattern-null-store-UI35ORHW.js +2 -0
- package/dist/cli/chunks/{pattern-usage-recorder-GOOR2BV5.js → pattern-usage-recorder-GXRMNPAZ.js} +2 -2
- package/dist/cli/chunks/{pipeline-5NSFQQIX.js → pipeline-2NA4DRDA.js} +2 -2
- package/dist/cli/chunks/{platform-SQM34J5G.js → platform-BGERNQ5V.js} +2 -2
- package/dist/cli/chunks/{plugin-UQJZRMZG.js → plugin-L4EPVENR.js} +2 -2
- package/dist/cli/chunks/{prime-radiant-advanced-wasm-WMDJOL4S.js → prime-radiant-advanced-wasm-RTQRTPTM.js} +2 -2
- package/dist/cli/chunks/project-root-S7WDFTMU.js +2 -0
- package/dist/cli/chunks/protocol-executor-OPANXQVB.js +2 -0
- package/dist/cli/chunks/{protocol-handler-OBDCVY6X.js → protocol-handler-SYQXM6JK.js} +2 -2
- package/dist/cli/chunks/{prove-XDC7I4XT.js → prove-5O7GPJCU.js} +2 -2
- package/dist/cli/chunks/qe-reasoning-bank-3OTF4DYQ.js +2 -0
- package/dist/cli/chunks/{quality-L4GQ6WX4.js → quality-KIIDHGNF.js} +2 -2
- package/dist/cli/chunks/{quality-gate-MJG66LKN.js → quality-gate-H65VECD3.js} +3 -3
- package/dist/cli/chunks/queen-coordinator-WTYH4TAN.js +2 -0
- package/dist/cli/chunks/{real-embeddings-HW4G2LWL.js → real-embeddings-DYIOLKQ3.js} +2 -2
- package/dist/cli/chunks/{ref-validation-FC7JOJ2C.js → ref-validation-CSBJOMZM.js} +2 -2
- package/dist/cli/chunks/{roocode-installer-KWS4CEIC.js → roocode-installer-G7OVYXEN.js} +2 -2
- package/dist/cli/chunks/router-DBBW4NC2.js +2 -0
- package/dist/cli/chunks/routing-feedback-W35QHCL4.js +2 -0
- package/dist/cli/chunks/{routing-handler-QF4WVB2S.js → routing-handler-ZNZPPI5Y.js} +2 -2
- package/dist/cli/chunks/{ruvector-commands-2MTCOUK6.js → ruvector-commands-C6IG3OY3.js} +2 -2
- package/dist/cli/chunks/rvf-dual-writer-X3NSL25Z.js +2 -0
- package/dist/cli/chunks/rvf-migration-adapter-TZR7GDOK.js +2 -0
- package/dist/cli/chunks/{rvf-migration-coordinator-BREJCXWN.js → rvf-migration-coordinator-4ATTHGHD.js} +2 -2
- package/dist/cli/chunks/rvf-native-adapter-HD25ZYV5.js +2 -0
- package/dist/cli/chunks/{rvf-store-integrity-KKC6HOJD.js → rvf-store-integrity-3G6LFLT3.js} +2 -2
- package/dist/cli/chunks/safe-db-ZS2QKANY.js +2 -0
- package/dist/cli/chunks/schedule-ZH6VNA32.js +2 -0
- package/dist/cli/chunks/scheduler-T6CD74B6.js +2 -0
- package/dist/cli/chunks/{security-OSAE7VAP.js → security-A3IMVLFM.js} +3 -3
- package/dist/cli/chunks/{shared-rvf-adapter-COUOS665.js → shared-rvf-adapter-VHWQ6US5.js} +2 -2
- package/dist/cli/chunks/{shared-rvf-dual-writer-YXMPZKQE.js → shared-rvf-dual-writer-JB3QS7IG.js} +2 -2
- package/dist/cli/chunks/sqlite-persistence-47WU5EKZ.js +2 -0
- package/dist/cli/chunks/{standalone-memory-E6JBMOIL.js → standalone-memory-DDNXCSBD.js} +2 -2
- package/dist/cli/chunks/{status-handler-AFTCIYIX.js → status-handler-2HK7XPEK.js} +2 -2
- package/dist/cli/chunks/{structural-health-2FROCEI4.js → structural-health-DSJVLEPV.js} +2 -2
- package/dist/cli/chunks/{sync-VAYTOWDC.js → sync-3MUV6S5E.js} +2 -2
- package/dist/cli/chunks/{sync-YIQYOFGW.js → sync-NTUR53PI.js} +2 -2
- package/dist/cli/chunks/{task-handler-KVQHDEX3.js → task-handler-74MZN2EO.js} +2 -2
- package/dist/cli/chunks/{task-handlers-MVVECQA6.js → task-handlers-VJR6EHRZ.js} +3 -3
- package/dist/cli/chunks/{test-5JSVTOMY.js → test-O6FK3FVF.js} +4 -4
- package/dist/cli/chunks/test-runner-process-2NPW3UDQ.js +2 -0
- package/dist/cli/chunks/{test-scheduling-HBOHVLI3.js → test-scheduling-Q6QEEOS6.js} +3 -3
- package/dist/cli/chunks/{token-bootstrap-5VEPTPFA.js → token-bootstrap-TTRCECLP.js} +2 -2
- package/dist/cli/chunks/{token-usage-TBJHDLY6.js → token-usage-YEEFWSSI.js} +2 -2
- package/dist/cli/chunks/{transformers-VAWYMHMZ.js → transformers-BZCHJJJT.js} +2 -2
- package/dist/cli/chunks/tree-sitter-wasm-parser-RZAND65G.js +2 -0
- package/dist/cli/chunks/{types-R5SDZU2E.js → types-4AOKZYOX.js} +2 -2
- package/dist/cli/chunks/unified-memory-FZ5K2C7W.js +2 -0
- package/dist/cli/chunks/unified-memory-hnsw-VREWX56M.js +2 -0
- package/dist/cli/chunks/unified-persistence-YZGMKX6B.js +2 -0
- package/dist/cli/chunks/{upgrade-K5PIHXRB.js → upgrade-2MWW6BT2.js} +2 -2
- package/dist/cli/chunks/{validate-RPTS7RYJ.js → validate-PAEV3GT5.js} +2 -2
- package/dist/cli/chunks/{validate-swarm-B2ZL556X.js → validate-swarm-ZIXACK5K.js} +2 -2
- package/dist/cli/chunks/visual-security-GXGSFBVA.js +2 -0
- package/dist/cli/chunks/{web-tree-sitter-K4DUJC32.js → web-tree-sitter-VLTXZFAB.js} +2 -2
- package/dist/cli/chunks/{windsurf-installer-OK2AJN35.js → windsurf-installer-VELMLOZF.js} +2 -2
- package/dist/cli/chunks/witness-chain-MRJKVCOW.js +2 -0
- package/dist/cli/chunks/witness-chain-WWHJKITG.js +2 -0
- package/dist/cli/chunks/{witness-chain-repair-L6Y5RFXR.js → witness-chain-repair-5SAXPETG.js} +2 -2
- package/dist/cli/chunks/{witness-chain-verifier-N4CW7FZX.js → witness-chain-verifier-MIDWD4JS.js} +2 -2
- package/dist/cli/chunks/{witness-key-manager-TDNPS3WD.js → witness-key-manager-OSVCWOB2.js} +2 -2
- package/dist/cli/chunks/{workflow-XRZA3YCY.js → workflow-MK7A7QCX.js} +4 -4
- package/dist/cli/chunks/workflow-orchestrator-SG7DV72E.js +2 -0
- package/dist/cli/chunks/{wrappers-5JIFWKN6.js → wrappers-5QFMCKXL.js} +2 -2
- package/dist/cli/commands/coverage.js +6 -0
- package/dist/cli/commands/learning-prune.d.ts +14 -0
- package/dist/cli/commands/learning-prune.js +105 -0
- package/dist/cli/commands/learning.js +9 -0
- package/dist/cli/handlers/brain-handler.js +12 -1
- package/dist/cli/utils/coverage-verdict.js +14 -3
- package/dist/context/compaction/index.d.ts +7 -0
- package/dist/context/compaction/index.js +30 -6
- package/dist/coordination/handlers/coverage-evidence.d.ts +19 -0
- package/dist/coordination/handlers/coverage-evidence.js +31 -2
- package/dist/coordination/handlers/coverage-handlers.js +5 -1
- package/dist/coordination/handlers/coverage-target.js +8 -1
- package/dist/coordination/handlers/quality-handlers.js +9 -1
- package/dist/coordination/result-saver-adapters.js +1 -0
- package/dist/coordination/result-saver.js +9 -5
- package/dist/domains/chaos-resilience/services/chaos-engineer.d.ts +1 -0
- package/dist/domains/chaos-resilience/services/chaos-engineer.js +23 -45
- package/dist/domains/coverage-analysis/collected-metrics.d.ts +22 -6
- package/dist/domains/coverage-analysis/collected-metrics.js +37 -12
- package/dist/domains/coverage-analysis/services/coverage-analyzer.js +2 -0
- package/dist/domains/defect-intelligence/services/defect-predictor.js +3 -6
- package/dist/domains/quality-assessment/coverage-report-event.d.ts +8 -0
- package/dist/domains/quality-assessment/coverage-report-event.js +22 -1
- package/dist/domains/quality-assessment/interfaces.d.ts +6 -0
- package/dist/domains/quality-assessment/services/quality-analyzer.d.ts +4 -0
- package/dist/domains/quality-assessment/services/quality-analyzer.js +63 -17
- package/dist/domains/test-execution/interfaces.d.ts +5 -0
- package/dist/domains/test-execution/services/test-executor.js +6 -0
- package/dist/init/init-wizard-hooks.d.ts +1 -1
- package/dist/init/init-wizard-hooks.js +7 -8
- package/dist/init/phases/07-hooks.js +90 -6
- package/dist/init/phases/08-mcp.js +9 -0
- package/dist/init/settings-merge.d.ts +13 -0
- package/dist/init/settings-merge.js +49 -2
- package/dist/integrations/agent-booster-wasm/agent_booster_wasm.js +849 -0
- package/dist/integrations/agent-booster-wasm/agent_booster_wasm_bg.wasm +0 -0
- package/dist/integrations/agent-booster-wasm/index.d.ts +8 -0
- package/dist/integrations/agent-booster-wasm/index.js +25 -2
- package/dist/integrations/agent-booster-wasm/package.json +16 -0
- package/dist/integrations/ruvector/brain-rvf-exporter.d.ts +25 -0
- package/dist/integrations/ruvector/brain-rvf-exporter.js +154 -61
- package/dist/learning/dream/dream-engine.d.ts +27 -3
- package/dist/learning/dream/dream-engine.js +97 -28
- package/dist/learning/dream/dream-lock-retry.d.ts +38 -0
- package/dist/learning/dream/dream-lock-retry.js +66 -0
- package/dist/learning/dream/speculative-dreamer.js +1 -1
- package/dist/learning/learning-retention.d.ts +103 -0
- package/dist/learning/learning-retention.js +213 -0
- package/dist/mcp/bundle.js +501 -496
- package/dist/mcp/handlers/domain-handler-configs.d.ts +9 -1
- package/dist/mcp/handlers/domain-handler-configs.js +24 -14
- package/dist/mcp/protocol-server.js +1 -1
- package/dist/mcp/tools/chaos-resilience/inject.d.ts +3 -4
- package/dist/mcp/tools/chaos-resilience/inject.js +11 -81
- package/dist/mcp/tools/learning-optimization/dream.d.ts +8 -0
- package/dist/mcp/tools/learning-optimization/dream.js +4 -0
- package/package.json +4 -2
- package/dist/cli/chunks/adapter-KCQDVYY2.js +0 -2
- package/dist/cli/chunks/agent-booster-wasm-6RRQWMNE.js +0 -2
- package/dist/cli/chunks/aqe-learning-engine-SAQOHSGN.js +0 -2
- package/dist/cli/chunks/base-WCACU3FN.js +0 -2
- package/dist/cli/chunks/brain-handler-GTQNHHZS.js +0 -94
- package/dist/cli/chunks/browser-workflow-G6IASEAP.js +0 -2
- package/dist/cli/chunks/chunk-C6JTLKG7.js +0 -141
- package/dist/cli/chunks/chunk-K65CGKLD.js +0 -8
- package/dist/cli/chunks/chunk-MB46UBGY.js +0 -3
- package/dist/cli/chunks/chunk-N4CYAKOX.js +0 -79
- package/dist/cli/chunks/chunk-PT4FMJPQ.js +0 -3
- package/dist/cli/chunks/chunk-S5AZCIZS.js +0 -2
- package/dist/cli/chunks/chunk-UT2VZ33P.js +0 -2
- package/dist/cli/chunks/client-TV3V2YZ5.js +0 -2
- package/dist/cli/chunks/core-handlers-PZT4OLWR.js +0 -2
- package/dist/cli/chunks/coverage-NV3C4IMM.js +0 -50
- package/dist/cli/chunks/cross-domain-router-QOFCZ7G4.js +0 -2
- package/dist/cli/chunks/dream-TRFBGDSQ.js +0 -2
- package/dist/cli/chunks/file-discovery-WCKGMSPZ.js +0 -2
- package/dist/cli/chunks/heartbeat-scheduler-P44A2OX3.js +0 -2
- package/dist/cli/chunks/hnsw-adapter-ZJQIQJKC.js +0 -2
- package/dist/cli/chunks/hnsw-index-HMG2GH3Z.js +0 -2
- package/dist/cli/chunks/hybrid-backend-B7M74PZG.js +0 -2
- package/dist/cli/chunks/impact-analyzer-PZYOVKQO.js +0 -2
- package/dist/cli/chunks/init-wizard-TZDJQK3U.js +0 -2
- package/dist/cli/chunks/kernel-Y6RRIOKW.js +0 -2
- package/dist/cli/chunks/knowledge-graph-BVD5Z66M.js +0 -2
- package/dist/cli/chunks/learning-6KDH7FK4.js +0 -122
- package/dist/cli/chunks/llm-router-service-KHCAMSUU.js +0 -2
- package/dist/cli/chunks/load-test-RUF7DZA5.js +0 -2
- package/dist/cli/chunks/memory-backend-7ZLFOVGG.js +0 -2
- package/dist/cli/chunks/pattern-null-store-RY6CVYHP.js +0 -2
- package/dist/cli/chunks/project-root-IO5KRNGL.js +0 -2
- package/dist/cli/chunks/protocol-executor-U2CUDWDE.js +0 -2
- package/dist/cli/chunks/qe-reasoning-bank-DQSSX2IP.js +0 -2
- package/dist/cli/chunks/queen-coordinator-6FN4BZIX.js +0 -2
- package/dist/cli/chunks/router-YUO3I7RU.js +0 -2
- package/dist/cli/chunks/routing-feedback-36SLQGJE.js +0 -2
- package/dist/cli/chunks/rvf-dual-writer-FRYZH3WZ.js +0 -2
- package/dist/cli/chunks/rvf-migration-adapter-XXNITL5I.js +0 -2
- package/dist/cli/chunks/rvf-native-adapter-D2WWKJIV.js +0 -2
- package/dist/cli/chunks/safe-db-4RRIGRXD.js +0 -2
- package/dist/cli/chunks/schedule-25RTO4DQ.js +0 -2
- package/dist/cli/chunks/scheduler-BPIOJZ5P.js +0 -2
- package/dist/cli/chunks/sqlite-persistence-EDF47DDX.js +0 -2
- package/dist/cli/chunks/test-runner-process-LEPF2OSS.js +0 -2
- package/dist/cli/chunks/tree-sitter-wasm-parser-TSZTCMFV.js +0 -2
- package/dist/cli/chunks/unified-memory-TLGSSLMI.js +0 -2
- package/dist/cli/chunks/unified-memory-hnsw-MSUR7ZOO.js +0 -2
- package/dist/cli/chunks/unified-persistence-VFFOTWK7.js +0 -2
- package/dist/cli/chunks/visual-security-6Q44XNLB.js +0 -2
- package/dist/cli/chunks/witness-chain-KDOMXDQX.js +0 -2
- package/dist/cli/chunks/witness-chain-N3OY2RMH.js +0 -2
- 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
|
-
//
|
|
272
|
-
//
|
|
273
|
-
//
|
|
274
|
-
//
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
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
|
-
|
|
291
|
-
|
|
292
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
533
|
-
|
|
554
|
+
result.commitDurationMs = commit.durationMs;
|
|
555
|
+
result.retention = commit.retention;
|
|
556
|
+
return commit.durationMs;
|
|
534
557
|
}
|
|
535
|
-
/**
|
|
536
|
-
|
|
537
|
-
|
|
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
|
-
|
|
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
|