agentic-qe 3.9.5 → 3.9.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (290) hide show
  1. package/.claude/skills/skills-manifest.json +1 -1
  2. package/CHANGELOG.md +56 -0
  3. package/dist/cli/bundle.js +5 -5
  4. package/dist/cli/chunks/adapter-GE3RSG32.js +2 -0
  5. package/dist/cli/chunks/{agent-booster-wasm-AW36VJXL.js → agent-booster-wasm-MXTWTD4D.js} +2 -2
  6. package/dist/cli/chunks/{agent-handler-AQFW2CMW.js → agent-handler-6NEP2BOA.js} +2 -2
  7. package/dist/cli/chunks/{agent-memory-branch-VA6A47U5.js → agent-memory-branch-SAPEIGE2.js} +2 -2
  8. package/dist/cli/chunks/aqe-learning-engine-IYL6TK6E.js +2 -0
  9. package/dist/cli/chunks/{audit-WVJHTVUU.js → audit-53LCI6R3.js} +2 -2
  10. package/dist/cli/chunks/base-L3G3GEZY.js +2 -0
  11. package/dist/cli/chunks/{better-sqlite3-HCMGVEDO.js → better-sqlite3-UZSKFGCK.js} +2 -2
  12. package/dist/cli/chunks/{brain-handler-JZISBH2W.js → brain-handler-67NDDXVO.js} +3 -3
  13. package/dist/cli/chunks/{branch-enumerator-3TQXIETD.js → branch-enumerator-IUIGYEK5.js} +2 -2
  14. package/dist/cli/chunks/{browser-4GZXU4YT.js → browser-UFUF65LQ.js} +2 -2
  15. package/dist/cli/chunks/browser-workflow-7KTCY5FI.js +2 -0
  16. package/dist/cli/chunks/{chunk-QPW2O5TR.js → chunk-2SJQ3CYN.js} +9 -9
  17. package/dist/cli/chunks/{chunk-WTGUS7DD.js → chunk-2TRWUJWG.js} +2 -2
  18. package/dist/cli/chunks/{chunk-3VNEMHOO.js → chunk-3DXO5CWI.js} +1 -1
  19. package/dist/cli/chunks/{chunk-QHMDETCU.js → chunk-3KX7CQEM.js} +1 -1
  20. package/dist/cli/chunks/{chunk-LPVQ6QCW.js → chunk-426OO3RH.js} +2 -2
  21. package/dist/cli/chunks/{chunk-NNNH36RU.js → chunk-4B5IYFKE.js} +2 -2
  22. package/dist/cli/chunks/{chunk-GFZRXQWH.js → chunk-4NHE7AJE.js} +1 -1
  23. package/dist/cli/chunks/{chunk-KWIDDPKG.js → chunk-52MUZGZF.js} +2 -2
  24. package/dist/cli/chunks/{chunk-73LG5ELL.js → chunk-5EOM3W6Q.js} +2 -2
  25. package/dist/cli/chunks/{chunk-N66G743A.js → chunk-6MMRZYYS.js} +3 -3
  26. package/dist/cli/chunks/{chunk-OQCEI7Q4.js → chunk-6OKXGDT3.js} +2 -2
  27. package/dist/cli/chunks/{chunk-YGZBS4RW.js → chunk-6ULPQTIE.js} +2 -2
  28. package/dist/cli/chunks/{chunk-DPEX4UOC.js → chunk-7GPYOMVY.js} +1 -1
  29. package/dist/cli/chunks/{chunk-YHSIUFFY.js → chunk-7OPVTN5W.js} +2 -2
  30. package/dist/cli/chunks/{chunk-4FPCCKNQ.js → chunk-7TKZ6LK6.js} +1 -1
  31. package/dist/cli/chunks/{chunk-TRRJP27A.js → chunk-A5VULTCD.js} +1 -1
  32. package/dist/cli/chunks/{chunk-E55RROAP.js → chunk-AHB2F42G.js} +1 -1
  33. package/dist/cli/chunks/{chunk-3KYKE7B6.js → chunk-APPVAGD5.js} +1 -1
  34. package/dist/cli/chunks/{chunk-7JQOOPA2.js → chunk-AT6LBLUV.js} +2 -2
  35. package/dist/cli/chunks/{chunk-ERV3OVUG.js → chunk-BJKRAFS2.js} +2 -2
  36. package/dist/cli/chunks/{chunk-OPOTKH42.js → chunk-BPYWDM2Y.js} +3 -3
  37. package/dist/cli/chunks/{chunk-BM7VSJTE.js → chunk-BTZEKSWH.js} +2 -2
  38. package/dist/cli/chunks/{chunk-4EOSDCDM.js → chunk-BWNH22V2.js} +1 -1
  39. package/dist/cli/chunks/{chunk-ITIYGUIL.js → chunk-CDFYF33M.js} +2 -2
  40. package/dist/cli/chunks/{chunk-NDWWN2YC.js → chunk-D2C4XNF5.js} +4 -4
  41. package/dist/cli/chunks/{chunk-NGP3DRFU.js → chunk-D3KORDD5.js} +1 -1
  42. package/dist/cli/chunks/{chunk-YZ3WB4TN.js → chunk-DKBXIBRS.js} +2 -2
  43. package/dist/cli/chunks/{chunk-WV7K5A7J.js → chunk-DL46KSFX.js} +2 -2
  44. package/dist/cli/chunks/{chunk-HA4COQ66.js → chunk-DS3XAGGL.js} +2 -2
  45. package/dist/cli/chunks/{chunk-I4HGIQC2.js → chunk-ECRYU5XG.js} +2 -2
  46. package/dist/cli/chunks/{chunk-KCQ2GFRN.js → chunk-EFHR7LML.js} +2 -2
  47. package/dist/cli/chunks/{chunk-3UFAEGSS.js → chunk-EIGXGMOR.js} +1 -1
  48. package/dist/cli/chunks/{chunk-GSTDQLXR.js → chunk-EL2WLSUI.js} +2 -2
  49. package/dist/cli/chunks/{chunk-OTOQXMP6.js → chunk-FBVEHGNE.js} +3 -3
  50. package/dist/cli/chunks/{chunk-53J3R7PZ.js → chunk-FHBIJBZ3.js} +2 -2
  51. package/dist/cli/chunks/{chunk-DSOEKRQL.js → chunk-FJEIX3IS.js} +2 -2
  52. package/dist/cli/chunks/{chunk-Y6XYH7EV.js → chunk-FKJ4XZ6E.js} +2 -2
  53. package/dist/cli/chunks/{chunk-35DP6LX6.js → chunk-FOCGOVIM.js} +2 -2
  54. package/dist/cli/chunks/{chunk-3QH67ZYC.js → chunk-GGPGY5QT.js} +2 -2
  55. package/dist/cli/chunks/{chunk-3UE5GART.js → chunk-GOG6L2F7.js} +2 -2
  56. package/dist/cli/chunks/chunk-HE5VY2BI.js +2 -0
  57. package/dist/cli/chunks/{chunk-55EAFHVH.js → chunk-HEENVPYF.js} +3 -3
  58. package/dist/cli/chunks/{chunk-45WEXMKC.js → chunk-HFPT7QXQ.js} +2 -2
  59. package/dist/cli/chunks/{chunk-6FM5DJHR.js → chunk-HVJXXGB4.js} +4 -4
  60. package/dist/cli/chunks/{chunk-FDFJHGRZ.js → chunk-HWDE4RB3.js} +2 -2
  61. package/dist/cli/chunks/{chunk-5NBYV7FL.js → chunk-INJPS7RF.js} +1 -1
  62. package/dist/cli/chunks/{chunk-GFXAKQ77.js → chunk-IQLFWO5U.js} +2 -2
  63. package/dist/cli/chunks/{chunk-3DGO7NJK.js → chunk-JJSJSQNJ.js} +1 -1
  64. package/dist/cli/chunks/{chunk-PTAUZ3XL.js → chunk-JNEG6DKU.js} +1 -1
  65. package/dist/cli/chunks/{chunk-HT5EZYPZ.js → chunk-JRHKFRUB.js} +2 -2
  66. package/dist/cli/chunks/{chunk-UPFCV7MX.js → chunk-JZYCZMHN.js} +2 -2
  67. package/dist/cli/chunks/{chunk-UO2R7ZN3.js → chunk-KHEAWN23.js} +2 -2
  68. package/dist/cli/chunks/{chunk-6VB4VZCR.js → chunk-KHH5UJXY.js} +2 -2
  69. package/dist/cli/chunks/{chunk-BYD54ZUF.js → chunk-KLLHSXIC.js} +2 -2
  70. package/dist/cli/chunks/{chunk-6QKGLIIY.js → chunk-KO5HO6MY.js} +2 -2
  71. package/dist/cli/chunks/{chunk-ZFCRDCHW.js → chunk-KZSZHP32.js} +2 -2
  72. package/dist/cli/chunks/{chunk-MRTDOSHR.js → chunk-LHGZRKPO.js} +2 -2
  73. package/dist/cli/chunks/{chunk-YQTPEQO6.js → chunk-LP6EQI2P.js} +2 -2
  74. package/dist/cli/chunks/{chunk-6QR7GSNJ.js → chunk-LPLCT2HH.js} +2 -2
  75. package/dist/cli/chunks/{chunk-WIZOYPFT.js → chunk-LZ34CKYE.js} +2 -2
  76. package/dist/cli/chunks/{chunk-MYIDAWGQ.js → chunk-MR7V7QVL.js} +2 -2
  77. package/dist/cli/chunks/{chunk-ZWS7J73Q.js → chunk-MUEFXLGX.js} +1 -1
  78. package/dist/cli/chunks/chunk-N5SLJOBK.js +2 -0
  79. package/dist/cli/chunks/{chunk-T4KMG3GJ.js → chunk-NJ5IC6ZR.js} +1 -1
  80. package/dist/cli/chunks/{chunk-TRPCOY3C.js → chunk-NKX2Z546.js} +1 -1
  81. package/dist/cli/chunks/{chunk-YHKJYBWK.js → chunk-OURDPRGM.js} +1 -1
  82. package/dist/cli/chunks/{chunk-ZP237D7K.js → chunk-PFTR6XAO.js} +2 -2
  83. package/dist/cli/chunks/{chunk-ZD2FS4Q7.js → chunk-PHBE2VBN.js} +2 -2
  84. package/dist/cli/chunks/{chunk-ZJWDWM6B.js → chunk-PMZJ54WX.js} +3 -3
  85. package/dist/cli/chunks/{chunk-MBXSHGDD.js → chunk-QI5VGEKC.js} +2 -2
  86. package/dist/cli/chunks/{chunk-TSA5MUTQ.js → chunk-QKJ4LUAM.js} +2 -2
  87. package/dist/cli/chunks/{chunk-REXMKRR2.js → chunk-RGJ4RMUR.js} +8 -8
  88. package/dist/cli/chunks/{chunk-CGYTM7AB.js → chunk-SIIYQLKH.js} +2 -2
  89. package/dist/cli/chunks/{chunk-TRO45ZLC.js → chunk-SMKRBNO7.js} +1 -1
  90. package/dist/cli/chunks/{chunk-MO3IIM7L.js → chunk-SP3X35XC.js} +1 -1
  91. package/dist/cli/chunks/{chunk-KQ7VBUO4.js → chunk-SQQ57TSJ.js} +2 -2
  92. package/dist/cli/chunks/{chunk-TUMXWCB7.js → chunk-SQZ3H6WR.js} +3 -3
  93. package/dist/cli/chunks/{chunk-ALX5RJSR.js → chunk-STASZVMY.js} +2 -2
  94. package/dist/cli/chunks/{chunk-CGYOMD6X.js → chunk-SURZYSSL.js} +1 -1
  95. package/dist/cli/chunks/{chunk-74YG34UH.js → chunk-T7R5NXJW.js} +2 -2
  96. package/dist/cli/chunks/{chunk-YDBMYTOV.js → chunk-TD2WOW75.js} +2 -2
  97. package/dist/cli/chunks/{chunk-XG2JAIQT.js → chunk-TLTRL32T.js} +1 -1
  98. package/dist/cli/chunks/{chunk-KUDPFLL4.js → chunk-TT2YXNHH.js} +4 -4
  99. package/dist/cli/chunks/{chunk-IMCYFQWF.js → chunk-UDBSEFUT.js} +2 -2
  100. package/dist/cli/chunks/{chunk-GHFXURNS.js → chunk-UEFAPTBV.js} +1 -1
  101. package/dist/cli/chunks/{chunk-PGFHFPDP.js → chunk-URBXUDY3.js} +2 -2
  102. package/dist/cli/chunks/{chunk-EPH2GZQM.js → chunk-UXCEJ3AV.js} +2 -2
  103. package/dist/cli/chunks/{chunk-PVLOT5BL.js → chunk-VAKJOTGU.js} +2 -2
  104. package/dist/cli/chunks/{chunk-VKT4STAE.js → chunk-VMWLVRJO.js} +2 -2
  105. package/dist/cli/chunks/{chunk-S4F3CNSP.js → chunk-W4HUWBPK.js} +2 -2
  106. package/dist/cli/chunks/{chunk-IHXDXFUX.js → chunk-W4Y4GFRB.js} +1 -1
  107. package/dist/cli/chunks/{chunk-J4SEGMXL.js → chunk-WAP7ROO5.js} +2 -2
  108. package/dist/cli/chunks/{chunk-CNGRXBKO.js → chunk-WLYSZV5U.js} +2 -2
  109. package/dist/cli/chunks/{chunk-CQT3IEEX.js → chunk-WS4OVAWU.js} +2 -2
  110. package/dist/cli/chunks/{chunk-2XJRSIM5.js → chunk-WV3R5JFE.js} +2 -2
  111. package/dist/cli/chunks/{chunk-673PL3DG.js → chunk-XB2GVTY6.js} +1 -1
  112. package/dist/cli/chunks/{chunk-IMGRYCAT.js → chunk-XD4UFF2Y.js} +1 -1
  113. package/dist/cli/chunks/{chunk-BQUN2NB4.js → chunk-XOHRM3M7.js} +3 -3
  114. package/dist/cli/chunks/{chunk-G7XBTBM7.js → chunk-XY5FMZRA.js} +2 -2
  115. package/dist/cli/chunks/{chunk-NHIQ5HP3.js → chunk-YHZWNT45.js} +2 -2
  116. package/dist/cli/chunks/{chunk-W73AYMDP.js → chunk-YIVZ5Z4V.js} +1 -1
  117. package/dist/cli/chunks/{chunk-4QGNSNQL.js → chunk-YR5ZNQT2.js} +2 -2
  118. package/dist/cli/chunks/{chunk-X6J7VYVD.js → chunk-YTF5G3RQ.js} +2 -2
  119. package/dist/cli/chunks/{chunk-JUBICWL2.js → chunk-YV2PVXJE.js} +1 -1
  120. package/dist/cli/chunks/{chunk-6AMXWB6Y.js → chunk-ZEFDSMF4.js} +2 -2
  121. package/dist/cli/chunks/{chunk-JYJXVTUP.js → chunk-ZETZATNY.js} +2 -2
  122. package/dist/cli/chunks/{chunk-LLXBL36X.js → chunk-ZLQYGO6N.js} +1 -1
  123. package/dist/cli/chunks/{chunk-DFOANC7Z.js → chunk-ZSXSUUBS.js} +1 -1
  124. package/dist/cli/chunks/{chunk-BNYHBEDE.js → chunk-ZV7FGZNJ.js} +2 -2
  125. package/dist/cli/chunks/{chunk-I27OTSC7.js → chunk-ZWAJV4SN.js} +2 -2
  126. package/dist/cli/chunks/{ci-3ATT6NMC.js → ci-F4F3SDHP.js} +2 -2
  127. package/dist/cli/chunks/{ci-output-2JR3J753.js → ci-output-4SUMOQGO.js} +2 -2
  128. package/dist/cli/chunks/{claude-flow-setup-SG2BSEED.js → claude-flow-setup-NKXPDFMJ.js} +2 -2
  129. package/dist/cli/chunks/client-3DPPDO2H.js +2 -0
  130. package/dist/cli/chunks/{cline-installer-A26SXDX6.js → cline-installer-3FMNXEKM.js} +2 -2
  131. package/dist/cli/chunks/{code-WIXKPGAQ.js → code-5QEDZNKI.js} +2 -2
  132. package/dist/cli/chunks/{code-index-extractor-W2NO6MR3.js → code-index-extractor-RD5EAOLE.js} +2 -2
  133. package/dist/cli/chunks/{codex-installer-VBSJHXI4.js → codex-installer-UU4O2FIE.js} +2 -2
  134. package/dist/cli/chunks/{completions-JFXIUS2V.js → completions-CS6RJLYZ.js} +2 -2
  135. package/dist/cli/chunks/{complexity-analyzer-GPO4ZAIZ.js → complexity-analyzer-U4DE2QTP.js} +2 -2
  136. package/dist/cli/chunks/{continuedev-installer-OULSFVLB.js → continuedev-installer-E55EG2TB.js} +2 -2
  137. package/dist/cli/chunks/{copilot-installer-QS7EG5DW.js → copilot-installer-TVJUX3AZ.js} +2 -2
  138. package/dist/cli/chunks/{cost-tracker-D7LNB633.js → cost-tracker-IAKDLDJH.js} +2 -2
  139. package/dist/cli/chunks/{coverage-YUQ4MQYK.js → coverage-LX7UIEKV.js} +3 -3
  140. package/dist/cli/chunks/cross-domain-router-JOYTUBFT.js +2 -0
  141. package/dist/cli/chunks/{cursor-installer-UOZGHZHD.js → cursor-installer-2NJ7MK23.js} +2 -2
  142. package/dist/cli/chunks/{daemon-27TMWDPY.js → daemon-T4CPOFHM.js} +3 -3
  143. package/dist/cli/chunks/{dag-attention-scheduler-PVAFQBDL.js → dag-attention-scheduler-GAPYYUHZ.js} +2 -2
  144. package/dist/cli/chunks/{detect-FUKMZ37Y.js → detect-RU5LBCCI.js} +2 -2
  145. package/dist/cli/chunks/{domain-handler-SP3QB5VN.js → domain-handler-LKPDVPF6.js} +2 -2
  146. package/dist/cli/chunks/{domain-transfer-A2WL6HEJ.js → domain-transfer-Q76ITWBK.js} +2 -2
  147. package/dist/cli/chunks/dream-IF2HCRW4.js +2 -0
  148. package/dist/cli/chunks/esm-node-LNRP5BNU.js +2 -0
  149. package/dist/cli/chunks/{eval-6MIZUXEO.js → eval-TFFIZGTW.js} +2 -2
  150. package/dist/cli/chunks/{fast-paths-XT542LOU.js → fast-paths-V6KA3VWH.js} +2 -2
  151. package/dist/cli/chunks/{feature-flags-WBF5B6WE.js → feature-flags-DWS4XL2P.js} +2 -2
  152. package/dist/cli/chunks/{feature-flags-NWACCWCB.js → feature-flags-MYSY53UU.js} +2 -2
  153. package/dist/cli/chunks/{file-discovery-GKCJFWTD.js → file-discovery-AMKZRFLT.js} +2 -2
  154. package/dist/cli/chunks/{fleet-V2MKGNMG.js → fleet-B2BJFKEV.js} +3 -3
  155. package/dist/cli/chunks/{gnn-wrapper-HUUMTTSV.js → gnn-wrapper-SOJHQ7VC.js} +2 -2
  156. package/dist/cli/chunks/{heartbeat-handler-UY3TCEN7.js → heartbeat-handler-O7FF6NRE.js} +4 -4
  157. package/dist/cli/chunks/{heartbeat-scheduler-YWXPSCH2.js → heartbeat-scheduler-WOGW5R7J.js} +2 -2
  158. package/dist/cli/chunks/hnsw-adapter-UPX4AXOQ.js +2 -0
  159. package/dist/cli/chunks/hnsw-index-CSI2EXXR.js +2 -0
  160. package/dist/cli/chunks/{hnsw-legacy-bridge-IYYYSRK5.js → hnsw-legacy-bridge-CC5YS47X.js} +2 -2
  161. package/dist/cli/chunks/{hnswlib-node-WDWAE74R.js → hnswlib-node-FTWYRETS.js} +2 -2
  162. package/dist/cli/chunks/{hooks-DTBJK6LL.js → hooks-ETOFFBMV.js} +6 -6
  163. package/dist/cli/chunks/{hypergraph-engine-K47IBQNO.js → hypergraph-engine-FGAHFWFO.js} +2 -2
  164. package/dist/cli/chunks/{hypergraph-handler-2NDPG2N4.js → hypergraph-handler-GNWJD7E3.js} +3 -3
  165. package/dist/cli/chunks/impact-analyzer-2YVBHMES.js +2 -0
  166. package/dist/cli/chunks/init-handler-BEYOLKQO.js +69 -0
  167. package/dist/cli/chunks/init-wizard-V6GZQMMR.js +2 -0
  168. package/dist/cli/chunks/kernel-EHJ4SP2Y.js +2 -0
  169. package/dist/cli/chunks/{kilocode-installer-XZAHWQEA.js → kilocode-installer-ED6LYSEM.js} +2 -2
  170. package/dist/cli/chunks/{kiro-installer-53C7DXEF.js → kiro-installer-NG77T5YR.js} +2 -2
  171. package/dist/cli/chunks/knowledge-graph-ZYXBWGKL.js +2 -0
  172. package/dist/cli/chunks/{learning-XYW2EEVX.js → learning-P3WY3LTI.js} +3 -3
  173. package/dist/cli/chunks/{llm-router-64SKMJ7B.js → llm-router-ETSFMOWS.js} +2 -2
  174. package/dist/cli/chunks/{load-HVL4O7EY.js → load-PP3GVQT7.js} +2 -2
  175. package/dist/cli/chunks/load-test-VDZEYGKV.js +2 -0
  176. package/dist/cli/chunks/{mcp-4H2NJ3EO.js → mcp-B2VX7EKL.js} +2 -2
  177. package/dist/cli/chunks/{memory-2CD4BAJK.js → memory-SBZQ6MZ4.js} +5 -5
  178. package/dist/cli/chunks/memory-backend-IB3BU4VM.js +2 -0
  179. package/dist/cli/chunks/{memory-handlers-XRYZBE5I.js → memory-handlers-5RMGG2CR.js} +2 -2
  180. package/dist/cli/chunks/{opencode-installer-I23QAZC6.js → opencode-installer-PIDIFO2L.js} +2 -2
  181. package/dist/cli/chunks/orchestrator-FSGUODZI.js +373 -0
  182. package/dist/cli/chunks/{pipeline-7UN7LP6B.js → pipeline-BQ5MWZPT.js} +2 -2
  183. package/dist/cli/chunks/{platform-P44YUHPK.js → platform-6EJK4QMD.js} +2 -2
  184. package/dist/cli/chunks/{plugin-YWYR7FKS.js → plugin-EDGOMUJY.js} +2 -2
  185. package/dist/cli/chunks/{prime-radiant-advanced-wasm-A7CDGUK6.js → prime-radiant-advanced-wasm-4S6FYKPP.js} +2 -2
  186. package/dist/cli/chunks/protocol-executor-H2ZG7JBJ.js +2 -0
  187. package/dist/cli/chunks/{protocol-handler-BM7RLC4Z.js → protocol-handler-ETM7PMQU.js} +2 -2
  188. package/dist/cli/chunks/{prove-UVBYODRV.js → prove-YUBORZAP.js} +2 -2
  189. package/dist/cli/chunks/qe-reasoning-bank-ZCSHSKZU.js +2 -0
  190. package/dist/cli/chunks/{quality-4L42LN5Q.js → quality-XPZDC5FJ.js} +2 -2
  191. package/dist/cli/chunks/queen-coordinator-NEC373VS.js +2 -0
  192. package/dist/cli/chunks/{real-embeddings-4CYZTWHT.js → real-embeddings-KTDUTUJL.js} +2 -2
  193. package/dist/cli/chunks/{roocode-installer-UOSJS7KT.js → roocode-installer-WADVKI3P.js} +2 -2
  194. package/dist/cli/chunks/router-3PP5XRTD.js +2 -0
  195. package/dist/cli/chunks/routing-feedback-JNUFV2X3.js +2 -0
  196. package/dist/cli/chunks/{routing-handler-43G4D5UP.js → routing-handler-OOPOYHEV.js} +2 -2
  197. package/dist/cli/chunks/ruvector-commands-UPEZL4OK.js +8 -0
  198. package/dist/cli/chunks/{rvf-dual-writer-USU2IWO7.js → rvf-dual-writer-TOBBCJ7K.js} +2 -2
  199. package/dist/cli/chunks/{rvf-migration-adapter-DZMYVJJY.js → rvf-migration-adapter-U7UM2U36.js} +2 -2
  200. package/dist/cli/chunks/{rvf-migration-coordinator-AZ5JDT33.js → rvf-migration-coordinator-CUX3EU2X.js} +2 -2
  201. package/dist/cli/chunks/rvf-native-adapter-PTOZXG4W.js +2 -0
  202. package/dist/cli/chunks/safe-db-CGYNYUES.js +2 -0
  203. package/dist/cli/chunks/schedule-NRN4WOHX.js +2 -0
  204. package/dist/cli/chunks/scheduler-DRAQGYLL.js +2 -0
  205. package/dist/cli/chunks/{security-RXG4H3UK.js → security-AQ4N5YKV.js} +3 -3
  206. package/dist/cli/chunks/shared-rvf-adapter-6UVVDOHK.js +2 -0
  207. package/dist/cli/chunks/{shared-rvf-dual-writer-2PUFIGX5.js → shared-rvf-dual-writer-OKRIHVSY.js} +2 -2
  208. package/dist/cli/chunks/sqlite-persistence-3WG7PBPL.js +2 -0
  209. package/dist/cli/chunks/{status-handler-SXQKG6VP.js → status-handler-HSJLJPNG.js} +2 -2
  210. package/dist/cli/chunks/{structural-health-LPXOOMG3.js → structural-health-KWZAS7ON.js} +2 -2
  211. package/dist/cli/chunks/{sync-5NX7GQQY.js → sync-6L5Z4IWH.js} +2 -2
  212. package/dist/cli/chunks/{task-handler-Y4KVNCOI.js → task-handler-KEAIPB6G.js} +2 -2
  213. package/dist/cli/chunks/{task-handlers-CG27Z3CP.js → task-handlers-BPDN6OSM.js} +2 -2
  214. package/dist/cli/chunks/{test-PWVTWOWS.js → test-PICO6RLU.js} +4 -4
  215. package/dist/cli/chunks/{test-scheduling-5S5EBVE7.js → test-scheduling-BI3R3DX5.js} +3 -3
  216. package/dist/cli/chunks/{token-bootstrap-QMPUKGQC.js → token-bootstrap-KMQC6ALU.js} +2 -2
  217. package/dist/cli/chunks/{token-usage-OZNRTJLE.js → token-usage-QGDX7MLB.js} +2 -2
  218. package/dist/cli/chunks/{transformers-DRPOBWCW.js → transformers-UNRYJSIU.js} +2 -2
  219. package/dist/cli/chunks/{tree-sitter-wasm-parser-VLX6HQW2.js → tree-sitter-wasm-parser-U22JYPOG.js} +2 -2
  220. package/dist/cli/chunks/{types-TUF6HUPE.js → types-CYXAGOY5.js} +2 -2
  221. package/dist/cli/chunks/unified-memory-EXRANFUS.js +2 -0
  222. package/dist/cli/chunks/unified-memory-hnsw-GB752D44.js +2 -0
  223. package/dist/cli/chunks/unified-persistence-V2B3YWFD.js +2 -0
  224. package/dist/cli/chunks/{validate-H7QFV2CI.js → validate-IUY5BWAV.js} +2 -2
  225. package/dist/cli/chunks/{validate-swarm-BGH6YM4S.js → validate-swarm-FXFKSEOI.js} +2 -2
  226. package/dist/cli/chunks/{vibium-DQOGR2PH.js → vibium-DKZ64NR3.js} +2 -2
  227. package/dist/cli/chunks/visual-security-YMPI7X7V.js +2 -0
  228. package/dist/cli/chunks/{web-tree-sitter-TOI4XJIL.js → web-tree-sitter-WQDTN5CV.js} +2 -2
  229. package/dist/cli/chunks/{windsurf-installer-EUMBFA42.js → windsurf-installer-O5WOBFOQ.js} +2 -2
  230. package/dist/cli/chunks/witness-chain-7LIPUVMI.js +2 -0
  231. package/dist/cli/chunks/{witness-chain-MWPUR4Q2.js → witness-chain-F7WXEVJA.js} +2 -2
  232. package/dist/cli/chunks/{workflow-V5HI3AQR.js → workflow-47524I5G.js} +4 -4
  233. package/dist/cli/chunks/workflow-orchestrator-QPIAR4LI.js +2 -0
  234. package/dist/cli/chunks/{wrappers-VOU4IVAQ.js → wrappers-MP2HWQD7.js} +2 -2
  235. package/dist/cli/commands/init.js +1 -1
  236. package/dist/cli/commands/ruvector-commands.js +5 -2
  237. package/dist/cli/handlers/init-handler.d.ts +53 -0
  238. package/dist/cli/handlers/init-handler.js +53 -3
  239. package/dist/cli/index.js +5 -4
  240. package/dist/init/phases/04-database.js +19 -0
  241. package/dist/init/phases/06-code-intelligence.d.ts +14 -9
  242. package/dist/init/phases/06-code-intelligence.js +72 -34
  243. package/dist/init/phases/10-workers.js +2 -0
  244. package/dist/init/phases/phase-interface.d.ts +16 -4
  245. package/dist/integrations/ruvector/feature-flags.d.ts +27 -5
  246. package/dist/integrations/ruvector/feature-flags.js +15 -2
  247. package/dist/kernel/hnsw-adapter.js +1 -1
  248. package/dist/kernel/native-hnsw-backend.d.ts +100 -37
  249. package/dist/kernel/native-hnsw-backend.js +207 -192
  250. package/dist/kernel/unified-memory.js +15 -10
  251. package/dist/mcp/bundle.js +189 -189
  252. package/package.json +1 -1
  253. package/dist/cli/chunks/adapter-HOBCL2VF.js +0 -2
  254. package/dist/cli/chunks/aqe-learning-engine-77FVV2ZJ.js +0 -2
  255. package/dist/cli/chunks/base-2IXMPGJV.js +0 -2
  256. package/dist/cli/chunks/browser-workflow-AQYKV2NE.js +0 -2
  257. package/dist/cli/chunks/chunk-PMFZHFCB.js +0 -2
  258. package/dist/cli/chunks/chunk-Z2GK7COI.js +0 -2
  259. package/dist/cli/chunks/client-3CA57H5P.js +0 -2
  260. package/dist/cli/chunks/cross-domain-router-GECFIALH.js +0 -2
  261. package/dist/cli/chunks/dream-CJ4MKM5G.js +0 -2
  262. package/dist/cli/chunks/esm-node-X7U3YS4M.js +0 -2
  263. package/dist/cli/chunks/hnsw-adapter-LJGOH772.js +0 -2
  264. package/dist/cli/chunks/hnsw-index-V6SST2MB.js +0 -2
  265. package/dist/cli/chunks/impact-analyzer-MTOVFD3O.js +0 -2
  266. package/dist/cli/chunks/init-handler-VRZS6KO2.js +0 -68
  267. package/dist/cli/chunks/init-wizard-IH6PSRJY.js +0 -2
  268. package/dist/cli/chunks/kernel-3MC7WV5G.js +0 -2
  269. package/dist/cli/chunks/knowledge-graph-HLUQJ2GI.js +0 -2
  270. package/dist/cli/chunks/load-test-VVVME7GZ.js +0 -2
  271. package/dist/cli/chunks/memory-backend-O3U2QDU3.js +0 -2
  272. package/dist/cli/chunks/orchestrator-7BL6R54P.js +0 -370
  273. package/dist/cli/chunks/protocol-executor-HLNTSRYC.js +0 -2
  274. package/dist/cli/chunks/qe-reasoning-bank-JK5CK4D4.js +0 -2
  275. package/dist/cli/chunks/queen-coordinator-FLF6XYLX.js +0 -2
  276. package/dist/cli/chunks/router-DUFZW3WQ.js +0 -2
  277. package/dist/cli/chunks/routing-feedback-6U76TI6X.js +0 -2
  278. package/dist/cli/chunks/ruvector-commands-H7A7LG6Q.js +0 -8
  279. package/dist/cli/chunks/rvf-native-adapter-4UD7SUMB.js +0 -2
  280. package/dist/cli/chunks/safe-db-32Q5RXHR.js +0 -2
  281. package/dist/cli/chunks/schedule-ZHCM3L6H.js +0 -2
  282. package/dist/cli/chunks/scheduler-HBSSLDOD.js +0 -2
  283. package/dist/cli/chunks/shared-rvf-adapter-PLZVKKW7.js +0 -2
  284. package/dist/cli/chunks/sqlite-persistence-YUZMB44Y.js +0 -2
  285. package/dist/cli/chunks/unified-memory-3D4VDY4G.js +0 -2
  286. package/dist/cli/chunks/unified-memory-hnsw-AAQ5IA6M.js +0 -2
  287. package/dist/cli/chunks/unified-persistence-PY7MVJTL.js +0 -2
  288. package/dist/cli/chunks/visual-security-ZBNB7LEG.js +0 -2
  289. package/dist/cli/chunks/witness-chain-CS76OJFL.js +0 -2
  290. package/dist/cli/chunks/workflow-orchestrator-FS4HGYI7.js +0 -2
@@ -1,28 +1,55 @@
1
1
  /**
2
- * Native HNSW Backend via @ruvector/router VectorDb
2
+ * Native HNSW Backend via hnswlib-node
3
3
  *
4
- * Provides a high-performance HNSW index backed by the Rust-based
5
- * @ruvector/router library. This backend implements the same
6
- * IHnswIndexProvider interface as ProgressiveHnswBackend but delegates
7
- * vector storage and search to native code for lower latency and
8
- * higher throughput.
4
+ * Provides a high-performance HNSW index backed by hnswlib-node, the
5
+ * canonical Node.js binding for the C++ Hnswlib reference implementation
6
+ * (Yury Malkov's HNSW library, the same code Pinecone, Weaviate, Qdrant
7
+ * and chromadb-default-embed are built on top of).
9
8
  *
10
- * When @ruvector/router is unavailable (e.g., unsupported platform,
11
- * missing binary), construction throws NativeHnswUnavailableError so the
12
- * caller (HnswAdapter factory) can fall back to the JS backend.
9
+ * This backend implements the same IHnswIndexProvider interface as
10
+ * ProgressiveHnswBackend but delegates vector storage and search to
11
+ * native code for sublinear search latency on large indexes.
13
12
  *
14
- * @see ADR-081: Native HNSW NAPI Integration
13
+ * History issue #399 (April 2026):
14
+ * This backend previously wrapped @ruvector/router's VectorDb. Empirical
15
+ * verification (scripts/diagnose-issue-399*.mjs) found four serious bugs
16
+ * in @ruvector/router 0.1.28:
17
+ *
18
+ * 1. HNSW search returned essentially random results — recall@10 ≈ 0%
19
+ * on textbook unit-Gaussian random vectors at default M/efC/efS,
20
+ * could not find self-vectors. Pumping efSearch to N≈index-size
21
+ * restored correctness but defeated HNSW's purpose.
22
+ * 2. The VectorDb constructor unconditionally created a `vectors.db`
23
+ * redb file in the current working directory (NOT in .agentic-qe/),
24
+ * violating the unified memory architecture and polluting users'
25
+ * project roots with multi-MB persistence files they never asked for.
26
+ * 3. The redb file held a process-wide exclusive lock — only ONE
27
+ * VectorDb instance could exist per process. Subsequent constructors
28
+ * threw "Database already open. Cannot acquire lock."
29
+ * 4. NAPI dispose did not synchronously release the redb lock, so the
30
+ * lock outlived our dispose() call and caused the v3.9.5 futex
31
+ * deadlock when the indexer tried to recreate after reset.
32
+ *
33
+ * Comparison test on 1000 vector self-query (linux-arm64, M=16, efC=200,
34
+ * efS=100, cosine):
35
+ * - @ruvector/router 0.1.28: recall@10 = 10%, top-1 = wrong vector
36
+ * - hnswlib-node 3.0.0: recall@10 = 100%, top-1 = id 42 ✓
37
+ *
38
+ * The migration to hnswlib-node fixes all four bugs in one swap.
39
+ *
40
+ * @see ADR-090: hnswlib-node migration
41
+ * @see https://github.com/proffesor-for-testing/agentic-qe/issues/399
15
42
  * @module kernel/native-hnsw-backend
16
43
  */
17
44
  import { createRequire } from 'module';
18
45
  import { DEFAULT_HNSW_CONFIG } from './hnsw-index-provider.js';
19
- // Use createRequire for @ruvector/router (native CJS/NAPI module)
46
+ // hnswlib-node is a native CommonJS module distributed via node-gyp
20
47
  const esmRequire = createRequire(import.meta.url);
21
48
  // ============================================================================
22
49
  // Error Types
23
50
  // ============================================================================
24
51
  /**
25
- * Thrown when @ruvector/router native binary is not available.
52
+ * Thrown when hnswlib-node native binary is not available.
26
53
  * The HnswAdapter factory catches this to fall back to the JS backend.
27
54
  */
28
55
  export class NativeHnswUnavailableError extends Error {
@@ -38,7 +65,7 @@ let nativeModule = null;
38
65
  let nativeLoadAttempted = false;
39
66
  let nativeLoadError = null;
40
67
  /**
41
- * Attempt to load the @ruvector/router native module.
68
+ * Attempt to load the hnswlib-node native module.
42
69
  * Caches the result so subsequent calls are instant.
43
70
  */
44
71
  function loadNativeModule() {
@@ -49,11 +76,10 @@ function loadNativeModule() {
49
76
  }
50
77
  nativeLoadAttempted = true;
51
78
  try {
52
- // Use createRequire for the optional native NAPI dependency
53
- const mod = esmRequire('@ruvector/router');
54
- // Verify the module has the expected API
55
- if (!mod.VectorDb || !mod.DistanceMetric) {
56
- throw new Error('@ruvector/router module missing VectorDb or DistanceMetric exports');
79
+ // hnswlib-node ships a CommonJS default export with HierarchicalNSW on it
80
+ const mod = esmRequire('hnswlib-node');
81
+ if (!mod.HierarchicalNSW) {
82
+ throw new Error('hnswlib-node module missing HierarchicalNSW export');
57
83
  }
58
84
  nativeModule = mod;
59
85
  return nativeModule;
@@ -88,22 +114,6 @@ export function isNativeModuleAvailable() {
88
114
  // ============================================================================
89
115
  // Vector Math Helpers
90
116
  // ============================================================================
91
- function computeNorm(v) {
92
- let sum = 0;
93
- for (let i = 0; i < v.length; i++)
94
- sum += v[i] * v[i];
95
- return Math.sqrt(sum);
96
- }
97
- function fastCosineSimilarity(a, b, normA, normB) {
98
- const denom = normA * normB;
99
- if (denom === 0)
100
- return 0;
101
- let dot = 0;
102
- const len = Math.min(a.length, b.length);
103
- for (let i = 0; i < len; i++)
104
- dot += a[i] * b[i];
105
- return dot / denom;
106
- }
107
117
  /**
108
118
  * Resize a vector to the target dimensions.
109
119
  * Shrink: average adjacent values. Grow: zero-pad.
@@ -131,29 +141,47 @@ function resizeVector(vector, targetDim) {
131
141
  }
132
142
  return result;
133
143
  }
144
+ /**
145
+ * Convert a Float32Array to a plain number[] (required by hnswlib-node API).
146
+ */
147
+ function toNumberArray(v) {
148
+ const out = new Array(v.length);
149
+ for (let i = 0; i < v.length; i++)
150
+ out[i] = v[i];
151
+ return out;
152
+ }
134
153
  // ============================================================================
135
154
  // NativeHnswBackend
136
155
  // ============================================================================
137
156
  /**
138
- * Native HNSW backend using @ruvector/router VectorDb.
157
+ * Initial maxElements capacity for a new HierarchicalNSW index. The index
158
+ * will be doubled in place via resizeIndex() each time it fills up, so this
159
+ * value only controls the initial allocation cost. Tuned for AQE's typical
160
+ * code-intelligence index size (~2.5k vectors today, expected to grow).
161
+ */
162
+ const INITIAL_MAX_ELEMENTS = 10_000;
163
+ /**
164
+ * Native HNSW backend using hnswlib-node HierarchicalNSW.
139
165
  *
140
166
  * Provides the same IHnswIndexProvider interface as ProgressiveHnswBackend
141
- * but delegates all vector operations to a Rust-based HNSW implementation
142
- * for improved performance.
167
+ * but delegates all vector operations to the C++ Hnswlib reference
168
+ * implementation for sublinear search latency at scale.
143
169
  *
144
- * Note: @ruvector/router VectorDb uses string IDs while IHnswIndexProvider
145
- * uses numeric IDs. Conversion is done via String(id) and Number(id).
146
- * VectorDb search returns distance scores (lower = closer) which are
147
- * converted to similarity scores (higher = closer) for consistency.
170
+ * Key differences from the previous @ruvector/router-backed implementation:
171
+ * - No local vectorStore mirror hnswlib-node returns correct distances
172
+ * directly, so re-scoring is unnecessary.
173
+ * - No process-wide singleton lock multiple instances coexist.
174
+ * - No vectors.db pollution — persistence is opt-in via writeIndex().
175
+ * - resizeIndex() doubling on overflow — grows past initial maxElements.
148
176
  */
149
177
  export class NativeHnswBackend {
150
178
  config;
151
- nativeDb = null;
179
+ nativeIndex = null;
180
+ currentMaxElements = INITIAL_MAX_ELEMENTS;
181
+ /** Tracks live ids so size() and remove() can correctly distinguish soft-deleted slots. */
182
+ liveIds = new Set();
183
+ /** Optional metadata mirror — only stored when callers attach metadata. */
152
184
  metadataStore = new Map();
153
- vectorStore = new Map();
154
- normStore = new Map();
155
- operationLock = Promise.resolve();
156
- highFallbackWarningEmitted = false;
157
185
  _metrics = {
158
186
  totalSearches: 0,
159
187
  totalAdds: 0,
@@ -171,148 +199,161 @@ export class NativeHnswBackend {
171
199
  * Create a NativeHnswBackend.
172
200
  *
173
201
  * @param config - HNSW configuration overrides
174
- * @throws {NativeHnswUnavailableError} If @ruvector/router is not available
202
+ * @throws {NativeHnswUnavailableError} If hnswlib-node is not available
175
203
  */
176
204
  constructor(config) {
177
205
  this.config = { ...DEFAULT_HNSW_CONFIG, ...config };
178
- // Attempt to load native module and create VectorDb immediately.
179
- // If the native module is unavailable or the database can't be opened,
180
- // this throws NativeHnswUnavailableError so the factory can fall back
181
- // to ProgressiveHnswBackend.
206
+ this.nativeIndex = this.createFreshIndex();
207
+ }
208
+ /**
209
+ * Build a fresh HierarchicalNSW with the configured parameters.
210
+ *
211
+ * Used both at construction time and on `clear()` to guarantee a clean
212
+ * graph. hnswlib-node's `markDelete` is a soft tombstone — it leaves the
213
+ * graph node in place and only hides it from search. Across many cycles
214
+ * of `clear() → re-add` (which happens during long test runs that share
215
+ * the singleton HnswAdapter registry), the tombstoned slots can interact
216
+ * pathologically with `addPoint(label, replaceDeleted=true)` and produce
217
+ * duplicate-label results from `searchKnn`. Recreating the underlying
218
+ * index on `clear()` is the only way to guarantee O(1) clean state
219
+ * regardless of how the wrapper is used over time.
220
+ */
221
+ createFreshIndex() {
182
222
  const native = loadNativeModule();
183
- const distanceMetric = this.config.metric === 'cosine'
184
- ? native.DistanceMetric.Cosine
185
- : native.DistanceMetric.Euclidean;
223
+ const space = this.config.metric === 'euclidean' ? 'l2' : 'cosine';
186
224
  try {
187
- this.nativeDb = new native.VectorDb({
188
- dimensions: this.config.dimensions,
189
- distanceMetric,
190
- hnswM: this.config.M,
191
- hnswEfConstruction: this.config.efConstruction,
192
- hnswEfSearch: this.config.efSearch,
193
- });
225
+ const idx = new native.HierarchicalNSW(space, this.config.dimensions);
226
+ idx.initIndex(this.currentMaxElements, this.config.M, this.config.efConstruction,
227
+ // randomSeed: deterministic per-config seed so test runs are reproducible.
228
+ // hnswlib-node uses this to randomize level assignment during graph construction.
229
+ 100,
230
+ // allowReplaceDeleted: true so markDelete()-ed slots can be reused by future addPoint().
231
+ true);
232
+ idx.setEf(this.config.efSearch);
233
+ return idx;
194
234
  }
195
235
  catch (err) {
196
236
  const message = err instanceof Error ? err.message : String(err);
197
- throw new NativeHnswUnavailableError(`VectorDb creation failed: ${message}`);
237
+ throw new NativeHnswUnavailableError(`HierarchicalNSW init failed: ${message}`);
198
238
  }
199
239
  }
200
240
  // ============================================================================
201
241
  // IHnswIndexProvider Implementation
202
242
  // ============================================================================
203
243
  add(id, vector, metadata) {
244
+ if (!this.nativeIndex) {
245
+ throw new Error('NativeHnswBackend has been disposed');
246
+ }
204
247
  const normalized = this.normalizeVector(vector);
205
- const norm = computeNorm(normalized);
206
- // Remove existing entry if updating
207
- if (this.vectorStore.has(id)) {
208
- try {
209
- this.nativeDb.delete(String(id));
210
- }
211
- catch { /* ignore if not found */ }
248
+ // Grow the index if we're about to overflow. hnswlib-node's resizeIndex
249
+ // doubles in-place; this gives amortized O(1) growth at the cost of a
250
+ // single memcpy on each doubling. Required for production use cases
251
+ // where the index size is not known at construction time.
252
+ if (!this.liveIds.has(id) && this.liveIds.size >= this.currentMaxElements) {
253
+ const newMax = this.currentMaxElements * 2;
254
+ this.nativeIndex.resizeIndex(newMax);
255
+ this.currentMaxElements = newMax;
212
256
  }
213
- this.nativeDb.insert(String(id), normalized);
214
- this.vectorStore.set(id, normalized);
215
- this.normStore.set(id, norm);
257
+ // hnswlib-node treats addPoint with an existing label as an UPDATE.
258
+ // The replaceDeleted flag lets us reuse soft-deleted slots transparently.
259
+ this.nativeIndex.addPoint(toNumberArray(normalized), id, true);
260
+ this.liveIds.add(id);
216
261
  if (metadata) {
217
262
  this.metadataStore.set(id, metadata);
218
263
  }
264
+ else {
265
+ this.metadataStore.delete(id);
266
+ }
219
267
  this._metrics.totalAdds++;
220
268
  }
221
269
  search(query, k) {
222
- const start = performance.now();
223
- if (this.vectorStore.size === 0)
270
+ if (!this.nativeIndex) {
271
+ throw new Error('NativeHnswBackend has been disposed');
272
+ }
273
+ if (this.liveIds.size === 0 || k <= 0)
224
274
  return [];
275
+ const start = performance.now();
225
276
  const normalizedQuery = this.normalizeVector(query);
226
- const queryNorm = computeNorm(normalizedQuery);
227
- const actualK = Math.min(k, this.vectorStore.size);
228
- let results;
229
- try {
230
- const nativeResults = this.nativeDb.search(normalizedQuery, actualK);
231
- // Convert native distance scores to similarity scores.
232
- // @ruvector/router returns { id: string, score: number } where
233
- // score is a distance (lower = closer). We convert string IDs
234
- // back to numbers and compute cosine similarity for consistency.
235
- results = nativeResults.map((nr) => {
236
- const numericId = Number(nr.id);
237
- const storedVector = this.vectorStore.get(numericId);
238
- const storedNorm = this.normStore.get(numericId) ?? 0;
239
- // Compute cosine similarity for consistent scoring with ProgressiveHnswBackend
240
- let score;
241
- if (this.config.metric === 'cosine' && storedVector) {
242
- score = fastCosineSimilarity(normalizedQuery, storedVector, queryNorm, storedNorm);
243
- }
244
- else {
245
- // For euclidean, negate the distance (higher = closer)
246
- score = -nr.score;
247
- }
248
- return {
249
- id: numericId,
250
- score,
251
- metadata: this.metadataStore.get(numericId),
252
- };
253
- });
254
- // Sort by descending score for consistency
255
- results.sort((a, b) => b.score - a.score);
256
- this._metrics.nativeSearchCount++;
257
- }
258
- catch {
259
- // If native search fails, fall back to brute-force over stored vectors
260
- this._metrics.fallbackSearchCount++;
261
- this._metrics.bruteForceSearchCount++;
262
- console.warn(`[NativeHNSW] FALLBACK: Using brute-force linear scan (@ruvector/router search failed). Index size: ${this.vectorStore.size}`);
263
- results = this.bruteForceSearch(normalizedQuery, queryNorm, actualK);
277
+ const actualK = Math.min(k, this.liveIds.size);
278
+ // Overshoot k by 2x (capped at index size) so that defensive dedup
279
+ // below can drop any duplicate-label entries hnswlib may return after
280
+ // long add/remove churn and still leave us with at least k unique
281
+ // results when possible.
282
+ const overshoot = Math.min(actualK * 2, this.liveIds.size);
283
+ const native = this.nativeIndex.searchKnn(toNumberArray(normalizedQuery), overshoot);
284
+ // Convert hnswlib-node distances to similarity scores.
285
+ // cosine space: distance = 1 - cos_sim, so similarity = 1 - distance
286
+ // l2 space: distance = sum((x_i - y_i)^2), no clean similarity;
287
+ // we negate so that "higher = closer" remains the contract
288
+ const isCosine = this.config.metric === 'cosine';
289
+ // Defensive dedup: keep only the best score for each id. hnswlib-node
290
+ // can return duplicate labels after pathological add/remove cycles
291
+ // (verified empirically — see ADR-090 / issue #399 follow-up). We
292
+ // can't fix the C++ side from here, but we can make sure callers
293
+ // never see duplicates by collapsing them at the wrapper boundary.
294
+ const seen = new Map();
295
+ for (let i = 0; i < native.neighbors.length; i++) {
296
+ const id = native.neighbors[i];
297
+ // Skip ids we've already removed at the wrapper level. liveIds is
298
+ // the source of truth for "is this id currently in the index" —
299
+ // hnswlib's internal markDelete state can lag.
300
+ if (!this.liveIds.has(id))
301
+ continue;
302
+ const distance = native.distances[i];
303
+ const score = isCosine ? 1 - distance : -distance;
304
+ const existing = seen.get(id);
305
+ if (existing === undefined || score > existing.score) {
306
+ seen.set(id, { id, score, metadata: this.metadataStore.get(id) });
307
+ }
264
308
  }
309
+ const results = Array.from(seen.values());
310
+ // hnswlib-node returns results in ascending distance order (best first
311
+ // for distance), but our SearchResult contract is descending score
312
+ // (best first for similarity). Sort defensively to guarantee the
313
+ // contract regardless of how the metric maps.
314
+ results.sort((a, b) => b.score - a.score);
315
+ // Truncate to the requested k after dedup.
316
+ if (results.length > actualK)
317
+ results.length = actualK;
265
318
  const elapsed = performance.now() - start;
266
319
  this.updateSearchMetrics(elapsed);
267
- // Compute derived fallback metrics
268
- this._metrics.fallbackRate =
269
- this._metrics.fallbackSearchCount / this._metrics.totalSearches;
270
- this._metrics.allSearchesBruteForce =
271
- this._metrics.nativeSearchCount === 0 && this._metrics.totalSearches > 0;
272
- // One-time warning when fallback rate is dangerously high
273
- if (!this.highFallbackWarningEmitted &&
274
- this._metrics.fallbackRate > 0.5 &&
275
- this._metrics.totalSearches >= 10) {
276
- this.highFallbackWarningEmitted = true;
277
- console.error(`[NativeHNSW] WARNING: ${(this._metrics.fallbackRate * 100).toFixed(0)}% of searches are using brute-force fallback. Native HNSW may not be functioning correctly. Consider rebuilding the index or checking @ruvector/router installation.`);
278
- }
320
+ this._metrics.nativeSearchCount = this._metrics.totalSearches;
279
321
  if (elapsed > 50) {
280
322
  console.warn(`[NativeHNSW] search took ${elapsed.toFixed(1)}ms (k=${k}, results=${results.length})`);
281
323
  }
282
324
  return results;
283
325
  }
284
326
  remove(id) {
285
- if (!this.vectorStore.has(id))
327
+ if (!this.nativeIndex)
328
+ return false;
329
+ if (!this.liveIds.has(id))
286
330
  return false;
287
331
  try {
288
- this.nativeDb.delete(String(id));
332
+ this.nativeIndex.markDelete(id);
289
333
  }
290
334
  catch {
291
- // Native remove failed; clean up local state anyway
335
+ // markDelete throws if the label was never added; treat as not-found.
336
+ return false;
292
337
  }
293
- this.vectorStore.delete(id);
294
- this.normStore.delete(id);
338
+ this.liveIds.delete(id);
295
339
  this.metadataStore.delete(id);
296
340
  this._metrics.totalRemoves++;
297
341
  return true;
298
342
  }
299
343
  size() {
300
- return this.vectorStore.size;
344
+ return this.liveIds.size;
301
345
  }
302
346
  dimensions() {
303
347
  return this.config.dimensions;
304
348
  }
305
349
  recall() {
306
- // HNSW is approximate, estimate recall based on efSearch/M ratio
307
- // Higher efSearch relative to M means better recall
308
- const ratio = this.config.efSearch / this.config.M;
309
- if (ratio >= 10)
310
- return 0.99;
311
- if (ratio >= 5)
312
- return 0.97;
313
- if (ratio >= 3)
314
- return 0.95;
315
- return 0.90;
350
+ // hnswlib-node with default M=16, efConstruction=200, efSearch=100 hits
351
+ // 100% recall@10 on the project's own qe-kernel fixture and on textbook
352
+ // Gaussian random vectors (verified empirically — see ADR-090). At very
353
+ // large N or aggressively low efSearch, recall is approximate; we report
354
+ // a slightly conservative 0.99 to make that property visible to callers
355
+ // that care about the difference between exact and approximate search.
356
+ return 0.99;
316
357
  }
317
358
  // ============================================================================
318
359
  // Public Utilities
@@ -337,45 +378,47 @@ export class NativeHnswBackend {
337
378
  }
338
379
  /**
339
380
  * Clear all vectors from the index.
340
- * Deletes all entries from the native VectorDb.
381
+ *
382
+ * Recreates the underlying HierarchicalNSW from scratch rather than
383
+ * `markDelete`-ing each label. The tombstone-only approach leaks state
384
+ * across `clear() → re-add` cycles (the C++ graph keeps every deleted
385
+ * slot, and `addPoint(label, replaceDeleted=true)` can produce
386
+ * duplicate-label results from `searchKnn` after many cycles). A fresh
387
+ * index is the only guarantee of O(1) clean state and is what callers
388
+ * who use `clear()` actually expect.
341
389
  */
342
390
  clear() {
343
- if (!this.nativeDb)
391
+ if (!this.nativeIndex)
344
392
  return;
345
- // Delete all entries from native DB
346
- for (const id of this.vectorStore.keys()) {
347
- try {
348
- this.nativeDb.delete(String(id));
349
- }
350
- catch { /* ignore */ }
351
- }
352
- this.vectorStore.clear();
353
- this.normStore.clear();
393
+ this.liveIds.clear();
354
394
  this.metadataStore.clear();
395
+ // Reset capacity to the initial value so a fresh index doesn't carry
396
+ // over the previous index's resize history.
397
+ this.currentMaxElements = INITIAL_MAX_ELEMENTS;
398
+ this.nativeIndex = this.createFreshIndex();
355
399
  }
356
400
  /**
357
- * Dispose of the native VectorDb handle so NAPI garbage collection can
358
- * reclaim the underlying Rust-side index. After dispose(), this backend
359
- * instance must not be used. The HnswAdapter registry is expected to
360
- * drop its reference as part of `HnswAdapter.close(name)`.
401
+ * Dispose of the native index handle.
402
+ *
403
+ * hnswlib-node holds the C++ index in JS-managed memory; setting the
404
+ * reference to null lets V8 GC reclaim it on the next collection cycle.
405
+ * Unlike the previous @ruvector/router VectorDb, there is no file lock
406
+ * to release and no synchronous teardown required.
361
407
  *
362
- * This is the load-bearing fix for the v3.9.1 regression where
363
- * `resetUnifiedMemory()` would null the UnifiedMemoryManager but leave
364
- * a stale NativeHnswBackend alive in the HnswAdapter registry.
408
+ * After dispose(), this backend instance must not be used. The
409
+ * HnswAdapter registry is expected to drop its reference as part of
410
+ * `HnswAdapter.close(name)`.
365
411
  */
366
412
  dispose() {
367
- // Clear local mirrors first so `clear()` on a dead nativeDb is a no-op.
368
- this.vectorStore.clear();
369
- this.normStore.clear();
413
+ this.liveIds.clear();
370
414
  this.metadataStore.clear();
371
- // Drop the native handle. Rust-side VectorDb is reclaimed by NAPI GC.
372
- this.nativeDb = null;
415
+ this.nativeIndex = null;
373
416
  }
374
417
  /**
375
418
  * Check if the native backend is operational.
376
419
  */
377
420
  isNativeAvailable() {
378
- return this.nativeDb !== null;
421
+ return this.nativeIndex !== null;
379
422
  }
380
423
  // ============================================================================
381
424
  // Private Helpers
@@ -396,33 +439,5 @@ export class NativeHnswBackend {
396
439
  this._metrics.avgSearchLatencyMs =
397
440
  this._metrics.avgSearchLatencyMs * ((n - 1) / n) + latencyMs / n;
398
441
  }
399
- /**
400
- * Brute-force fallback search over locally stored vectors.
401
- * Used when native search throws an unexpected error.
402
- */
403
- bruteForceSearch(query, queryNorm, k) {
404
- const scored = [];
405
- for (const [id, vector] of this.vectorStore) {
406
- const norm = this.normStore.get(id) ?? computeNorm(vector);
407
- const score = this.config.metric === 'cosine'
408
- ? fastCosineSimilarity(query, vector, queryNorm, norm)
409
- : -(function () {
410
- let sum = 0;
411
- const len = Math.min(query.length, vector.length);
412
- for (let i = 0; i < len; i++) {
413
- const diff = query[i] - vector[i];
414
- sum += diff * diff;
415
- }
416
- return Math.sqrt(sum);
417
- })();
418
- scored.push({
419
- id,
420
- score,
421
- metadata: this.metadataStore.get(id),
422
- });
423
- }
424
- scored.sort((a, b) => b.score - a.score);
425
- return scored.slice(0, k);
426
- }
427
442
  }
428
443
  //# sourceMappingURL=native-hnsw-backend.js.map
@@ -807,16 +807,21 @@ export class UnifiedMemoryManager {
807
807
  close() {
808
808
  if (this.db) {
809
809
  this.preparedStatements.clear();
810
- // IMPORTANT: vectorIndex.clear() empties the vectors but does NOT
811
- // dispose the backend. The underlying NativeHnswBackend (if native
812
- // HNSW is enabled) holds a native VectorDb that is process-global
813
- // @ruvector/router does not allow a second VectorDb to be
814
- // created in the same process while the first is still alive
815
- // ("Database already open. Cannot acquire lock."). We deliberately
816
- // keep the HnswAdapter alive in its registry so the next
817
- // UnifiedMemoryManager instance re-binds to the same backend.
818
- // See fix/init-v3-9-3 Fix 1 for the dispose() plumbing that tests
819
- // and explicit shutdown paths can use via HnswAdapter.close(name).
810
+ // vectorIndex.clear() recreates the underlying HierarchicalNSW
811
+ // (post #399 / ADR-090 see NativeHnswBackend.clear()), so the
812
+ // next UnifiedMemoryManager instance starts with a fresh graph.
813
+ // The HnswAdapter registry singleton is intentionally preserved
814
+ // across close()/re-init cycles so that consumers that hold a
815
+ // reference to the named adapter (e.g. PatternStore) continue to
816
+ // see live state. Tests and explicit shutdown paths can fully
817
+ // tear down via HnswAdapter.close(name).
818
+ //
819
+ // Historical context: prior to #399, NativeHnswBackend wrapped
820
+ // @ruvector/router's VectorDb which held a process-wide redb file
821
+ // lock — only ONE instance could exist per process and the lock
822
+ // was not released by NAPI dispose ("Database already open").
823
+ // hnswlib-node has none of those constraints; multiple instances
824
+ // coexist freely.
820
825
  this.vectorIndex.clear();
821
826
  this.db.close();
822
827
  this.db = null;