agentic-qe 3.12.2 → 3.12.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/skills-manifest.json +1 -1
- package/CHANGELOG.md +39 -0
- package/assets/skills/skills-manifest.json +1 -1
- package/dist/cli/bundle.js +5 -5
- package/dist/cli/chunks/adapter-D657MKZY.js +2 -0
- package/dist/cli/chunks/{agent-booster-wasm-3KYNICBC.js → agent-booster-wasm-XFAQATTH.js} +2 -2
- package/dist/cli/chunks/{agent-handler-NGPTMI6E.js → agent-handler-2ZV4CA3U.js} +2 -2
- package/dist/cli/chunks/{agent-memory-branch-GNTQKQMG.js → agent-memory-branch-6WGP7F5T.js} +2 -2
- package/dist/cli/chunks/aqe-learning-engine-AFR6OZJK.js +2 -0
- package/dist/cli/chunks/{arena-HQEP2NWI.js → arena-FWX7XZAE.js} +4 -4
- package/dist/cli/chunks/{arena-PA7VIYD4.js → arena-KJUNQK4N.js} +2 -2
- package/dist/cli/chunks/{audit-XSDM57GC.js → audit-YFUDEOKN.js} +3 -3
- package/dist/cli/chunks/base-K5QRGZWE.js +2 -0
- package/dist/cli/chunks/{hnswlib-node-BCASOCNU.js → better-sqlite3-FE55OGYB.js} +2 -2
- package/dist/cli/chunks/brain-handler-ZCK4WTPK.js +89 -0
- package/dist/cli/chunks/{branch-enumerator-ZW7RNMUF.js → branch-enumerator-HTVINRYG.js} +2 -2
- package/dist/cli/chunks/{browser-4LU22CPP.js → browser-WUL2B77M.js} +2 -2
- package/dist/cli/chunks/browser-workflow-ZMMKCGYW.js +2 -0
- package/dist/cli/chunks/{chunk-TRHUH24V.js → chunk-2CPJCXV6.js} +2 -2
- package/dist/cli/chunks/{chunk-TLYZPOA7.js → chunk-2HCMRGMO.js} +2 -2
- package/dist/cli/chunks/{chunk-X47GHZY3.js → chunk-2LNDU7AW.js} +2 -2
- package/dist/cli/chunks/{chunk-OIUIVV2N.js → chunk-2OX74DOO.js} +1 -1
- package/dist/cli/chunks/{chunk-AJ6DZXKK.js → chunk-2YDZXFO2.js} +2 -2
- package/dist/cli/chunks/{chunk-Z63IOTDW.js → chunk-32L7DKNQ.js} +2 -2
- package/dist/cli/chunks/{chunk-7DV42KFP.js → chunk-3YC4YUGB.js} +2 -2
- package/dist/cli/chunks/{chunk-R5HC6JVJ.js → chunk-4EHW4TNA.js} +2 -2
- package/dist/cli/chunks/{chunk-NDAJWCXN.js → chunk-4HP7N6SP.js} +2 -2
- package/dist/cli/chunks/{chunk-BMRR3MBR.js → chunk-5FAWIIWF.js} +2 -2
- package/dist/cli/chunks/{chunk-5CGTBAVF.js → chunk-67BCEHU5.js} +1 -1
- package/dist/cli/chunks/{chunk-BDX54WJV.js → chunk-6E47R27C.js} +1 -1
- package/dist/cli/chunks/{chunk-J6EFAKDQ.js → chunk-6HQDPDN5.js} +2 -2
- package/dist/cli/chunks/{chunk-ABHKXMOJ.js → chunk-6SQ72FG7.js} +1 -1
- package/dist/cli/chunks/{chunk-WMNGPIP3.js → chunk-6SUSRXXF.js} +1 -1
- package/dist/cli/chunks/{chunk-6X65BGGK.js → chunk-72QQDR3Y.js} +2 -2
- package/dist/cli/chunks/{chunk-YYV3FYVB.js → chunk-7Q74K3HZ.js} +1 -1
- package/dist/cli/chunks/{chunk-Z3FA5KR6.js → chunk-7WF3TW3G.js} +4 -4
- package/dist/cli/chunks/{chunk-WL5VMIO4.js → chunk-7XUM4LBC.js} +1 -1
- package/dist/cli/chunks/{chunk-EZ3JVN6S.js → chunk-ADQFQBFJ.js} +2 -2
- package/dist/cli/chunks/{chunk-LIAW5FD7.js → chunk-AIWRYWK2.js} +2 -2
- package/dist/cli/chunks/{chunk-KBAXD6PH.js → chunk-AZ24ONMX.js} +1 -1
- package/dist/cli/chunks/{chunk-ZHWXI4SK.js → chunk-BDGKB2PT.js} +2 -2
- package/dist/cli/chunks/{chunk-4FHJYJCH.js → chunk-BEPP57C2.js} +2 -2
- package/dist/cli/chunks/{chunk-WY5CX3VH.js → chunk-BQ2K4BPD.js} +2 -2
- package/dist/cli/chunks/{chunk-T6TQPF5P.js → chunk-BSNNTOHY.js} +3 -3
- package/dist/cli/chunks/chunk-CHFTHSMM.js +9 -0
- package/dist/cli/chunks/{chunk-HNU32LN3.js → chunk-CL6SNCFF.js} +1 -1
- package/dist/cli/chunks/{chunk-K43YXI7C.js → chunk-CXMOIE7D.js} +1 -1
- package/dist/cli/chunks/{chunk-QYST2TZW.js → chunk-CYSBM52D.js} +2 -2
- package/dist/cli/chunks/{chunk-UFPCNUJA.js → chunk-D4GMAUTP.js} +10 -10
- package/dist/cli/chunks/{chunk-WE5QHYL7.js → chunk-DCYBV6HV.js} +1 -1
- package/dist/cli/chunks/chunk-DDYP6FBC.js +2 -0
- package/dist/cli/chunks/{chunk-GP7IXYOY.js → chunk-DHUZHT5D.js} +1 -1
- package/dist/cli/chunks/{chunk-7KMYBRKJ.js → chunk-DMD6WVJ2.js} +2 -2
- package/dist/cli/chunks/{chunk-RXEQB4OT.js → chunk-DTZFZ5M7.js} +2 -2
- package/dist/cli/chunks/{chunk-M4XVEUUM.js → chunk-DW7OI5IF.js} +2 -2
- package/dist/cli/chunks/{chunk-ADZTWGEB.js → chunk-DZ775UGW.js} +2 -2
- package/dist/cli/chunks/{chunk-KDGLNJPB.js → chunk-E2U3LTGM.js} +1 -1
- package/dist/cli/chunks/{chunk-7OD6HFCP.js → chunk-E53UR2EW.js} +3 -3
- package/dist/cli/chunks/{chunk-R554WVIG.js → chunk-EH7TSJPS.js} +2 -2
- package/dist/cli/chunks/{chunk-FKUH33L3.js → chunk-EHO52NKU.js} +2 -2
- package/dist/cli/chunks/{chunk-ZBYMF2QJ.js → chunk-EOUJ6X5H.js} +1 -1
- package/dist/cli/chunks/{chunk-CDMAVNV5.js → chunk-FHHCH7WL.js} +1 -1
- package/dist/cli/chunks/{chunk-AL5QT6OX.js → chunk-FJACKKRL.js} +2 -2
- package/dist/cli/chunks/{chunk-MF4FULAI.js → chunk-FTM562PF.js} +1 -1
- package/dist/cli/chunks/{chunk-MNHGBG4D.js → chunk-FXOOOJQD.js} +1 -1
- package/dist/cli/chunks/chunk-G5OGKVLO.js +2 -0
- package/dist/cli/chunks/{chunk-WYFEVPLO.js → chunk-GGTCD4MA.js} +1 -1
- package/dist/cli/chunks/{chunk-LWVUNBZO.js → chunk-GMFFMJD6.js} +2 -2
- package/dist/cli/chunks/{chunk-V2QYW5KW.js → chunk-GS6G7AVS.js} +2 -2
- package/dist/cli/chunks/{chunk-IKIKIHFQ.js → chunk-GV2BS5NC.js} +2 -2
- package/dist/cli/chunks/{chunk-FUBN5GPY.js → chunk-HGJQSTQD.js} +1 -1
- package/dist/cli/chunks/{chunk-6SWR2BN7.js → chunk-HJ2LG5IH.js} +1 -1
- package/dist/cli/chunks/{chunk-C7VNQ4PY.js → chunk-HJ4U64BL.js} +2 -2
- package/dist/cli/chunks/{chunk-VM6VBRRU.js → chunk-ILRKO6A5.js} +3 -3
- package/dist/cli/chunks/{chunk-RXH2TC2K.js → chunk-IWQHQLT6.js} +2 -2
- package/dist/cli/chunks/{chunk-N57BKUVE.js → chunk-J2RJOJ5Q.js} +1 -1
- package/dist/cli/chunks/{chunk-KNOO6TFO.js → chunk-KA4EAMMQ.js} +3 -3
- package/dist/cli/chunks/{chunk-BOR5MME3.js → chunk-KE3RK35K.js} +1 -1
- package/dist/cli/chunks/{chunk-AMPYON7M.js → chunk-KGHSKDC7.js} +2 -2
- package/dist/cli/chunks/{chunk-2R7J4ZGT.js → chunk-KKOFH26C.js} +1 -1
- package/dist/cli/chunks/{chunk-OMIGKGJJ.js → chunk-KNWBRMLL.js} +2 -2
- package/dist/cli/chunks/{chunk-KV5OZ6T3.js → chunk-KRS4KGX5.js} +2 -2
- package/dist/cli/chunks/{chunk-PXKVW6PT.js → chunk-KVHCWH4H.js} +2 -2
- package/dist/cli/chunks/{chunk-ZF65VOQH.js → chunk-KXKACV3E.js} +2 -2
- package/dist/cli/chunks/{chunk-P65S7AZA.js → chunk-L2X3BWMN.js} +2 -2
- package/dist/cli/chunks/{chunk-ERQL3D2O.js → chunk-L6GZGEFQ.js} +2 -2
- package/dist/cli/chunks/{chunk-E5XWCGSX.js → chunk-LCM7TY76.js} +2 -2
- package/dist/cli/chunks/{chunk-HH5Y4NCR.js → chunk-LGYEOYQJ.js} +2 -2
- package/dist/cli/chunks/{chunk-6FBXYS6X.js → chunk-LHAUFY4Y.js} +2 -2
- package/dist/cli/chunks/{chunk-5YLY2WT2.js → chunk-LNIHLNW4.js} +3 -3
- package/dist/cli/chunks/{chunk-BUKGW63B.js → chunk-M32DTUZM.js} +2 -2
- package/dist/cli/chunks/{chunk-OSAPKOGN.js → chunk-M7W6VJ65.js} +1 -1
- package/dist/cli/chunks/{chunk-KBXW7S3W.js → chunk-MB7TZQW3.js} +3 -3
- package/dist/cli/chunks/{chunk-YRO7HNS4.js → chunk-MOX25RZQ.js} +2 -2
- package/dist/cli/chunks/{chunk-F3CKOVZM.js → chunk-MOXKKY5Q.js} +6 -6
- package/dist/cli/chunks/{chunk-XNNYHQLW.js → chunk-MS6VOSPY.js} +5 -5
- package/dist/cli/chunks/{chunk-6N62KS3C.js → chunk-MSDIIRLM.js} +2 -2
- package/dist/cli/chunks/{chunk-2R7XZ2WP.js → chunk-MZ7SIO6R.js} +2 -2
- package/dist/cli/chunks/{chunk-CMKCPRWX.js → chunk-N4ML23ZG.js} +1 -1
- package/dist/cli/chunks/{chunk-SYLTJKN2.js → chunk-NAMJGRGC.js} +1 -1
- package/dist/cli/chunks/{chunk-ACDZ2CRV.js → chunk-NJDLJ3KD.js} +2 -2
- package/dist/cli/chunks/{chunk-EGU54SNK.js → chunk-NKTLKMUB.js} +1 -1
- package/dist/cli/chunks/{chunk-YZ44FUVJ.js → chunk-NLDLUHOF.js} +2 -2
- package/dist/cli/chunks/{chunk-APVXTHTA.js → chunk-NOSQI2OW.js} +2 -2
- package/dist/cli/chunks/{chunk-MNNNA57O.js → chunk-NT66CT73.js} +2 -2
- package/dist/cli/chunks/{chunk-CQKEVUMO.js → chunk-NX522PRH.js} +2 -2
- package/dist/cli/chunks/{chunk-CKFZOPZN.js → chunk-OBL6W4Z5.js} +2 -2
- package/dist/cli/chunks/chunk-OPG2HV2W.js +2 -0
- package/dist/cli/chunks/{chunk-GCQATSMK.js → chunk-PDX7IYTJ.js} +2 -2
- package/dist/cli/chunks/{chunk-YDZIPP3Y.js → chunk-PEHEANAM.js} +2 -2
- package/dist/cli/chunks/{chunk-MALFTRCT.js → chunk-PPUDKQ4X.js} +2 -2
- package/dist/cli/chunks/{chunk-TMQ3S7HR.js → chunk-PSDH7CIL.js} +1 -1
- package/dist/cli/chunks/{chunk-R6LDR3IO.js → chunk-PTPN6HQ7.js} +2 -2
- package/dist/cli/chunks/{chunk-BDVOXGY5.js → chunk-PXCJDB7J.js} +1 -1
- package/dist/cli/chunks/{chunk-VOHYQ6MX.js → chunk-QILF6BZH.js} +2 -2
- package/dist/cli/chunks/{chunk-UEIIIDBJ.js → chunk-R6WMGSEK.js} +2 -2
- package/dist/cli/chunks/{chunk-DGOZ3CGB.js → chunk-RE42RJYR.js} +2 -2
- package/dist/cli/chunks/{chunk-TERRRQVY.js → chunk-RLBNAB6Y.js} +1 -1
- package/dist/cli/chunks/{chunk-BPSEFLJ6.js → chunk-ROFCS47F.js} +1 -1
- package/dist/cli/chunks/{chunk-3LELACAQ.js → chunk-RSZOCQOL.js} +2 -2
- package/dist/cli/chunks/{chunk-YSCEUK55.js → chunk-S47YGWXK.js} +2 -2
- package/dist/cli/chunks/{chunk-RFQIC6ZF.js → chunk-SFS3UHNF.js} +1 -1
- package/dist/cli/chunks/{chunk-HU6ETNA7.js → chunk-SGMJ277D.js} +1 -1
- package/dist/cli/chunks/{chunk-2L7K2J2T.js → chunk-SPI4LUJ6.js} +2 -2
- package/dist/cli/chunks/{chunk-LOZAUP6L.js → chunk-SV7J5FDW.js} +2 -2
- package/dist/cli/chunks/{chunk-GUGUYFU5.js → chunk-TP3UAWMB.js} +2 -2
- package/dist/cli/chunks/{chunk-ILNQPPKB.js → chunk-TXLPOXAN.js} +1 -1
- package/dist/cli/chunks/{chunk-UF3YOGHV.js → chunk-UAPUA6OY.js} +2 -2
- package/dist/cli/chunks/{chunk-GECWGFRR.js → chunk-UGW23T6S.js} +2 -2
- package/dist/cli/chunks/{chunk-B7DI76SY.js → chunk-UGXHMQ6P.js} +2 -2
- package/dist/cli/chunks/{chunk-VHYACXLN.js → chunk-UIHZ34SJ.js} +2 -2
- package/dist/cli/chunks/{chunk-WRMUQVKY.js → chunk-ULQCEM7K.js} +2 -2
- package/dist/cli/chunks/{chunk-ZL7ZOIHO.js → chunk-UZ7FXVH5.js} +1 -1
- package/dist/cli/chunks/{chunk-3AJUJAUJ.js → chunk-VFYMWDSJ.js} +1 -1
- package/dist/cli/chunks/{chunk-TQNNKW7K.js → chunk-VSD6JE2H.js} +2 -2
- package/dist/cli/chunks/{chunk-327YEKBU.js → chunk-VUCVSKJC.js} +2 -2
- package/dist/cli/chunks/{chunk-LGEPR7MH.js → chunk-WBZNLFTV.js} +3 -3
- package/dist/cli/chunks/{chunk-OELLHV7S.js → chunk-WFPGIP4N.js} +2 -2
- package/dist/cli/chunks/{chunk-WC5PM33J.js → chunk-WKE6WL5C.js} +3 -3
- package/dist/cli/chunks/{chunk-P2FYRAC5.js → chunk-WQASUQ5P.js} +1 -1
- package/dist/cli/chunks/{chunk-OEZNUXY7.js → chunk-WUE53ZPH.js} +1 -1
- package/dist/cli/chunks/{chunk-KJJP446A.js → chunk-XBOCRCC6.js} +1 -1
- package/dist/cli/chunks/{chunk-TFVWUR2U.js → chunk-XDHGCBTS.js} +2 -2
- package/dist/cli/chunks/{chunk-WKWIUS5G.js → chunk-XQ5JT7KM.js} +2 -2
- package/dist/cli/chunks/{chunk-CTFW7CMI.js → chunk-XUUVAAHV.js} +2 -2
- package/dist/cli/chunks/{chunk-IQ56KMMH.js → chunk-XZGOXLZH.js} +1 -1
- package/dist/cli/chunks/{chunk-EKTWIEEO.js → chunk-Y5L37K7X.js} +2 -2
- package/dist/cli/chunks/{chunk-VQU2JXTK.js → chunk-Y625LP6K.js} +2 -2
- package/dist/cli/chunks/{chunk-56MXYSYY.js → chunk-Y6XNISHP.js} +2 -2
- package/dist/cli/chunks/{chunk-FTG4ZVTX.js → chunk-YDYKFSD2.js} +10 -10
- package/dist/cli/chunks/{chunk-W7LBT3BF.js → chunk-YEC55GO5.js} +2 -2
- package/dist/cli/chunks/{chunk-DTXHRALB.js → chunk-YOG5KQZF.js} +2 -2
- package/dist/cli/chunks/{chunk-4KEOBDEI.js → chunk-YUDGQZJN.js} +2 -2
- package/dist/cli/chunks/{chunk-PHIEJAQK.js → chunk-Z3SXMYVI.js} +3 -3
- package/dist/cli/chunks/{chunk-PSA2SOON.js → chunk-ZFLE4D4X.js} +2 -2
- package/dist/cli/chunks/{chunk-5SM57X4D.js → chunk-ZGKQCUPB.js} +2 -2
- package/dist/cli/chunks/{chunk-SVUWAV6Y.js → chunk-ZTKCGEB6.js} +1 -1
- package/dist/cli/chunks/{ci-NT4DUGQ4.js → ci-MMLUV6L6.js} +2 -2
- package/dist/cli/chunks/{ci-output-PXBD2QPH.js → ci-output-25GS6RXR.js} +2 -2
- package/dist/cli/chunks/{circuit-breaker-ZPCCEEDX.js → circuit-breaker-4OWAN6R6.js} +2 -2
- package/dist/cli/chunks/{claude-flow-setup-CZCDFZOE.js → claude-flow-setup-LR3SRBX6.js} +2 -2
- package/dist/cli/chunks/client-WI7RRUZO.js +2 -0
- package/dist/cli/chunks/{cline-installer-6J2S7GLM.js → cline-installer-YSZWRZUI.js} +2 -2
- package/dist/cli/chunks/{code-UTERK5AP.js → code-UUWUIXI7.js} +2 -2
- package/dist/cli/chunks/{code-index-extractor-O3MJTOS2.js → code-index-extractor-2LSPQORU.js} +2 -2
- package/dist/cli/chunks/{codex-installer-AZJIVXJR.js → codex-installer-E5BVXZVA.js} +2 -2
- package/dist/cli/chunks/{completions-A6ANQSZN.js → completions-YKXBKZSO.js} +2 -2
- package/dist/cli/chunks/{complexity-analyzer-MRSN7VUP.js → complexity-analyzer-HNT2QRWB.js} +2 -2
- package/dist/cli/chunks/{continuedev-installer-6LMKQRUI.js → continuedev-installer-AW5VCB66.js} +2 -2
- package/dist/cli/chunks/{copilot-installer-KP3TWUNO.js → copilot-installer-B6SVZXQT.js} +2 -2
- package/dist/cli/chunks/core-handlers-T6URR57V.js +2 -0
- package/dist/cli/chunks/{cost-tracker-R3C5IQPZ.js → cost-tracker-POZMBN2V.js} +2 -2
- package/dist/cli/chunks/{coverage-MR4QA2NM.js → coverage-V5BGPN5Q.js} +3 -3
- package/dist/cli/chunks/cross-domain-router-WHTTKHWM.js +2 -0
- package/dist/cli/chunks/{cursor-installer-LPZ7NGOS.js → cursor-installer-EYBI4QVK.js} +2 -2
- package/dist/cli/chunks/{daemon-X5KXHRY3.js → daemon-CF6ENQB2.js} +3 -3
- package/dist/cli/chunks/{daemon-K3KW2UDV.js → daemon-HKARXY2W.js} +4 -4
- package/dist/cli/chunks/{dag-attention-scheduler-J4FJSGNN.js → dag-attention-scheduler-XIL5IAP7.js} +2 -2
- package/dist/cli/chunks/{detect-22TX2NCA.js → detect-RRX2U2KK.js} +2 -2
- package/dist/cli/chunks/{dist-node-QI4I4QPS.js → dist-node-DOANNRCS.js} +2 -2
- package/dist/cli/chunks/{domain-handler-ZYZGPNOQ.js → domain-handler-QMTJV5OR.js} +2 -2
- package/dist/cli/chunks/{domain-transfer-2EEQTNIU.js → domain-transfer-FSNH75XW.js} +2 -2
- package/dist/cli/chunks/dream-QUL6SURC.js +2 -0
- package/dist/cli/chunks/{embed-and-insert-pattern-LYCTU5BS.js → embed-and-insert-pattern-NI7PGONV.js} +2 -2
- package/dist/cli/chunks/{eval-SOA72GUX.js → eval-6ZAF2RY3.js} +2 -2
- package/dist/cli/chunks/{experience-capture-middleware-AFFYOMYM.js → experience-capture-middleware-JMXR7N5G.js} +3 -3
- package/dist/cli/chunks/{fast-paths-WNMHOSUH.js → fast-paths-YB7XZZ76.js} +2 -2
- package/dist/cli/chunks/{feature-flags-FT4YBZH4.js → feature-flags-2RC4GFC4.js} +2 -2
- package/dist/cli/chunks/{feature-flags-HAP5IAAY.js → feature-flags-KJSP7KR6.js} +2 -2
- package/dist/cli/chunks/{file-discovery-B4FFOH3Z.js → file-discovery-SUPBXFYI.js} +2 -2
- package/dist/cli/chunks/{fleet-2ICPYV3J.js → fleet-KSXFOLFW.js} +3 -3
- package/dist/cli/chunks/{gnn-wrapper-XIBJAHMW.js → gnn-wrapper-DFZ5KPPK.js} +2 -2
- package/dist/cli/chunks/{heartbeat-handler-NSLSKDOI.js → heartbeat-handler-G3EADK2H.js} +4 -4
- package/dist/cli/chunks/heartbeat-scheduler-VZNKE33K.js +2 -0
- package/dist/cli/chunks/hnsw-adapter-LGWLDZLC.js +2 -0
- package/dist/cli/chunks/hnsw-index-66FOOI7U.js +2 -0
- package/dist/cli/chunks/{hnsw-legacy-bridge-FTV4CCBB.js → hnsw-legacy-bridge-MA676GER.js} +2 -2
- package/dist/cli/chunks/{better-sqlite3-RQCOOAZC.js → hnswlib-node-SKTT5KIH.js} +2 -2
- package/dist/cli/chunks/{hooks-SM4EU52N.js → hooks-HTCPMZNZ.js} +10 -10
- package/dist/cli/chunks/hybrid-router-I5MEVQDF.js +2 -0
- package/dist/cli/chunks/{hypergraph-engine-RRMX4N3L.js → hypergraph-engine-QPB3IH4A.js} +2 -2
- package/dist/cli/chunks/{hypergraph-handler-MNFGDKAP.js → hypergraph-handler-GBFSVD7N.js} +3 -3
- package/dist/cli/chunks/impact-analyzer-K6ANYIY3.js +2 -0
- package/dist/cli/chunks/{init-handler-BNHIJ5TX.js → init-handler-XYBTBCPD.js} +6 -6
- package/dist/cli/chunks/init-wizard-URHGXJ32.js +2 -0
- package/dist/cli/chunks/kernel-OKI5ZY5P.js +2 -0
- package/dist/cli/chunks/{kilocode-installer-GFKUKPLY.js → kilocode-installer-LY6JOBFY.js} +2 -2
- package/dist/cli/chunks/{kiro-installer-YBIYKODN.js → kiro-installer-JF6NXTJL.js} +2 -2
- package/dist/cli/chunks/knowledge-graph-VQQSK7T5.js +2 -0
- package/dist/cli/chunks/{learning-QEWUPCK6.js → learning-BIISN67N.js} +3 -3
- package/dist/cli/chunks/{llm-router-D5FQIMVQ.js → llm-router-YZUNVZQE.js} +4 -4
- package/dist/cli/chunks/llm-router-service-TISH33SY.js +2 -0
- package/dist/cli/chunks/{load-CLBUCKZQ.js → load-MTWNBNLL.js} +2 -2
- package/dist/cli/chunks/load-test-KWKWC4Q7.js +2 -0
- package/dist/cli/chunks/{mcp-VOMG5DPV.js → mcp-37PYMNHQ.js} +2 -2
- package/dist/cli/chunks/{memory-WZO63VSC.js → memory-IXUUDCI3.js} +5 -5
- package/dist/cli/chunks/memory-backend-JSQQMXVS.js +2 -0
- package/dist/cli/chunks/memory-handlers-RM2VOFJX.js +2 -0
- package/dist/cli/chunks/{multi-model-executor-7UKW43VV.js → multi-model-executor-RKKS5XYG.js} +2 -2
- package/dist/cli/chunks/{opencode-installer-MLFPRRL2.js → opencode-installer-3VXI5MTR.js} +2 -2
- package/dist/cli/chunks/{orchestrator-XNYDBGIN.js → orchestrator-UO3ZOGFZ.js} +5 -5
- package/dist/cli/chunks/pattern-null-store-SXBIUKE5.js +2 -0
- package/dist/cli/chunks/{pattern-usage-recorder-ZAP7ASQI.js → pattern-usage-recorder-YJKRL2GI.js} +2 -2
- package/dist/cli/chunks/{pipeline-4EJYOPBC.js → pipeline-GJQJKXWX.js} +2 -2
- package/dist/cli/chunks/{platform-ALPOWCOH.js → platform-RHVCZK6C.js} +2 -2
- package/dist/cli/chunks/{plugin-S2RX3KHR.js → plugin-ZKAIW7O6.js} +2 -2
- package/dist/cli/chunks/{prime-radiant-advanced-wasm-P2JB73XX.js → prime-radiant-advanced-wasm-4X3DSKQV.js} +2 -2
- package/dist/cli/chunks/protocol-executor-D3Q5P3WY.js +2 -0
- package/dist/cli/chunks/{protocol-handler-ZBJXSESA.js → protocol-handler-KKYQZMB2.js} +2 -2
- package/dist/cli/chunks/{prove-MYJ5YV45.js → prove-OD6RPKWX.js} +2 -2
- package/dist/cli/chunks/provider-manager-2EIX7E5Q.js +2 -0
- package/dist/cli/chunks/qe-reasoning-bank-ITOW2ZHC.js +2 -0
- package/dist/cli/chunks/{quality-NIACQC4M.js → quality-ZRWBXCKO.js} +2 -2
- package/dist/cli/chunks/{quality-gate-OAZ23ON5.js → quality-gate-Y6BWQV7J.js} +3 -3
- package/dist/cli/chunks/queen-coordinator-TO5X2EXL.js +2 -0
- package/dist/cli/chunks/{real-embeddings-6I4LP7PL.js → real-embeddings-YYEUO4P2.js} +2 -2
- package/dist/cli/chunks/{roocode-installer-LRQHP6MK.js → roocode-installer-JBCPS3FK.js} +2 -2
- package/dist/cli/chunks/router-GZJQEJU3.js +2 -0
- package/dist/cli/chunks/routing-feedback-CRXSKFNS.js +2 -0
- package/dist/cli/chunks/{routing-handler-A7BW7MV4.js → routing-handler-KTPJOSBJ.js} +2 -2
- package/dist/cli/chunks/{ruvector-commands-ZDRRFSJS.js → ruvector-commands-SCZZVRE7.js} +2 -2
- package/dist/cli/chunks/{rvf-dual-writer-QWE3Z6BB.js → rvf-dual-writer-IP7GELQJ.js} +2 -2
- package/dist/cli/chunks/{rvf-migration-adapter-6UDAP7QB.js → rvf-migration-adapter-WLFTDARU.js} +2 -2
- package/dist/cli/chunks/{rvf-migration-coordinator-FEW2N4R4.js → rvf-migration-coordinator-MGFDQ5WD.js} +2 -2
- package/dist/cli/chunks/rvf-native-adapter-WHADT5HX.js +2 -0
- package/dist/cli/chunks/rvf-store-integrity-OTOAGT5W.js +2 -0
- package/dist/cli/chunks/safe-db-MIZ2OFWC.js +2 -0
- package/dist/cli/chunks/schedule-XFILYTYC.js +2 -0
- package/dist/cli/chunks/scheduler-EIPJ777A.js +2 -0
- package/dist/cli/chunks/{security-KFXBV65O.js → security-B2CLZKRB.js} +3 -3
- package/dist/cli/chunks/shared-rvf-adapter-2PMFAQMN.js +2 -0
- package/dist/cli/chunks/{shared-rvf-dual-writer-CXXTB7CU.js → shared-rvf-dual-writer-B6P732AV.js} +2 -2
- package/dist/cli/chunks/sqlite-persistence-PFU3GSRD.js +2 -0
- package/dist/cli/chunks/{status-handler-CXSVM236.js → status-handler-M6SN2W2D.js} +2 -2
- package/dist/cli/chunks/{structural-health-LMHSM7MJ.js → structural-health-YCCTGI3K.js} +2 -2
- package/dist/cli/chunks/{sync-REEFKICL.js → sync-3SDMVAIU.js} +2 -2
- package/dist/cli/chunks/{sync-DMOUY2EY.js → sync-KSRF77ID.js} +2 -2
- package/dist/cli/chunks/{task-handler-DMSNFIH3.js → task-handler-MIKRB2SL.js} +2 -2
- package/dist/cli/chunks/{task-handlers-3Z3QV7X7.js → task-handlers-YXKRUBQ4.js} +3 -3
- package/dist/cli/chunks/{test-U6CGMDLN.js → test-MLOLQCB7.js} +4 -4
- package/dist/cli/chunks/{test-scheduling-YHYA3BP5.js → test-scheduling-3KXESUZS.js} +3 -3
- package/dist/cli/chunks/token-bootstrap-6V2PMDBJ.js +2 -0
- package/dist/cli/chunks/{token-usage-EOOTM7Q3.js → token-usage-DP6THJ3I.js} +2 -2
- package/dist/cli/chunks/{transformers-EKDJW2H6.js → transformers-QFOBOP2Y.js} +2 -2
- package/dist/cli/chunks/{tree-sitter-wasm-parser-HTGAXDQA.js → tree-sitter-wasm-parser-COK2XERS.js} +2 -2
- package/dist/cli/chunks/{types-GLRXY4RY.js → types-PYHUCVOZ.js} +2 -2
- package/dist/cli/chunks/unified-memory-OUVCMFGK.js +2 -0
- package/dist/cli/chunks/unified-memory-hnsw-YGQPOHXB.js +2 -0
- package/dist/cli/chunks/unified-persistence-GFRZVDOW.js +2 -0
- package/dist/cli/chunks/{upgrade-KU55H77X.js → upgrade-ONP2HNGL.js} +2 -2
- package/dist/cli/chunks/{validate-26VSBOJN.js → validate-NWSICDAY.js} +2 -2
- package/dist/cli/chunks/{validate-swarm-OIALRDKF.js → validate-swarm-KXS5P3U7.js} +2 -2
- package/dist/cli/chunks/{vibium-LOTWW25P.js → vibium-TZSGZRCQ.js} +2 -2
- package/dist/cli/chunks/visual-security-LVOOYQ64.js +2 -0
- package/dist/cli/chunks/{web-tree-sitter-6LWPPBYU.js → web-tree-sitter-V2FADNRA.js} +2 -2
- package/dist/cli/chunks/{windsurf-installer-ILOQYENG.js → windsurf-installer-GQM7KWDC.js} +2 -2
- package/dist/cli/chunks/{witness-chain-YBS6OHS4.js → witness-chain-GTITDIA2.js} +2 -2
- package/dist/cli/chunks/witness-chain-QNFPV4UL.js +2 -0
- package/dist/cli/chunks/{witness-key-manager-SI3WV3ZQ.js → witness-key-manager-AHRM2M52.js} +2 -2
- package/dist/cli/chunks/{workflow-GY6SJRQW.js → workflow-XCGHEL3I.js} +4 -4
- package/dist/cli/chunks/workflow-orchestrator-MIVBCALG.js +2 -0
- package/dist/cli/chunks/{wrappers-MMO5YKOZ.js → wrappers-VGO2GO4J.js} +2 -2
- package/dist/integrations/ruvector/brain-rvf-exporter.js +115 -13
- package/dist/integrations/ruvector/rvf-dual-writer.js +20 -3
- package/dist/integrations/ruvector/rvf-store-integrity.d.ts +49 -0
- package/dist/integrations/ruvector/rvf-store-integrity.js +137 -0
- package/dist/integrations/ruvector/shared-rvf-adapter.js +23 -5
- package/dist/learning/pattern-store.js +23 -5
- package/dist/learning/qe-flywheel/platform-signer.d.ts +32 -0
- package/dist/learning/qe-flywheel/platform-signer.js +60 -0
- package/dist/learning/qe-flywheel/receipt.js +9 -2
- package/dist/mcp/bundle.js +363 -363
- package/package.json +2 -2
- package/dist/cli/chunks/adapter-RL6GNUOS.js +0 -2
- package/dist/cli/chunks/aqe-learning-engine-UEEW6AQG.js +0 -2
- package/dist/cli/chunks/base-JQA5YULE.js +0 -2
- package/dist/cli/chunks/brain-handler-T7RDPKNM.js +0 -89
- package/dist/cli/chunks/browser-workflow-XTKUHTIT.js +0 -2
- package/dist/cli/chunks/chunk-KPV4N4KT.js +0 -9
- package/dist/cli/chunks/chunk-T75VH6NT.js +0 -2
- package/dist/cli/chunks/chunk-YY4KXDI6.js +0 -2
- package/dist/cli/chunks/client-S7DIRNFJ.js +0 -2
- package/dist/cli/chunks/core-handlers-NM2KCI6Z.js +0 -2
- package/dist/cli/chunks/cross-domain-router-3TSZMCBM.js +0 -2
- package/dist/cli/chunks/dream-QIIJONYI.js +0 -2
- package/dist/cli/chunks/heartbeat-scheduler-CDNGLJJO.js +0 -2
- package/dist/cli/chunks/hnsw-adapter-CR7Y4OAM.js +0 -2
- package/dist/cli/chunks/hnsw-index-TEDO4MQC.js +0 -2
- package/dist/cli/chunks/hybrid-router-O24ZDIP5.js +0 -2
- package/dist/cli/chunks/impact-analyzer-PDM4SDB6.js +0 -2
- package/dist/cli/chunks/init-wizard-F4KODPNW.js +0 -2
- package/dist/cli/chunks/kernel-77UM35L6.js +0 -2
- package/dist/cli/chunks/knowledge-graph-R6ZWWV2K.js +0 -2
- package/dist/cli/chunks/llm-router-service-7QYCZ66H.js +0 -2
- package/dist/cli/chunks/load-test-AWVA3CAQ.js +0 -2
- package/dist/cli/chunks/memory-backend-YESSIHFW.js +0 -2
- package/dist/cli/chunks/memory-handlers-EOOWSUHI.js +0 -2
- package/dist/cli/chunks/pattern-null-store-X3UXLJNL.js +0 -2
- package/dist/cli/chunks/protocol-executor-KXDCTMWI.js +0 -2
- package/dist/cli/chunks/provider-manager-XJZVHYI6.js +0 -2
- package/dist/cli/chunks/qe-reasoning-bank-DPHPNIC6.js +0 -2
- package/dist/cli/chunks/queen-coordinator-EVGWME5C.js +0 -2
- package/dist/cli/chunks/router-R2N7TMAS.js +0 -2
- package/dist/cli/chunks/routing-feedback-G6W3H26L.js +0 -2
- package/dist/cli/chunks/rvf-native-adapter-D7R2GWXK.js +0 -2
- package/dist/cli/chunks/safe-db-CQZGF2KA.js +0 -2
- package/dist/cli/chunks/schedule-UP7E3LRC.js +0 -2
- package/dist/cli/chunks/scheduler-ENIZHYSL.js +0 -2
- package/dist/cli/chunks/shared-rvf-adapter-HDDCXCHY.js +0 -2
- package/dist/cli/chunks/sqlite-persistence-CEVJVWS5.js +0 -2
- package/dist/cli/chunks/token-bootstrap-MQCTJURQ.js +0 -2
- package/dist/cli/chunks/unified-memory-PXOQ4N53.js +0 -2
- package/dist/cli/chunks/unified-memory-hnsw-VEXD6ASE.js +0 -2
- package/dist/cli/chunks/unified-persistence-46G6MZYC.js +0 -2
- package/dist/cli/chunks/visual-security-4X3T3MFL.js +0 -2
- package/dist/cli/chunks/witness-chain-XW4S3LVW.js +0 -2
- package/dist/cli/chunks/workflow-orchestrator-IIVV6TCP.js +0 -2
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{createRequire as __cr}from"module";const require=__cr(import.meta.url);if(process.argv.includes('--version')||process.argv.includes('-v')){console.log("3.12.3");process.exit(0)}
|
|
2
|
+
import{a,b,c,d}from"./chunk-PDX7IYTJ.js";import"./chunk-Y6XNISHP.js";import"./chunk-NOSQI2OW.js";import"./chunk-FJACKKRL.js";import"./chunk-L2X3BWMN.js";import"./chunk-G5OGKVLO.js";import"./chunk-4EHW4TNA.js";import"./chunk-NJDLJ3KD.js";import"./chunk-OBL6W4Z5.js";import"./chunk-NKTLKMUB.js";import"./chunk-2LNDU7AW.js";import"./chunk-EOUJ6X5H.js";import"./chunk-ULQCEM7K.js";import"./chunk-UAPUA6OY.js";import"./chunk-GS6G7AVS.js";import"./chunk-YUDGQZJN.js";import"./chunk-HJ4U64BL.js";import"./chunk-CYSBM52D.js";import"./chunk-NLDLUHOF.js";import"./chunk-PEHEANAM.js";import"./chunk-XUUVAAHV.js";import"./chunk-SGMJ277D.js";export{b as DEFAULT_WORKFLOW_CONFIG,a as WorkflowEvents,c as WorkflowOrchestrator,d as createWorkflowOrchestrator};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createRequire as __cr}from"module";const require=__cr(import.meta.url);if(process.argv.includes('--version')||process.argv.includes('-v')){console.log("3.12.
|
|
2
|
-
import{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v as L,w as M,x as N}from"./chunk-
|
|
1
|
+
import{createRequire as __cr}from"module";const require=__cr(import.meta.url);if(process.argv.includes('--version')||process.argv.includes('-v')){console.log("3.12.3");process.exit(0)}
|
|
2
|
+
import{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v as L,w as M,x as N}from"./chunk-QILF6BZH.js";import{a as v,b as w,c as x,d as y,e as z,f as A,g as B,h as C,i as D,j as E,k as F,l as G,m as H,n as I,o as J,p as K}from"./chunk-YOG5KQZF.js";import"./chunk-NOSQI2OW.js";import"./chunk-FJACKKRL.js";import"./chunk-L2X3BWMN.js";import"./chunk-G5OGKVLO.js";import"./chunk-4EHW4TNA.js";import"./chunk-NJDLJ3KD.js";import"./chunk-OBL6W4Z5.js";import"./chunk-2LNDU7AW.js";import"./chunk-ULQCEM7K.js";import"./chunk-UAPUA6OY.js";import"./chunk-GS6G7AVS.js";import"./chunk-YUDGQZJN.js";import"./chunk-HJ4U64BL.js";import"./chunk-CYSBM52D.js";import"./chunk-NLDLUHOF.js";import"./chunk-PEHEANAM.js";import"./chunk-XUUVAAHV.js";import"./chunk-SGMJ277D.js";export{z as GNNLayerFactory,i as QEFlashAttention,x as QEGNNEmbeddingIndex,y as QEGNNIndexFactory,a as QESONA,e as QE_FLASH_ATTENTION_CONFIG,g as QE_PERFORMANCE_TARGETS,f as QE_SONA_CONFIG,A as TensorCompressionFactory,u as batchComputeAttention,K as batchDifferentiableSearch,M as checkRuvectorPackagesAvailable,c as createDomainQESONA,j as createQEFlashAttention,b as createQESONA,D as getDifferentiableSearch,F as getGetCompressionLevel,E as getHierarchicalForward,G as getInit,h as getOptimalBlockConfig,k as getQEFlashAttentionConfig,n as getRuvectorDotProductAttention,m as getRuvectorFlashAttention,p as getRuvectorHyperbolicAttention,B as getRuvectorLayer,q as getRuvectorLinearAttention,r as getRuvectorMoEAttention,o as getRuvectorMultiHeadAttention,L as getRuvectorPackageVersions,C as getTensorCompress,l as getWorkloadTypes,N as initAllRuvectorPackages,w as initGNN,d as isAttentionAvailable,v as isGNNAvailable,s as toFloat32Array,H as toFloat32ArrayGNN,J as toIEmbedding,t as toNumberArrayAttn,I as toNumberArrayGNN};
|
|
@@ -3,11 +3,82 @@
|
|
|
3
3
|
* `.rvf` file using the @ruvector/rvf-node native binding via rvf-native-adapter.
|
|
4
4
|
* Falls back to JSONL directory format when the native binding is unavailable.
|
|
5
5
|
*/
|
|
6
|
-
import { existsSync, statSync, unlinkSync, writeFileSync } from 'fs';
|
|
7
|
-
import { resolve } from 'path';
|
|
6
|
+
import { existsSync, readdirSync, renameSync, statSync, unlinkSync, writeFileSync } from 'fs';
|
|
7
|
+
import { basename, dirname, join, resolve } from 'path';
|
|
8
8
|
import { createRvfStore, openRvfStore, openRvfStoreReadonly, isRvfNativeAvailable, } from './rvf-native-adapter.js';
|
|
9
9
|
import { sha256, tableExists, queryAll, domainFilterForColumn, ensureTargetTables, mergeGenericRow, mergeAppendOnlyRow, TABLE_CONFIGS, TABLE_BLOB_COLUMNS, PK_COLUMNS, CONFIDENCE_COLUMNS, TIMESTAMP_COLUMNS, serializeRowBlobs, deserializeRowBlobs, } from './brain-shared.js';
|
|
10
10
|
// --- Export ---
|
|
11
|
+
/**
|
|
12
|
+
* Sidecar suffixes that make up a complete store on disk. `''` is the store
|
|
13
|
+
* itself; the adapter writes `.idmap.json` on close, and we write the manifest.
|
|
14
|
+
*/
|
|
15
|
+
const RVF_STORE_SUFFIXES = ['', '.idmap.json', '.manifest.json'];
|
|
16
|
+
/**
|
|
17
|
+
* Everything an abandoned tmp export can leave behind. `.lock` is cleaned up
|
|
18
|
+
* but deliberately absent from RVF_STORE_SUFFIXES — renaming a lock into the
|
|
19
|
+
* final path is the very corruption this fix exists to prevent.
|
|
20
|
+
*/
|
|
21
|
+
const RVF_CLEANUP_SUFFIXES = [...RVF_STORE_SUFFIXES, '.lock'];
|
|
22
|
+
/** Best-effort removal of a store and its sidecars at `base`. */
|
|
23
|
+
function removeStoreFiles(base) {
|
|
24
|
+
for (const suffix of RVF_CLEANUP_SUFFIXES) {
|
|
25
|
+
try {
|
|
26
|
+
const p = `${base}${suffix}`;
|
|
27
|
+
if (existsSync(p))
|
|
28
|
+
unlinkSync(p);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// best-effort — a leftover tmp is inert, unlike a corrupt final store
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Remove tmp stores orphaned by killed exports (#563). Each interrupted export
|
|
37
|
+
* strands a full-size tmp store, so on a project where the checkpoint hook is
|
|
38
|
+
* killed regularly these would accumulate unbounded.
|
|
39
|
+
*
|
|
40
|
+
* Only tmps whose owning pid is gone are removed: a live pid means a concurrent
|
|
41
|
+
* export is mid-write, and deleting its tmp would corrupt exactly what this
|
|
42
|
+
* change exists to protect.
|
|
43
|
+
*/
|
|
44
|
+
function sweepStaleTmpFiles(outPath) {
|
|
45
|
+
const dir = dirname(outPath);
|
|
46
|
+
const prefix = `${basename(outPath)}.tmp.`;
|
|
47
|
+
let entries;
|
|
48
|
+
try {
|
|
49
|
+
entries = readdirSync(dir);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
for (const entry of entries) {
|
|
55
|
+
if (!entry.startsWith(prefix))
|
|
56
|
+
continue;
|
|
57
|
+
// `<name>.rvf.tmp.<pid>` and its `<...>.tmp.<pid>.idmap.json` siblings.
|
|
58
|
+
const pid = Number.parseInt(entry.slice(prefix.length).split('.')[0], 10);
|
|
59
|
+
if (!Number.isInteger(pid) || pid <= 0)
|
|
60
|
+
continue;
|
|
61
|
+
if (pid !== process.pid && isPidAlive(pid))
|
|
62
|
+
continue;
|
|
63
|
+
try {
|
|
64
|
+
unlinkSync(join(dir, entry));
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// best-effort
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/** True when a process with `pid` exists (signal 0 probes without delivering). */
|
|
72
|
+
function isPidAlive(pid) {
|
|
73
|
+
try {
|
|
74
|
+
process.kill(pid, 0);
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
// EPERM means it exists but belongs to another user — still alive.
|
|
79
|
+
return err.code === 'EPERM';
|
|
80
|
+
}
|
|
81
|
+
}
|
|
11
82
|
/** Export brain state to a single `.rvf` file with vector embeddings + kernel. */
|
|
12
83
|
export function exportBrainToRvf(db, options, sourceDbLabel = 'memory.db') {
|
|
13
84
|
if (!isRvfNativeAvailable()) {
|
|
@@ -15,14 +86,20 @@ export function exportBrainToRvf(db, options, sourceDbLabel = 'memory.db') {
|
|
|
15
86
|
}
|
|
16
87
|
const outPath = resolve(options.outputPath);
|
|
17
88
|
const dimension = options.dimension ?? 384;
|
|
18
|
-
//
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
89
|
+
// Issue #563: build the store at a private tmp path and rename it over the
|
|
90
|
+
// final path only once it is closed and complete. The previous code deleted
|
|
91
|
+
// the old store and then built the new one in place, so any interruption
|
|
92
|
+
// (hook timeout, session teardown, SIGKILL) left a created-but-incomplete
|
|
93
|
+
// store that could neither be opened (ManifestNotFound) nor created over
|
|
94
|
+
// (FsyncFailed) — permanently disabling the RVF backend. With tmp+rename an
|
|
95
|
+
// interrupted export leaves the *previous* good store untouched and orphans
|
|
96
|
+
// only an inert tmp file, which the next export sweeps.
|
|
97
|
+
const tmpPath = `${outPath}.tmp.${process.pid}`;
|
|
98
|
+
sweepStaleTmpFiles(outPath);
|
|
99
|
+
removeStoreFiles(tmpPath);
|
|
24
100
|
// Create RVF container via adapter (handles idmap automatically)
|
|
25
|
-
const rvf = createRvfStore(
|
|
101
|
+
const rvf = createRvfStore(tmpPath, dimension);
|
|
102
|
+
let closed = false;
|
|
26
103
|
try {
|
|
27
104
|
// --- Export all tables using TABLE_CONFIGS ---
|
|
28
105
|
const allTableData = {};
|
|
@@ -153,12 +230,37 @@ export function exportBrainToRvf(db, options, sourceDbLabel = 'memory.db') {
|
|
|
153
230
|
catch { /* best-effort */ }
|
|
154
231
|
}
|
|
155
232
|
// Persist manifest as sidecar JSON alongside the .rvf file
|
|
156
|
-
|
|
157
|
-
|
|
233
|
+
writeFileSync(`${tmpPath}.manifest.json`, JSON.stringify(manifest, null, 2), 'utf-8');
|
|
234
|
+
// Close before promoting: close() flushes the store and writes the idmap
|
|
235
|
+
// sidecar, so renaming any earlier would publish an incomplete store.
|
|
236
|
+
rvf.close();
|
|
237
|
+
closed = true;
|
|
238
|
+
// Promote tmp → final. The store itself goes last: until it lands, the
|
|
239
|
+
// previous store (if any) is still the one on disk, and a crash mid-promote
|
|
240
|
+
// leaves the old store readable rather than a half-written new one.
|
|
241
|
+
for (const suffix of [...RVF_STORE_SUFFIXES].reverse()) {
|
|
242
|
+
const from = `${tmpPath}${suffix}`;
|
|
243
|
+
const to = `${outPath}${suffix}`;
|
|
244
|
+
if (existsSync(from)) {
|
|
245
|
+
renameSync(from, to);
|
|
246
|
+
}
|
|
247
|
+
else if (existsSync(to)) {
|
|
248
|
+
// No new sidecar produced — drop the stale one so it can't be read
|
|
249
|
+
// against the new store.
|
|
250
|
+
unlinkSync(to);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
158
253
|
return manifest;
|
|
159
254
|
}
|
|
160
|
-
|
|
161
|
-
|
|
255
|
+
catch (err) {
|
|
256
|
+
if (!closed) {
|
|
257
|
+
try {
|
|
258
|
+
rvf.close();
|
|
259
|
+
}
|
|
260
|
+
catch { /* best-effort */ }
|
|
261
|
+
}
|
|
262
|
+
removeStoreFiles(tmpPath);
|
|
263
|
+
throw err;
|
|
162
264
|
}
|
|
163
265
|
}
|
|
164
266
|
/** Legacy field-to-table mapping for older RVF exports. */
|
|
@@ -87,14 +87,31 @@ export class RvfDualWriter {
|
|
|
87
87
|
nativeAdapter = adapter.openRvfStore(this.config.rvfPath);
|
|
88
88
|
}
|
|
89
89
|
catch {
|
|
90
|
-
|
|
90
|
+
try {
|
|
91
|
+
nativeAdapter = adapter.createRvfStore(this.config.rvfPath, this.config.dimensions);
|
|
92
|
+
}
|
|
93
|
+
catch (createErr) {
|
|
94
|
+
// Issue #563: open failed *and* create failed, so the file on disk is
|
|
95
|
+
// provably unusable — the signature of an export killed mid-write
|
|
96
|
+
// (open → ManifestNotFound, create → FsyncFailed because the path
|
|
97
|
+
// exists). Previously this fell to the catch below and disabled RVF
|
|
98
|
+
// silently for the whole run. Quarantine and rebuild instead.
|
|
99
|
+
const { quarantineUnusableStore } = await import('./rvf-store-integrity.js');
|
|
100
|
+
const quarantined = quarantineUnusableStore(this.config.rvfPath, createErr instanceof Error ? createErr.message : String(createErr));
|
|
101
|
+
if (!quarantined)
|
|
102
|
+
throw createErr; // live peer, or nothing to move
|
|
103
|
+
nativeAdapter = adapter.createRvfStore(this.config.rvfPath, this.config.dimensions);
|
|
104
|
+
}
|
|
91
105
|
}
|
|
92
106
|
this.rvfStore = wrapNativeAdapter(nativeAdapter, this.config.dimensions);
|
|
93
107
|
this.rvfAvailable = true;
|
|
94
108
|
}
|
|
95
|
-
catch {
|
|
96
|
-
// Native adapter
|
|
109
|
+
catch (err) {
|
|
110
|
+
// Native adapter unavailable, or recovery itself failed. Degrade to
|
|
111
|
+
// sqlite-only — but say so, instead of vanishing silently (#563).
|
|
97
112
|
this.rvfAvailable = false;
|
|
113
|
+
console.warn(`[RVF] Dual-writer disabled for ${this.config.rvfPath}; falling back to SQLite: ` +
|
|
114
|
+
`${err instanceof Error ? err.message : String(err)}`);
|
|
98
115
|
}
|
|
99
116
|
}
|
|
100
117
|
/**
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RVF store integrity helpers (issue #563).
|
|
3
|
+
*
|
|
4
|
+
* An export that is killed mid-write leaves a store that was created but never
|
|
5
|
+
* completed. Such a file cannot be opened (`RVF error 0x0106: ManifestNotFound`)
|
|
6
|
+
* and cannot be created over either, because the path already exists
|
|
7
|
+
* (`RVF error 0x0303: FsyncFailed`). Both paths fail forever, so the RVF
|
|
8
|
+
* backend stays disabled for the life of the project until someone deletes the
|
|
9
|
+
* file by hand.
|
|
10
|
+
*
|
|
11
|
+
* Recovery has to be evidence-based rather than fingerprint-based. Measured
|
|
12
|
+
* against @ruvector/rvf-node 0.1.8:
|
|
13
|
+
*
|
|
14
|
+
* • A *valid, empty* store is 162 bytes with magic `SFVR` — byte-for-byte
|
|
15
|
+
* the size the issue reports as "truncated: header only". Size and magic
|
|
16
|
+
* therefore cannot distinguish a broken store from a healthy empty one.
|
|
17
|
+
* • `<store>.lock` is a 104-byte record with magic `FLVR` and the owning pid
|
|
18
|
+
* as a little-endian u32 at offset 4. `FLVR` in a lock is the *normal*
|
|
19
|
+
* case — the issue reads it as "RVF store bytes leaked into the lock", but
|
|
20
|
+
* the store magic is `SFVR`; a 104-byte `FLVR` lock is just a live-or-stale
|
|
21
|
+
* lock record.
|
|
22
|
+
*
|
|
23
|
+
* So the only sound trigger is "open failed *and* create failed": at that point
|
|
24
|
+
* the file is provably unusable. The lock's pid is used as a *guard* — if it is
|
|
25
|
+
* held by a live process, the store is presumed healthy and left alone.
|
|
26
|
+
*/
|
|
27
|
+
/** The pid recorded in `<rvfPath>.lock`, or null if there is no readable lock. */
|
|
28
|
+
export declare function readLockOwnerPid(rvfPath: string): number | null;
|
|
29
|
+
/**
|
|
30
|
+
* True when the store's lock is held by a process that is still running.
|
|
31
|
+
*
|
|
32
|
+
* Deliberately conservative: an unreadable or pid-less lock reports false (the
|
|
33
|
+
* caller's open already failed, so there is nothing to protect), while a live
|
|
34
|
+
* pid reports true and blocks recovery. Pid reuse can only produce a false
|
|
35
|
+
* "alive", which fails safe — we leave the store alone.
|
|
36
|
+
*/
|
|
37
|
+
export declare function isLockHeldByLiveProcess(rvfPath: string): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Move an unusable store and its sidecars aside so the next create succeeds.
|
|
40
|
+
* Returns the quarantine base path, or null if nothing was quarantined.
|
|
41
|
+
*
|
|
42
|
+
* Only call this once open *and* create have both failed — that is the proof
|
|
43
|
+
* the file is unusable. The store is a derived cache, rebuilt from the unified
|
|
44
|
+
* DB, so quarantining is recoverable; we move rather than delete because the
|
|
45
|
+
* bytes may hold writes that never reached SQLite, and they are the only
|
|
46
|
+
* evidence if this recurs.
|
|
47
|
+
*/
|
|
48
|
+
export declare function quarantineUnusableStore(rvfPath: string, reason: string): string | null;
|
|
49
|
+
//# sourceMappingURL=rvf-store-integrity.d.ts.map
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RVF store integrity helpers (issue #563).
|
|
3
|
+
*
|
|
4
|
+
* An export that is killed mid-write leaves a store that was created but never
|
|
5
|
+
* completed. Such a file cannot be opened (`RVF error 0x0106: ManifestNotFound`)
|
|
6
|
+
* and cannot be created over either, because the path already exists
|
|
7
|
+
* (`RVF error 0x0303: FsyncFailed`). Both paths fail forever, so the RVF
|
|
8
|
+
* backend stays disabled for the life of the project until someone deletes the
|
|
9
|
+
* file by hand.
|
|
10
|
+
*
|
|
11
|
+
* Recovery has to be evidence-based rather than fingerprint-based. Measured
|
|
12
|
+
* against @ruvector/rvf-node 0.1.8:
|
|
13
|
+
*
|
|
14
|
+
* • A *valid, empty* store is 162 bytes with magic `SFVR` — byte-for-byte
|
|
15
|
+
* the size the issue reports as "truncated: header only". Size and magic
|
|
16
|
+
* therefore cannot distinguish a broken store from a healthy empty one.
|
|
17
|
+
* • `<store>.lock` is a 104-byte record with magic `FLVR` and the owning pid
|
|
18
|
+
* as a little-endian u32 at offset 4. `FLVR` in a lock is the *normal*
|
|
19
|
+
* case — the issue reads it as "RVF store bytes leaked into the lock", but
|
|
20
|
+
* the store magic is `SFVR`; a 104-byte `FLVR` lock is just a live-or-stale
|
|
21
|
+
* lock record.
|
|
22
|
+
*
|
|
23
|
+
* So the only sound trigger is "open failed *and* create failed": at that point
|
|
24
|
+
* the file is provably unusable. The lock's pid is used as a *guard* — if it is
|
|
25
|
+
* held by a live process, the store is presumed healthy and left alone.
|
|
26
|
+
*/
|
|
27
|
+
import { existsSync, openSync, readSync, closeSync, renameSync, unlinkSync } from 'fs';
|
|
28
|
+
/** Magic of a lock record (the store's own magic is `SFVR`). */
|
|
29
|
+
const LOCK_MAGIC = 'FLVR';
|
|
30
|
+
/** Byte offset of the owning pid within a lock record (u32 LE). */
|
|
31
|
+
const LOCK_PID_OFFSET = 4;
|
|
32
|
+
/** Sidecars that belong to a store and must be quarantined alongside it. */
|
|
33
|
+
const STORE_SIDECAR_SUFFIXES = ['', '.idmap.json', '.manifest.json'];
|
|
34
|
+
/** Read the first `n` bytes of a file, or null if unreadable/shorter. */
|
|
35
|
+
function readHead(path, n) {
|
|
36
|
+
let fd;
|
|
37
|
+
try {
|
|
38
|
+
fd = openSync(path, 'r');
|
|
39
|
+
const buf = Buffer.alloc(n);
|
|
40
|
+
if (readSync(fd, buf, 0, n, 0) < n)
|
|
41
|
+
return null;
|
|
42
|
+
return buf;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
if (fd !== undefined) {
|
|
49
|
+
try {
|
|
50
|
+
closeSync(fd);
|
|
51
|
+
}
|
|
52
|
+
catch { /* best-effort */ }
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** True when a process with `pid` exists (signal 0 probes without delivering). */
|
|
57
|
+
function isPidAlive(pid) {
|
|
58
|
+
try {
|
|
59
|
+
process.kill(pid, 0);
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
// EPERM means it exists but belongs to another user — still alive.
|
|
64
|
+
return err.code === 'EPERM';
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/** The pid recorded in `<rvfPath>.lock`, or null if there is no readable lock. */
|
|
68
|
+
export function readLockOwnerPid(rvfPath) {
|
|
69
|
+
const head = readHead(`${rvfPath}.lock`, LOCK_PID_OFFSET + 4);
|
|
70
|
+
if (!head || head.subarray(0, 4).toString('latin1') !== LOCK_MAGIC)
|
|
71
|
+
return null;
|
|
72
|
+
const pid = head.readUInt32LE(LOCK_PID_OFFSET);
|
|
73
|
+
return pid > 0 ? pid : null;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* True when the store's lock is held by a process that is still running.
|
|
77
|
+
*
|
|
78
|
+
* Deliberately conservative: an unreadable or pid-less lock reports false (the
|
|
79
|
+
* caller's open already failed, so there is nothing to protect), while a live
|
|
80
|
+
* pid reports true and blocks recovery. Pid reuse can only produce a false
|
|
81
|
+
* "alive", which fails safe — we leave the store alone.
|
|
82
|
+
*/
|
|
83
|
+
export function isLockHeldByLiveProcess(rvfPath) {
|
|
84
|
+
const pid = readLockOwnerPid(rvfPath);
|
|
85
|
+
if (pid === null)
|
|
86
|
+
return false;
|
|
87
|
+
return pid !== process.pid && isPidAlive(pid);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Move an unusable store and its sidecars aside so the next create succeeds.
|
|
91
|
+
* Returns the quarantine base path, or null if nothing was quarantined.
|
|
92
|
+
*
|
|
93
|
+
* Only call this once open *and* create have both failed — that is the proof
|
|
94
|
+
* the file is unusable. The store is a derived cache, rebuilt from the unified
|
|
95
|
+
* DB, so quarantining is recoverable; we move rather than delete because the
|
|
96
|
+
* bytes may hold writes that never reached SQLite, and they are the only
|
|
97
|
+
* evidence if this recurs.
|
|
98
|
+
*/
|
|
99
|
+
export function quarantineUnusableStore(rvfPath, reason) {
|
|
100
|
+
if (!existsSync(rvfPath))
|
|
101
|
+
return null;
|
|
102
|
+
// Never pull a store out from under a live peer.
|
|
103
|
+
if (isLockHeldByLiveProcess(rvfPath)) {
|
|
104
|
+
console.warn(`[RVF] ${rvfPath} is unusable but its lock is held by a live process — ` +
|
|
105
|
+
'leaving it alone and degrading to SQLite for this run.');
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
// Keyed by pid, not a timestamp: a crash-loop quarantining the same file
|
|
109
|
+
// repeatedly overwrites its own copy instead of filling .agentic-qe/ with
|
|
110
|
+
// one corrupt store per startup.
|
|
111
|
+
const quarantineBase = `${rvfPath}.corrupt-${process.pid}`;
|
|
112
|
+
for (const sidecar of STORE_SIDECAR_SUFFIXES) {
|
|
113
|
+
const from = `${rvfPath}${sidecar}`;
|
|
114
|
+
if (!existsSync(from))
|
|
115
|
+
continue;
|
|
116
|
+
try {
|
|
117
|
+
renameSync(from, `${quarantineBase}${sidecar}`);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
// A failed quarantine must not throw and take down the caller; the
|
|
121
|
+
// caller's retry will simply fail again and degrade as before.
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// The store is gone, so its lock — stale by definition here — goes with it.
|
|
125
|
+
try {
|
|
126
|
+
if (existsSync(`${rvfPath}.lock`))
|
|
127
|
+
unlinkSync(`${rvfPath}.lock`);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
// best-effort
|
|
131
|
+
}
|
|
132
|
+
console.warn(`[RVF] Quarantined unusable store ${rvfPath} → ${quarantineBase} (${reason}). ` +
|
|
133
|
+
'It is a derived cache and will be rebuilt from the unified DB. ' +
|
|
134
|
+
'Please report a recurrence with the quarantined files (issue #563).');
|
|
135
|
+
return quarantineBase;
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=rvf-store-integrity.js.map
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
// Issue #516: lightweight, sqlite-free project-root resolver (static import so it
|
|
14
14
|
// resolves under the test runner; avoids pulling unified-memory's sqlite graph).
|
|
15
15
|
import { findProjectRoot } from '../../kernel/project-root.js';
|
|
16
|
+
// Issue #563: static import — this module is fs-only, and a require() here
|
|
17
|
+
// would not resolve under the test runner.
|
|
18
|
+
import { quarantineUnusableStore, isLockHeldByLiveProcess, readLockOwnerPid, } from './rvf-store-integrity.js';
|
|
16
19
|
let sharedAdapter = null;
|
|
17
20
|
let initAttempted = false;
|
|
18
21
|
// ---------------------------------------------------------------------------
|
|
@@ -131,16 +134,23 @@ function openOrCreateRvf(openFn, createFn, rvfPath, dimensions) {
|
|
|
131
134
|
// .lock that subsequent invocations interpret as `LockHeld`. Since AQE
|
|
132
135
|
// CLI is overwhelmingly single-shot serial, the realistic case is "the
|
|
133
136
|
// prior process is dead and the lock is stale". We unlink the .lock and
|
|
134
|
-
// retry open exactly once.
|
|
135
|
-
//
|
|
136
|
-
//
|
|
137
|
-
//
|
|
137
|
+
// retry open exactly once.
|
|
138
|
+
//
|
|
139
|
+
// Issue #563: the lock record turns out to carry its owner's pid (u32 LE at
|
|
140
|
+
// offset 4, after the `FLVR` magic), so "is it stale?" is now a check rather
|
|
141
|
+
// than an assumption. This previously unlinked the lock unconditionally,
|
|
142
|
+
// which breaks a genuinely-live peer — the one case the old comment admitted
|
|
143
|
+
// it could not distinguish.
|
|
138
144
|
if (!opened && isLockHeld(openErr)) {
|
|
139
145
|
try {
|
|
140
146
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
141
147
|
const fs = require('fs');
|
|
142
148
|
const lockPath = `${rvfPath}.lock`;
|
|
143
|
-
if (fs.existsSync(lockPath)) {
|
|
149
|
+
if (fs.existsSync(lockPath) && isLockHeldByLiveProcess(rvfPath)) {
|
|
150
|
+
console.warn(`[RVF] ${rvfPath} is locked by a live process (pid ${readLockOwnerPid(rvfPath)}) — ` +
|
|
151
|
+
'not breaking the lock; degrading to SQLite for this run.');
|
|
152
|
+
}
|
|
153
|
+
else if (fs.existsSync(lockPath)) {
|
|
144
154
|
fs.unlinkSync(lockPath);
|
|
145
155
|
console.warn(`[RVF] Removed stale lock file at ${lockPath} (prior process exited without closing). ` +
|
|
146
156
|
'Retrying open. If you see this repeatedly under live concurrency, file an issue.');
|
|
@@ -187,6 +197,14 @@ function openOrCreateRvf(openFn, createFn, rvfPath, dimensions) {
|
|
|
187
197
|
return reopened;
|
|
188
198
|
}
|
|
189
199
|
catch {
|
|
200
|
+
// Pass 4 (#563): open failed, create failed, re-open failed. The file is
|
|
201
|
+
// provably unusable — the signature of an export killed mid-write, which
|
|
202
|
+
// used to disable the RVF backend permanently. Quarantine it (unless a
|
|
203
|
+
// live process holds its lock) and rebuild the derived cache.
|
|
204
|
+
const quarantined = quarantineUnusableStore(rvfPath, createErr instanceof Error ? createErr.message : String(createErr));
|
|
205
|
+
if (quarantined) {
|
|
206
|
+
return createFn(rvfPath, dimensions);
|
|
207
|
+
}
|
|
190
208
|
// Fall through with the more informative original error.
|
|
191
209
|
throw createErr instanceof Error ? createErr : new Error(String(createErr));
|
|
192
210
|
}
|
|
@@ -11,7 +11,13 @@ import { v4 as uuidv4 } from 'uuid';
|
|
|
11
11
|
import { findProjectRoot } from '../kernel/project-root.js';
|
|
12
12
|
import { ok, err } from '../shared/types/index.js';
|
|
13
13
|
import { RvfPatternStore } from './rvf-pattern-store.js';
|
|
14
|
-
import { createRvfStore as _createRvfStore, isRvfNativeAvailable } from '../integrations/ruvector/rvf-native-adapter.js';
|
|
14
|
+
import { createRvfStore as _createRvfStore, openRvfStore as _openRvfStore, isRvfNativeAvailable, } from '../integrations/ruvector/rvf-native-adapter.js';
|
|
15
|
+
// Issue #563: static imports — a require() of a source module resolves in the
|
|
16
|
+
// esbuild bundle but throws under the test runner, which silently changed which
|
|
17
|
+
// code path tests exercised. Neither module loads the native binding at import
|
|
18
|
+
// time, so this costs nothing at startup.
|
|
19
|
+
import { quarantineUnusableStore } from '../integrations/ruvector/rvf-store-integrity.js';
|
|
20
|
+
import { getSharedRvfAdapter } from '../integrations/ruvector/shared-rvf-adapter.js';
|
|
15
21
|
import { toErrorMessage, toError } from '../shared/error-utils.js';
|
|
16
22
|
import { calculateQualityScore, shouldPromotePattern, validateQEPattern, mapQEDomainToAQE, PROMOTION_THRESHOLD, } from './qe-patterns.js';
|
|
17
23
|
import { applyFilterSync } from '../integrations/ruvector/filter-adapter.js';
|
|
@@ -1419,7 +1425,9 @@ export function createPatternStore(memory, config) {
|
|
|
1419
1425
|
// deadlock on the native lock.
|
|
1420
1426
|
let useSharedAdapter = false;
|
|
1421
1427
|
try {
|
|
1422
|
-
|
|
1428
|
+
// Statically imported (#563): this require() throws "Cannot find
|
|
1429
|
+
// module" under the test runner, so every test silently took the
|
|
1430
|
+
// fallback ladder below instead of this preferred path.
|
|
1423
1431
|
const shared = getSharedRvfAdapter(rvfDir, mergedConfig.embeddingDimension);
|
|
1424
1432
|
if (shared) {
|
|
1425
1433
|
useSharedAdapter = true;
|
|
@@ -1439,11 +1447,13 @@ export function createPatternStore(memory, config) {
|
|
|
1439
1447
|
// open first, fall back to create, retry open on create-race.
|
|
1440
1448
|
// (Jordi #439 / RUFLO P020.)
|
|
1441
1449
|
const store = new RvfPatternStore((path, dim) => {
|
|
1442
|
-
//
|
|
1443
|
-
|
|
1450
|
+
// Statically imported (#563): a require() here resolves in the
|
|
1451
|
+
// esbuild bundle but throws "Cannot find module" under the test
|
|
1452
|
+
// runner, so this ladder — including its corruption recovery —
|
|
1453
|
+
// was unreachable from any test.
|
|
1444
1454
|
const tryOpen = () => {
|
|
1445
1455
|
try {
|
|
1446
|
-
return
|
|
1456
|
+
return _openRvfStore(path);
|
|
1447
1457
|
}
|
|
1448
1458
|
catch {
|
|
1449
1459
|
return null;
|
|
@@ -1467,6 +1477,14 @@ export function createPatternStore(memory, config) {
|
|
|
1467
1477
|
adapter = tryOpen();
|
|
1468
1478
|
if (adapter && adapter.dimension() === dim)
|
|
1469
1479
|
return adapter;
|
|
1480
|
+
// Issue #563: open failed, create failed, re-open failed — the
|
|
1481
|
+
// store is provably unusable (an export killed mid-write leaves
|
|
1482
|
+
// exactly this). Without recovery, RvfPatternStore.initialize()
|
|
1483
|
+
// logs "vector search is DISABLED" and stays that way for the
|
|
1484
|
+
// life of the process.
|
|
1485
|
+
if (quarantineUnusableStore(path, createErr instanceof Error ? createErr.message : String(createErr))) {
|
|
1486
|
+
return _createRvfStore(path, dim);
|
|
1487
|
+
}
|
|
1470
1488
|
throw createErr;
|
|
1471
1489
|
}
|
|
1472
1490
|
}, { rvfPath, base: mergedConfig });
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Witness-key bridge (qe-harness issue #7) — sign flywheel receipts with the ONE
|
|
3
|
+
* Cognitum platform identity instead of a self-generated key, so every QE receipt
|
|
4
|
+
* (engine campaign · flywheel promotion · coherence verdict) chains to the same
|
|
5
|
+
* externally-verifiable key (`QE_WITNESS_PUBLIC_KEYS_JSON` allowlist, fingerprint
|
|
6
|
+
* `f1ac28607da49ec1`).
|
|
7
|
+
*
|
|
8
|
+
* `createSigner` already accepts a 32-byte Ed25519 seed → deterministic keypair.
|
|
9
|
+
* The platform key is delivered as `QE_WITNESS_SIGNING_KEY` — a JSON
|
|
10
|
+
* `{ publicKey, privateKey }` of PEM strings (same shape qe-harness Stage-B reads
|
|
11
|
+
* from Secret Manager). We derive the seed from that private key and hand it to
|
|
12
|
+
* `createSigner`, reproducing the exact platform keypair.
|
|
13
|
+
*
|
|
14
|
+
* Graceful: returns null when the env var is absent/malformed, so the flywheel
|
|
15
|
+
* keeps its self-generated-key behaviour where the platform key isn't provided.
|
|
16
|
+
* Env-reading lives HERE, not in the dependency-free `receipt.ts` core.
|
|
17
|
+
*/
|
|
18
|
+
import { type Signer } from './receipt.js';
|
|
19
|
+
/**
|
|
20
|
+
* Extract the raw 32-byte Ed25519 seed from a PKCS#8 private-key PEM. Throws if the
|
|
21
|
+
* key is not an Ed25519 PKCS#8 key (wrong curve / format).
|
|
22
|
+
*/
|
|
23
|
+
export declare function seedFromPkcs8Pem(privateKeyPem: string): Buffer;
|
|
24
|
+
/**
|
|
25
|
+
* Build a {@link Signer} bound to the Cognitum platform identity from
|
|
26
|
+
* `QE_WITNESS_SIGNING_KEY`, or null when it is unset/malformed (graceful fallback).
|
|
27
|
+
* The returned signer's `keyId` equals the platform witness fingerprint, so a
|
|
28
|
+
* verifier can attribute the receipt to the platform via the same allowlist that
|
|
29
|
+
* accepts qe-harness evidence bundles.
|
|
30
|
+
*/
|
|
31
|
+
export declare function platformSigner(env?: NodeJS.ProcessEnv): Signer | null;
|
|
32
|
+
//# sourceMappingURL=platform-signer.d.ts.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Witness-key bridge (qe-harness issue #7) — sign flywheel receipts with the ONE
|
|
3
|
+
* Cognitum platform identity instead of a self-generated key, so every QE receipt
|
|
4
|
+
* (engine campaign · flywheel promotion · coherence verdict) chains to the same
|
|
5
|
+
* externally-verifiable key (`QE_WITNESS_PUBLIC_KEYS_JSON` allowlist, fingerprint
|
|
6
|
+
* `f1ac28607da49ec1`).
|
|
7
|
+
*
|
|
8
|
+
* `createSigner` already accepts a 32-byte Ed25519 seed → deterministic keypair.
|
|
9
|
+
* The platform key is delivered as `QE_WITNESS_SIGNING_KEY` — a JSON
|
|
10
|
+
* `{ publicKey, privateKey }` of PEM strings (same shape qe-harness Stage-B reads
|
|
11
|
+
* from Secret Manager). We derive the seed from that private key and hand it to
|
|
12
|
+
* `createSigner`, reproducing the exact platform keypair.
|
|
13
|
+
*
|
|
14
|
+
* Graceful: returns null when the env var is absent/malformed, so the flywheel
|
|
15
|
+
* keeps its self-generated-key behaviour where the platform key isn't provided.
|
|
16
|
+
* Env-reading lives HERE, not in the dependency-free `receipt.ts` core.
|
|
17
|
+
*/
|
|
18
|
+
import { createPrivateKey } from 'node:crypto';
|
|
19
|
+
import { createSigner } from './receipt.js';
|
|
20
|
+
/** DER prefix of an Ed25519 PKCS#8 private key (16 bytes) preceding the 32-byte seed. */
|
|
21
|
+
const ED25519_PKCS8_PREFIX = '302e020100300506032b657004220420';
|
|
22
|
+
/**
|
|
23
|
+
* Extract the raw 32-byte Ed25519 seed from a PKCS#8 private-key PEM. Throws if the
|
|
24
|
+
* key is not an Ed25519 PKCS#8 key (wrong curve / format).
|
|
25
|
+
*/
|
|
26
|
+
export function seedFromPkcs8Pem(privateKeyPem) {
|
|
27
|
+
const der = createPrivateKey(privateKeyPem).export({ format: 'der', type: 'pkcs8' });
|
|
28
|
+
if (der.length !== 48 || der.subarray(0, 16).toString('hex') !== ED25519_PKCS8_PREFIX) {
|
|
29
|
+
throw new Error('not an Ed25519 PKCS#8 private key (cannot derive a 32-byte seed)');
|
|
30
|
+
}
|
|
31
|
+
return Buffer.from(der.subarray(16, 48));
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Build a {@link Signer} bound to the Cognitum platform identity from
|
|
35
|
+
* `QE_WITNESS_SIGNING_KEY`, or null when it is unset/malformed (graceful fallback).
|
|
36
|
+
* The returned signer's `keyId` equals the platform witness fingerprint, so a
|
|
37
|
+
* verifier can attribute the receipt to the platform via the same allowlist that
|
|
38
|
+
* accepts qe-harness evidence bundles.
|
|
39
|
+
*/
|
|
40
|
+
export function platformSigner(env = process.env) {
|
|
41
|
+
const raw = env.QE_WITNESS_SIGNING_KEY;
|
|
42
|
+
if (!raw)
|
|
43
|
+
return null;
|
|
44
|
+
let key;
|
|
45
|
+
try {
|
|
46
|
+
key = JSON.parse(raw);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
if (!key.privateKey)
|
|
52
|
+
return null;
|
|
53
|
+
try {
|
|
54
|
+
return createSigner(seedFromPkcs8Pem(key.privateKey));
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return null; // wrong key type / unparseable — fall back to a self-generated signer
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=platform-signer.js.map
|
|
@@ -10,9 +10,16 @@
|
|
|
10
10
|
* Ed25519 via Node's built-in crypto — dependency-free (ADR-118 §6).
|
|
11
11
|
*/
|
|
12
12
|
import { generateKeyPairSync, createPrivateKey, createPublicKey, sign as edSign, verify as edVerify, createHash, } from 'node:crypto';
|
|
13
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* Derive a stable key id from a public key PEM. The PEM is trimmed first so the id
|
|
15
|
+
* is invariant to trailing whitespace (PEM exports carry a trailing newline) AND
|
|
16
|
+
* matches the Cognitum platform witness fingerprint scheme — `sha256(pem.trim())`
|
|
17
|
+
* truncated to 16 hex (qe-harness `witness.ts` / meta-llm `qe-witness.ts`). This lets
|
|
18
|
+
* a flywheel receipt signed with the platform key carry the SAME id the platform
|
|
19
|
+
* allowlist (`QE_WITNESS_PUBLIC_KEYS_JSON`) recognizes. See platform-signer.ts.
|
|
20
|
+
*/
|
|
14
21
|
function keyIdOf(publicKeyPem) {
|
|
15
|
-
return createHash('sha256').update(publicKeyPem).digest('hex').slice(0, 16);
|
|
22
|
+
return createHash('sha256').update(publicKeyPem.trim()).digest('hex').slice(0, 16);
|
|
16
23
|
}
|
|
17
24
|
/**
|
|
18
25
|
* Create an Ed25519 signer. With a 32-byte seed (hex or Buffer) the keypair is
|