agentic-qe 3.9.35 → 3.10.0

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 (308) hide show
  1. package/.claude/skills/skills-manifest.json +1 -1
  2. package/CHANGELOG.md +131 -0
  3. package/assets/skills/skills-manifest.json +1 -1
  4. package/dist/cli/bundle.js +5 -5
  5. package/dist/cli/chunks/adapter-WTE6UVGP.js +2 -0
  6. package/dist/cli/chunks/{agent-booster-wasm-4PJZ34PF.js → agent-booster-wasm-5UDM2PWG.js} +2 -2
  7. package/dist/cli/chunks/{agent-handler-OB5JATVT.js → agent-handler-JSYER5YC.js} +2 -2
  8. package/dist/cli/chunks/{agent-memory-branch-ZEHRWZ5R.js → agent-memory-branch-T2SAHI4F.js} +2 -2
  9. package/dist/cli/chunks/aqe-learning-engine-LCLEBU7D.js +2 -0
  10. package/dist/cli/chunks/{audit-PWFRSBBW.js → audit-HIBRVGXG.js} +2 -2
  11. package/dist/cli/chunks/base-73I73HBF.js +2 -0
  12. package/dist/cli/chunks/{hnswlib-node-XEOLAMMR.js → better-sqlite3-Y6GX6CGB.js} +2 -2
  13. package/dist/cli/chunks/{brain-handler-6SMUCFO7.js → brain-handler-N6AWIMXG.js} +3 -3
  14. package/dist/cli/chunks/{branch-enumerator-U6ROQR4O.js → branch-enumerator-VYQGBVEJ.js} +2 -2
  15. package/dist/cli/chunks/{browser-BMM57TA3.js → browser-2X4WKZPT.js} +2 -2
  16. package/dist/cli/chunks/browser-workflow-2NSV5O6W.js +2 -0
  17. package/dist/cli/chunks/{chunk-GWXP36YP.js → chunk-27ACATRH.js} +2 -2
  18. package/dist/cli/chunks/{chunk-3R6YQEQY.js → chunk-2GL4GH52.js} +4 -4
  19. package/dist/cli/chunks/{chunk-MSEG7GKM.js → chunk-2POXDKUB.js} +1 -1
  20. package/dist/cli/chunks/chunk-3BO7EKGO.js +12 -0
  21. package/dist/cli/chunks/{chunk-X3GKTB6R.js → chunk-3OSCWD7Z.js} +1 -1
  22. package/dist/cli/chunks/{chunk-WU3RGTLV.js → chunk-3QULDB7K.js} +1 -1
  23. package/dist/cli/chunks/{chunk-FXITHMQB.js → chunk-3U77XX6J.js} +4 -4
  24. package/dist/cli/chunks/{chunk-BEJAUYFA.js → chunk-4NQ6KANC.js} +2 -2
  25. package/dist/cli/chunks/{chunk-56O5V5MP.js → chunk-4UUDFWOP.js} +2 -2
  26. package/dist/cli/chunks/{chunk-7RNLOYAP.js → chunk-4WYGUTSF.js} +2 -2
  27. package/dist/cli/chunks/{chunk-HSR7EHVN.js → chunk-55JPAF56.js} +1 -1
  28. package/dist/cli/chunks/{chunk-T4HZLBM4.js → chunk-5QJDH4Z5.js} +2 -2
  29. package/dist/cli/chunks/{chunk-UQ6JC3UY.js → chunk-5RQT7EJP.js} +3 -3
  30. package/dist/cli/chunks/{chunk-CROIRPKG.js → chunk-5UOV7T36.js} +2 -2
  31. package/dist/cli/chunks/{chunk-HMIRBSTI.js → chunk-66GIKUI2.js} +2 -2
  32. package/dist/cli/chunks/{chunk-YLYKRAGZ.js → chunk-6F3WJOU2.js} +2 -2
  33. package/dist/cli/chunks/{chunk-SSJV4AZ7.js → chunk-6H5MRVJS.js} +6 -6
  34. package/dist/cli/chunks/{chunk-MHUPY3YO.js → chunk-6HCHW5TS.js} +2 -2
  35. package/dist/cli/chunks/{chunk-FMV22K3J.js → chunk-6MONUYQ5.js} +2 -2
  36. package/dist/cli/chunks/{chunk-HGJGU625.js → chunk-7Y54QZKF.js} +2 -2
  37. package/dist/cli/chunks/{chunk-JNK742DP.js → chunk-7ZIRDBXH.js} +1 -1
  38. package/dist/cli/chunks/{chunk-YPJ2O3TE.js → chunk-AFFYJSW2.js} +2 -2
  39. package/dist/cli/chunks/{chunk-4NVDPO7L.js → chunk-ALCQRJDY.js} +2 -2
  40. package/dist/cli/chunks/{chunk-BTPDHALG.js → chunk-BQT4J3BD.js} +2 -2
  41. package/dist/cli/chunks/{chunk-3UGY4ZQB.js → chunk-BQX5QDU5.js} +1 -1
  42. package/dist/cli/chunks/{chunk-BSM7YJBY.js → chunk-BTIVIWIG.js} +1 -1
  43. package/dist/cli/chunks/{chunk-3YIVRMQB.js → chunk-BXCS55GB.js} +1 -1
  44. package/dist/cli/chunks/{chunk-5CZDHJZX.js → chunk-C5QESAYA.js} +1 -1
  45. package/dist/cli/chunks/{chunk-CTU4V32J.js → chunk-CU4IUJ2K.js} +2 -2
  46. package/dist/cli/chunks/{chunk-6TYWIS4R.js → chunk-DQJJS4AX.js} +2 -2
  47. package/dist/cli/chunks/{chunk-OPD6AENV.js → chunk-DQLEZBWV.js} +2 -2
  48. package/dist/cli/chunks/{chunk-ACL5JFJR.js → chunk-DXV6NRG3.js} +2 -2
  49. package/dist/cli/chunks/{chunk-5XXZQCHS.js → chunk-DY7IRNE2.js} +1 -1
  50. package/dist/cli/chunks/{chunk-NPUMPLL7.js → chunk-F363JJUI.js} +1 -1
  51. package/dist/cli/chunks/{chunk-HAOGVFKR.js → chunk-FCSJ7GIZ.js} +2 -2
  52. package/dist/cli/chunks/{chunk-6WZNRHJJ.js → chunk-FEBXP74Y.js} +1 -1
  53. package/dist/cli/chunks/{chunk-G6BJ5I57.js → chunk-FQ5FT7IE.js} +1 -1
  54. package/dist/cli/chunks/{chunk-SI6VUQSI.js → chunk-FX4SYT6Y.js} +3 -3
  55. package/dist/cli/chunks/{chunk-INCNWH3R.js → chunk-G2HA2O3R.js} +2 -2
  56. package/dist/cli/chunks/{chunk-M4BCSFVN.js → chunk-GPKZ4MMH.js} +1 -1
  57. package/dist/cli/chunks/{chunk-QOAVXGAU.js → chunk-GXCD7GNH.js} +2 -2
  58. package/dist/cli/chunks/{chunk-4UZ7G2KT.js → chunk-HD5NQDOL.js} +2 -2
  59. package/dist/cli/chunks/{chunk-NS4P3VRA.js → chunk-HD6CZBZV.js} +2 -2
  60. package/dist/cli/chunks/{chunk-RPRFDO23.js → chunk-HIWBW4IQ.js} +1 -1
  61. package/dist/cli/chunks/{chunk-GHMIADYW.js → chunk-HZPXOAFW.js} +2 -2
  62. package/dist/cli/chunks/{chunk-3BDZSWCA.js → chunk-I4E6CLC4.js} +2 -2
  63. package/dist/cli/chunks/{chunk-T2QVCK56.js → chunk-I4T4JPR2.js} +1 -1
  64. package/dist/cli/chunks/{chunk-OJ5GBEXU.js → chunk-IBXNBLGM.js} +2 -2
  65. package/dist/cli/chunks/{chunk-J2LOP3GE.js → chunk-IQNR662U.js} +2 -2
  66. package/dist/cli/chunks/{chunk-FMAUTL26.js → chunk-J5RJYFRM.js} +2 -2
  67. package/dist/cli/chunks/{chunk-2UY3X3KE.js → chunk-JCKX2LEJ.js} +9 -9
  68. package/dist/cli/chunks/{chunk-2ICMLI2T.js → chunk-JKVNZASH.js} +2 -2
  69. package/dist/cli/chunks/{chunk-IQ363U37.js → chunk-JUICZG3T.js} +2 -2
  70. package/dist/cli/chunks/{chunk-RP5SDWCL.js → chunk-KCHFF4IE.js} +9 -9
  71. package/dist/cli/chunks/{chunk-NJUNYXMH.js → chunk-KDFW7MVM.js} +2 -2
  72. package/dist/cli/chunks/{chunk-DEJW6GYF.js → chunk-KNL3QWVA.js} +2 -2
  73. package/dist/cli/chunks/{chunk-5Q7X5SDB.js → chunk-KOSKGZK4.js} +2 -2
  74. package/dist/cli/chunks/{chunk-D2ITP3ON.js → chunk-KYLJERZ3.js} +2 -2
  75. package/dist/cli/chunks/{chunk-S3QU54ZQ.js → chunk-L2AIES7X.js} +1 -1
  76. package/dist/cli/chunks/{chunk-YYKZVBIG.js → chunk-L3IFZ4IX.js} +2 -2
  77. package/dist/cli/chunks/{chunk-42QMNST6.js → chunk-L4N6PTIC.js} +2 -2
  78. package/dist/cli/chunks/{chunk-I7XQT6YM.js → chunk-LDMG4372.js} +2 -2
  79. package/dist/cli/chunks/{chunk-NAVH552F.js → chunk-LQ3TA22E.js} +2 -2
  80. package/dist/cli/chunks/{chunk-2FTSVPVG.js → chunk-LRISVDVO.js} +1 -1
  81. package/dist/cli/chunks/{chunk-M7TDNJMZ.js → chunk-LXHA55EB.js} +1 -1
  82. package/dist/cli/chunks/{chunk-HKQ23RPJ.js → chunk-LYVFC7C7.js} +2 -2
  83. package/dist/cli/chunks/{chunk-BTQA2E2Y.js → chunk-M3M7HXDH.js} +2 -2
  84. package/dist/cli/chunks/{chunk-BKF3E3UJ.js → chunk-M4HDBRVJ.js} +1 -1
  85. package/dist/cli/chunks/{chunk-XMCMLPXY.js → chunk-M73IL7FA.js} +2 -2
  86. package/dist/cli/chunks/{chunk-UDKBQAAH.js → chunk-MF3XRML3.js} +2 -2
  87. package/dist/cli/chunks/{chunk-E7N6CRFV.js → chunk-MJBXQXSX.js} +1 -1
  88. package/dist/cli/chunks/{chunk-F6R2TGNS.js → chunk-NLCUQMUR.js} +2 -2
  89. package/dist/cli/chunks/{chunk-UJTI5MRE.js → chunk-NT4PI5HI.js} +2 -2
  90. package/dist/cli/chunks/{chunk-I5XEXLBF.js → chunk-NWHSEXHA.js} +1 -1
  91. package/dist/cli/chunks/{chunk-FPPV7TYI.js → chunk-O3NAUNFC.js} +2 -2
  92. package/dist/cli/chunks/{chunk-TE27EK44.js → chunk-OGT45MZN.js} +2 -2
  93. package/dist/cli/chunks/{chunk-RZDMSTAQ.js → chunk-OKGK7DBT.js} +2 -2
  94. package/dist/cli/chunks/{chunk-X27VMOIH.js → chunk-OUJJ34JH.js} +1 -1
  95. package/dist/cli/chunks/{chunk-A5LZVQQL.js → chunk-OWMGD7FO.js} +3 -3
  96. package/dist/cli/chunks/{chunk-AAVOYIKA.js → chunk-P6XYFDXN.js} +1 -1
  97. package/dist/cli/chunks/{chunk-TLBIFZM4.js → chunk-PNDO4W4L.js} +2 -2
  98. package/dist/cli/chunks/{chunk-WFVBK7N3.js → chunk-QL3U5VSM.js} +2 -2
  99. package/dist/cli/chunks/{chunk-6SN55CMC.js → chunk-QU54GUEA.js} +2 -2
  100. package/dist/cli/chunks/{chunk-YBGQT3OS.js → chunk-QWBO76AU.js} +2 -2
  101. package/dist/cli/chunks/{chunk-Z6NUCGQA.js → chunk-RARSTEUO.js} +1 -1
  102. package/dist/cli/chunks/{chunk-JW4N25B5.js → chunk-RF6QKV7M.js} +2 -2
  103. package/dist/cli/chunks/{chunk-T26ENWX5.js → chunk-RGONSQ44.js} +8 -8
  104. package/dist/cli/chunks/{chunk-PK3NAZQI.js → chunk-RH3PHCJT.js} +2 -2
  105. package/dist/cli/chunks/{chunk-WGWOCTQW.js → chunk-S33246T4.js} +1 -1
  106. package/dist/cli/chunks/{chunk-BXBUUSJN.js → chunk-S4CNA6Z5.js} +3 -3
  107. package/dist/cli/chunks/{chunk-YL56FMCJ.js → chunk-SCYF5CQA.js} +1 -1
  108. package/dist/cli/chunks/{chunk-SBDRHY3I.js → chunk-SGONA5GS.js} +2 -2
  109. package/dist/cli/chunks/{chunk-4YKHVRQH.js → chunk-T7DLX3LS.js} +3 -3
  110. package/dist/cli/chunks/{chunk-NFIOKKA6.js → chunk-TEJPHJMW.js} +2 -2
  111. package/dist/cli/chunks/{chunk-FMZ7I4XV.js → chunk-TR7BZLB6.js} +1 -1
  112. package/dist/cli/chunks/{chunk-VMMPOLUV.js → chunk-U56TIYGP.js} +2 -2
  113. package/dist/cli/chunks/{chunk-H7V3ZQT7.js → chunk-UCIJCRPB.js} +2 -2
  114. package/dist/cli/chunks/{chunk-GR732YA3.js → chunk-UCXQQCIP.js} +2 -2
  115. package/dist/cli/chunks/{chunk-IXOGBA7C.js → chunk-UE3XXKLN.js} +2 -2
  116. package/dist/cli/chunks/{chunk-KAEWFVGD.js → chunk-UGX4EHT5.js} +2 -2
  117. package/dist/cli/chunks/{chunk-ICYM7H6T.js → chunk-URVDWF2Y.js} +2 -2
  118. package/dist/cli/chunks/{chunk-BCD2IMXF.js → chunk-V5TRAL57.js} +2 -2
  119. package/dist/cli/chunks/{chunk-A7QP5E46.js → chunk-VEOQH4W6.js} +2 -2
  120. package/dist/cli/chunks/{chunk-CMKNLC3Q.js → chunk-VMJXNTJT.js} +4 -4
  121. package/dist/cli/chunks/{chunk-PY7PJT2Y.js → chunk-VTIXFHZR.js} +2 -2
  122. package/dist/cli/chunks/{chunk-YTB7DDLE.js → chunk-VTO5O7DA.js} +1 -1
  123. package/dist/cli/chunks/{chunk-C7QVMFCJ.js → chunk-W6U7SIIK.js} +3 -3
  124. package/dist/cli/chunks/{chunk-II6DIMY6.js → chunk-WC6KZDPM.js} +2 -2
  125. package/dist/cli/chunks/{chunk-4HJVTKJD.js → chunk-WG6I7YF3.js} +1 -1
  126. package/dist/cli/chunks/{chunk-GWROZUWK.js → chunk-WLLE54TA.js} +1 -1
  127. package/dist/cli/chunks/{chunk-BBHTM2RF.js → chunk-WVCIZIKH.js} +1 -1
  128. package/dist/cli/chunks/{chunk-ZAGCKWOC.js → chunk-X4U5NYB6.js} +1 -1
  129. package/dist/cli/chunks/chunk-X73CRYF4.js +2 -0
  130. package/dist/cli/chunks/{chunk-GQCIW2ZZ.js → chunk-XFMSHTXG.js} +1 -1
  131. package/dist/cli/chunks/{chunk-NWWXVXXG.js → chunk-XFUU2RCA.js} +2 -2
  132. package/dist/cli/chunks/{chunk-WSJN6HFR.js → chunk-Y4I5JBOL.js} +2 -2
  133. package/dist/cli/chunks/{chunk-XUZ73S3Y.js → chunk-YHNEBCYQ.js} +2 -2
  134. package/dist/cli/chunks/{chunk-O3MTYRBX.js → chunk-YYDHTBHE.js} +1 -1
  135. package/dist/cli/chunks/{chunk-6CCKOU2U.js → chunk-Z2SCTEZD.js} +2 -2
  136. package/dist/cli/chunks/{chunk-72HXOVRN.js → chunk-Z6JLPPAY.js} +1 -1
  137. package/dist/cli/chunks/{chunk-NZB2JE2D.js → chunk-ZCNVFULO.js} +2 -2
  138. package/dist/cli/chunks/{chunk-VLZ3LC6L.js → chunk-ZFBMBCKN.js} +2 -2
  139. package/dist/cli/chunks/{chunk-SMPMLODT.js → chunk-ZYZWBNKT.js} +1 -1
  140. package/dist/cli/chunks/{ci-GXSOJB6I.js → ci-7TR4NQ5I.js} +2 -2
  141. package/dist/cli/chunks/{ci-output-GNUGZD2F.js → ci-output-SLTICF3O.js} +2 -2
  142. package/dist/cli/chunks/{circuit-breaker-LAW2AAHF.js → circuit-breaker-7GVVTMBY.js} +2 -2
  143. package/dist/cli/chunks/{claude-flow-setup-VF5NUUJZ.js → claude-flow-setup-TYCWYEMM.js} +2 -2
  144. package/dist/cli/chunks/client-7GB4WWUD.js +2 -0
  145. package/dist/cli/chunks/{cline-installer-H7RPYI3G.js → cline-installer-ESIAJOLK.js} +2 -2
  146. package/dist/cli/chunks/{code-COHRPYF6.js → code-I42JGOVI.js} +2 -2
  147. package/dist/cli/chunks/{code-index-extractor-353PWY6B.js → code-index-extractor-2CCXPCQW.js} +2 -2
  148. package/dist/cli/chunks/{codex-installer-DIXHDH63.js → codex-installer-HEZRDNUT.js} +2 -2
  149. package/dist/cli/chunks/{completions-NGPREB6E.js → completions-44HLIZGI.js} +2 -2
  150. package/dist/cli/chunks/{complexity-analyzer-BO3QCTWT.js → complexity-analyzer-SOCSFDVO.js} +2 -2
  151. package/dist/cli/chunks/{continuedev-installer-SG4HUNX6.js → continuedev-installer-Q7O4HLIM.js} +2 -2
  152. package/dist/cli/chunks/{copilot-installer-RC6ZFHQG.js → copilot-installer-GIWCVLCS.js} +2 -2
  153. package/dist/cli/chunks/{cost-tracker-Q76KFISR.js → cost-tracker-G7BONKEV.js} +2 -2
  154. package/dist/cli/chunks/{coverage-PT23ZOGU.js → coverage-5TWVP7KY.js} +3 -3
  155. package/dist/cli/chunks/cross-domain-router-7HQ74TLE.js +2 -0
  156. package/dist/cli/chunks/{cursor-installer-ZDS65WC6.js → cursor-installer-43EQZSB5.js} +2 -2
  157. package/dist/cli/chunks/{daemon-M32BWOES.js → daemon-QQZE4BU2.js} +4 -4
  158. package/dist/cli/chunks/{daemon-ZRDBUK4Q.js → daemon-ZXHFRDKG.js} +3 -3
  159. package/dist/cli/chunks/{dag-attention-scheduler-GUPZT7PR.js → dag-attention-scheduler-GOZAVAZQ.js} +2 -2
  160. package/dist/cli/chunks/{detect-PZNLC2CO.js → detect-X777GVJ4.js} +2 -2
  161. package/dist/cli/chunks/{dist-node-QO5MMHVF.js → dist-node-EZZK46TB.js} +2 -2
  162. package/dist/cli/chunks/{domain-handler-OH2YSZCT.js → domain-handler-ZT32DKYY.js} +2 -2
  163. package/dist/cli/chunks/{domain-transfer-TVTK2YX5.js → domain-transfer-LHQVSLJW.js} +2 -2
  164. package/dist/cli/chunks/dream-G5SEFHI4.js +2 -0
  165. package/dist/cli/chunks/{embed-and-insert-pattern-2ARE7NCX.js → embed-and-insert-pattern-XFYPPWG7.js} +2 -2
  166. package/dist/cli/chunks/{eval-64RXRKM4.js → eval-V4NYJZUZ.js} +2 -2
  167. package/dist/cli/chunks/{experience-capture-middleware-TH7JERGY.js → experience-capture-middleware-HXX2W4GL.js} +3 -3
  168. package/dist/cli/chunks/{fast-paths-IAWNSJFU.js → fast-paths-RBPWQSFJ.js} +2 -2
  169. package/dist/cli/chunks/{feature-flags-TAKLIOWM.js → feature-flags-INJJZBMN.js} +2 -2
  170. package/dist/cli/chunks/{feature-flags-22FDDEFG.js → feature-flags-NX5EXRO3.js} +2 -2
  171. package/dist/cli/chunks/{file-discovery-QWEHC5VO.js → file-discovery-SNFSG6NK.js} +2 -2
  172. package/dist/cli/chunks/{fleet-5PQX4H2Q.js → fleet-6SDN4UWE.js} +3 -3
  173. package/dist/cli/chunks/{gnn-wrapper-RR5EYGCL.js → gnn-wrapper-2JDRTDDK.js} +2 -2
  174. package/dist/cli/chunks/{heartbeat-handler-QOVPD6JV.js → heartbeat-handler-QLK6E7KA.js} +4 -4
  175. package/dist/cli/chunks/heartbeat-scheduler-NG7BY3FR.js +2 -0
  176. package/dist/cli/chunks/hnsw-adapter-TDSLUI7K.js +2 -0
  177. package/dist/cli/chunks/hnsw-index-OWLQSOQH.js +2 -0
  178. package/dist/cli/chunks/{hnsw-legacy-bridge-RRTRMCEL.js → hnsw-legacy-bridge-Q2ZEZQKB.js} +2 -2
  179. package/dist/cli/chunks/{better-sqlite3-XEIBI22V.js → hnswlib-node-TA4DZV62.js} +2 -2
  180. package/dist/cli/chunks/{hooks-DTEIDS42.js → hooks-D4YENHO2.js} +53 -53
  181. package/dist/cli/chunks/{hybrid-router-E36GZC7Q.js → hybrid-router-URU2XLBD.js} +2 -2
  182. package/dist/cli/chunks/{hypergraph-engine-7VTF3N6A.js → hypergraph-engine-G72U446M.js} +2 -2
  183. package/dist/cli/chunks/{hypergraph-handler-CTUGX3DL.js → hypergraph-handler-TRZ5FDRH.js} +3 -3
  184. package/dist/cli/chunks/impact-analyzer-NMTN75KA.js +2 -0
  185. package/dist/cli/chunks/{init-handler-HRSUGKSE.js → init-handler-3ZD4GCT4.js} +6 -6
  186. package/dist/cli/chunks/init-wizard-SHBFYGBV.js +2 -0
  187. package/dist/cli/chunks/kernel-7KVY2JGO.js +2 -0
  188. package/dist/cli/chunks/{kilocode-installer-UGB5UY5B.js → kilocode-installer-AXSIW3XW.js} +2 -2
  189. package/dist/cli/chunks/{kiro-installer-7SAM5O2F.js → kiro-installer-JQGIFWBK.js} +2 -2
  190. package/dist/cli/chunks/knowledge-graph-V4G5J5B7.js +2 -0
  191. package/dist/cli/chunks/{learning-GBRPEBXN.js → learning-SPO7TGWX.js} +3 -3
  192. package/dist/cli/chunks/{llm-router-YP2RW2QC.js → llm-router-G6N2OKDA.js} +4 -4
  193. package/dist/cli/chunks/{load-3TRJPJBJ.js → load-XIDDK64U.js} +2 -2
  194. package/dist/cli/chunks/load-test-N4RNPLG4.js +2 -0
  195. package/dist/cli/chunks/{mcp-U7ZYZTEU.js → mcp-3JXRGXO4.js} +2 -2
  196. package/dist/cli/chunks/{memory-CLBPDAAE.js → memory-A66KRS2P.js} +5 -5
  197. package/dist/cli/chunks/memory-backend-HPGJ5YDQ.js +2 -0
  198. package/dist/cli/chunks/{memory-handlers-JEOU6AOR.js → memory-handlers-K33YVCVQ.js} +2 -2
  199. package/dist/cli/chunks/{multi-model-executor-MPPD63KI.js → multi-model-executor-XCDGUVCE.js} +2 -2
  200. package/dist/cli/chunks/{opencode-installer-DIMXI5PK.js → opencode-installer-GELXWLF2.js} +2 -2
  201. package/dist/cli/chunks/{orchestrator-YKOSNTFS.js → orchestrator-CCS3K6NH.js} +5 -5
  202. package/dist/cli/chunks/{pipeline-SDCM3CNA.js → pipeline-Z5C72H5S.js} +2 -2
  203. package/dist/cli/chunks/{platform-7UH4BXN7.js → platform-4AK7XJ3Y.js} +2 -2
  204. package/dist/cli/chunks/{plugin-KIVAXJ3P.js → plugin-7RYBIZI7.js} +2 -2
  205. package/dist/cli/chunks/{prime-radiant-advanced-wasm-PONLGWM6.js → prime-radiant-advanced-wasm-E5PARKRX.js} +2 -2
  206. package/dist/cli/chunks/protocol-executor-GNVWUJUP.js +2 -0
  207. package/dist/cli/chunks/{protocol-handler-6RYLLDOG.js → protocol-handler-R6QJQFNL.js} +2 -2
  208. package/dist/cli/chunks/{prove-PDFFRQQW.js → prove-7ESQ2YAL.js} +2 -2
  209. package/dist/cli/chunks/{provider-manager-I6R4EQGK.js → provider-manager-HV55NIIO.js} +2 -2
  210. package/dist/cli/chunks/qe-reasoning-bank-DDSBHO6D.js +2 -0
  211. package/dist/cli/chunks/{quality-KQVKAGWL.js → quality-4UE345QA.js} +2 -2
  212. package/dist/cli/chunks/queen-coordinator-BQJ5O63C.js +2 -0
  213. package/dist/cli/chunks/real-embeddings-TYIVN3N5.js +2 -0
  214. package/dist/cli/chunks/{roocode-installer-RYPQ25JO.js → roocode-installer-2KOANC47.js} +2 -2
  215. package/dist/cli/chunks/router-C2RKWB7J.js +2 -0
  216. package/dist/cli/chunks/routing-feedback-RHATTSJ6.js +2 -0
  217. package/dist/cli/chunks/{routing-handler-U4FEWPIN.js → routing-handler-JFEYTN7T.js} +2 -2
  218. package/dist/cli/chunks/{ruvector-commands-YID52EZ6.js → ruvector-commands-KSLSZRJX.js} +2 -2
  219. package/dist/cli/chunks/{rvf-dual-writer-HABBORJW.js → rvf-dual-writer-EPBL226J.js} +2 -2
  220. package/dist/cli/chunks/{rvf-migration-adapter-JE5NWU3J.js → rvf-migration-adapter-25KSI6SF.js} +2 -2
  221. package/dist/cli/chunks/{rvf-migration-coordinator-FBIFWTAD.js → rvf-migration-coordinator-2XBYHPZP.js} +2 -2
  222. package/dist/cli/chunks/rvf-native-adapter-QG4CXHLL.js +2 -0
  223. package/dist/cli/chunks/safe-db-A4KQ2IDB.js +2 -0
  224. package/dist/cli/chunks/schedule-O7MLASQT.js +2 -0
  225. package/dist/cli/chunks/scheduler-HT7RNYQ2.js +2 -0
  226. package/dist/cli/chunks/{security-22ERFMD6.js → security-4XWYKI4O.js} +3 -3
  227. package/dist/cli/chunks/{shared-rvf-adapter-YU7XN6ND.js → shared-rvf-adapter-WRZ3HGDQ.js} +2 -2
  228. package/dist/cli/chunks/{shared-rvf-dual-writer-G5VIQHSN.js → shared-rvf-dual-writer-DX2N5STR.js} +2 -2
  229. package/dist/cli/chunks/sqlite-persistence-4NNKJ6CQ.js +2 -0
  230. package/dist/cli/chunks/{status-handler-5B3FP2DN.js → status-handler-V75OSXMQ.js} +2 -2
  231. package/dist/cli/chunks/{structural-health-6YSKVKQG.js → structural-health-TLX3JHZ6.js} +2 -2
  232. package/dist/cli/chunks/{sync-OFSJUYBU.js → sync-DXZFMVZQ.js} +2 -2
  233. package/dist/cli/chunks/{sync-2YCW23XX.js → sync-KGBEXUF7.js} +2 -2
  234. package/dist/cli/chunks/{task-handler-6OIPFSXX.js → task-handler-T3OJ6R7H.js} +2 -2
  235. package/dist/cli/chunks/{task-handlers-6QY5Q5IH.js → task-handlers-NJYR54AS.js} +3 -3
  236. package/dist/cli/chunks/{test-VR6EP23Y.js → test-KMVDNNQA.js} +4 -4
  237. package/dist/cli/chunks/{test-scheduling-OI7N5QBA.js → test-scheduling-R5EQ2XGV.js} +3 -3
  238. package/dist/cli/chunks/{token-bootstrap-HZES3TAA.js → token-bootstrap-PFKVV3RO.js} +2 -2
  239. package/dist/cli/chunks/{token-usage-2NSXSNS7.js → token-usage-ZLOGA6LR.js} +2 -2
  240. package/dist/cli/chunks/{transformers-4U4PX5YQ.js → transformers-TNPSPQI3.js} +2 -2
  241. package/dist/cli/chunks/{tree-sitter-wasm-parser-NQ3JYKHC.js → tree-sitter-wasm-parser-A2EEB5BF.js} +2 -2
  242. package/dist/cli/chunks/{types-YGTXBQ4T.js → types-DIXPI4NR.js} +2 -2
  243. package/dist/cli/chunks/unified-memory-CMNJVHOJ.js +2 -0
  244. package/dist/cli/chunks/unified-memory-hnsw-JQLU2KI6.js +2 -0
  245. package/dist/cli/chunks/unified-persistence-I25TEDIU.js +2 -0
  246. package/dist/cli/chunks/{upgrade-GS4EJOHW.js → upgrade-LX5KP6VO.js} +2 -2
  247. package/dist/cli/chunks/{validate-4X7OETYQ.js → validate-3L6F7M36.js} +2 -2
  248. package/dist/cli/chunks/{validate-swarm-RSVPLHZQ.js → validate-swarm-FD42ZKAQ.js} +2 -2
  249. package/dist/cli/chunks/{vibium-SN2J4QEA.js → vibium-GSBSJR53.js} +2 -2
  250. package/dist/cli/chunks/visual-security-AJJIEV5V.js +2 -0
  251. package/dist/cli/chunks/{web-tree-sitter-ZO6DPXRC.js → web-tree-sitter-TXHMO4BW.js} +2 -2
  252. package/dist/cli/chunks/{windsurf-installer-RGSOOJSH.js → windsurf-installer-3EUZ6RD3.js} +2 -2
  253. package/dist/cli/chunks/witness-chain-762QQBTN.js +2 -0
  254. package/dist/cli/chunks/{witness-chain-7XBKRDAW.js → witness-chain-ONAUEJ4M.js} +2 -2
  255. package/dist/cli/chunks/{workflow-H7KG5R6L.js → workflow-E7A6BV4C.js} +4 -4
  256. package/dist/cli/chunks/workflow-orchestrator-ZGPYISKY.js +2 -0
  257. package/dist/cli/chunks/{wrappers-3YCDNHDG.js → wrappers-AHHAQJM3.js} +2 -2
  258. package/dist/cli/commands/hooks-handlers/hooks-dream-learning.d.ts +3 -3
  259. package/dist/cli/commands/hooks-handlers/hooks-dream-learning.js +4 -3
  260. package/dist/cli/commands/hooks-handlers/routing-hooks.js +50 -12
  261. package/dist/cli/commands/hooks-handlers/task-hooks.js +30 -6
  262. package/dist/learning/agent-routing.d.ts +13 -1
  263. package/dist/learning/agent-routing.js +14 -1
  264. package/dist/learning/embedder-endpoint-client.d.ts +133 -0
  265. package/dist/learning/embedder-endpoint-client.js +426 -0
  266. package/dist/learning/embedder-identity-store.d.ts +30 -0
  267. package/dist/learning/embedder-identity-store.js +136 -0
  268. package/dist/learning/qe-reasoning-bank.js +15 -5
  269. package/dist/learning/real-embeddings.d.ts +28 -0
  270. package/dist/learning/real-embeddings.js +130 -19
  271. package/dist/learning/sqlite-persistence.js +16 -3
  272. package/dist/mcp/bundle.js +399 -389
  273. package/package.json +1 -1
  274. package/dist/cli/chunks/adapter-JUISYMI3.js +0 -2
  275. package/dist/cli/chunks/aqe-learning-engine-DEIUPULJ.js +0 -2
  276. package/dist/cli/chunks/base-7SMQWXHT.js +0 -2
  277. package/dist/cli/chunks/browser-workflow-4DGHRZLS.js +0 -2
  278. package/dist/cli/chunks/chunk-PHJK33IV.js +0 -2
  279. package/dist/cli/chunks/chunk-YQRABKOC.js +0 -2
  280. package/dist/cli/chunks/client-OSUT6W6W.js +0 -2
  281. package/dist/cli/chunks/cross-domain-router-X5EEGWMA.js +0 -2
  282. package/dist/cli/chunks/dream-CP4VOPNU.js +0 -2
  283. package/dist/cli/chunks/heartbeat-scheduler-MX7EHYU5.js +0 -2
  284. package/dist/cli/chunks/hnsw-adapter-B7FZYZGZ.js +0 -2
  285. package/dist/cli/chunks/hnsw-index-7OVB67MX.js +0 -2
  286. package/dist/cli/chunks/impact-analyzer-TG34YBHU.js +0 -2
  287. package/dist/cli/chunks/init-wizard-MS3A2X5C.js +0 -2
  288. package/dist/cli/chunks/kernel-J4IW4DA6.js +0 -2
  289. package/dist/cli/chunks/knowledge-graph-4LCYX5AN.js +0 -2
  290. package/dist/cli/chunks/load-test-TFBVT7V3.js +0 -2
  291. package/dist/cli/chunks/memory-backend-E7OCG27P.js +0 -2
  292. package/dist/cli/chunks/protocol-executor-MYFH7ZP4.js +0 -2
  293. package/dist/cli/chunks/qe-reasoning-bank-G46PVD2U.js +0 -2
  294. package/dist/cli/chunks/queen-coordinator-ZQRKBBUH.js +0 -2
  295. package/dist/cli/chunks/real-embeddings-VQXMPAH6.js +0 -2
  296. package/dist/cli/chunks/router-UBQULTOO.js +0 -2
  297. package/dist/cli/chunks/routing-feedback-3VBS3SYD.js +0 -2
  298. package/dist/cli/chunks/rvf-native-adapter-NDKSHCMG.js +0 -2
  299. package/dist/cli/chunks/safe-db-ZPGX4NYW.js +0 -2
  300. package/dist/cli/chunks/schedule-JZUKDE6O.js +0 -2
  301. package/dist/cli/chunks/scheduler-7YIQOOW3.js +0 -2
  302. package/dist/cli/chunks/sqlite-persistence-4STSI5SJ.js +0 -2
  303. package/dist/cli/chunks/unified-memory-R72C7IBY.js +0 -2
  304. package/dist/cli/chunks/unified-memory-hnsw-A4LOFKDQ.js +0 -2
  305. package/dist/cli/chunks/unified-persistence-MYD2R4LE.js +0 -2
  306. package/dist/cli/chunks/visual-security-CUKQ5N37.js +0 -2
  307. package/dist/cli/chunks/witness-chain-S7ADS6TA.js +0 -2
  308. package/dist/cli/chunks/workflow-orchestrator-3GIDXU43.js +0 -2
@@ -216,13 +216,26 @@ export function deriveTaskType(description) {
216
216
  * Build the canonical Q-learning state_key. Must match the format used by
217
217
  * `updateHookRouterQValue` in hooks-dream-learning.ts — the writer and
218
218
  * reader must agree on the key shape.
219
+ *
220
+ * ADR-096 (issue #499): dropped `complexityBucket` from the state_key.
221
+ * The previous 4-dim key fragmented the state space on raw description
222
+ * length (a ~55-char vs ~130-char phrasing of the same task landed in
223
+ * different buckets), so `QWEIGHT_RAMP_VISITS=20` was rarely reached per
224
+ * cell and Q-values never converged. The 3-dim key collapses related
225
+ * tasks into the same state, letting Q-learning actually generalize.
219
226
  */
220
227
  export function buildRoutingStateKey(opts) {
221
- return `${opts.taskType}|${opts.priority ?? 'normal'}|${opts.domain ?? 'any'}|${opts.complexityBucket}`;
228
+ return `${opts.taskType}|${opts.priority ?? 'normal'}|${opts.domain ?? 'any'}`;
222
229
  }
223
230
  /**
224
231
  * Compute the complexity bucket [0, 10] from a task description length.
225
232
  * Mirrors the formula in task-hooks.ts pre-task bridge.
233
+ *
234
+ * @deprecated ADR-096: no longer used for state_key construction (the
235
+ * length-keyed bucket fragmented the Q-state space). Retained for the
236
+ * pre-task bridge payload (kv_store schema compatibility) and any
237
+ * downstream telemetry that wants a coarse complexity signal. Do NOT use
238
+ * for new Q-routing surfaces.
226
239
  */
227
240
  export function deriveComplexityBucket(description) {
228
241
  return Math.max(0, Math.min(10, Math.round(Math.min(description.length / 200, 1) * 10)));
@@ -0,0 +1,133 @@
1
+ /**
2
+ * External Embedder Endpoint Client (ADR-097)
3
+ *
4
+ * OpenAI-compatible `/v1/embeddings` client over HTTP and HTTP-over-Unix-socket.
5
+ * When `EmbeddingConfig.endpoint` is set, AQE skips loading `@huggingface/transformers`
6
+ * entirely and routes feature-extraction through this client.
7
+ *
8
+ * Design choices per ADR-097 (revised after devil's-advocate audit):
9
+ * - OpenAI wire format with `encoding_format: 'float'` pinned (interop with TEI /
10
+ * vLLM / llama.cpp / Ollama / LocalAI / LM Studio — float pin avoids the
11
+ * base64 default some servers ship).
12
+ * - HTTP + HTTP-over-Unix (one protocol, two transports — no NDJSON fork).
13
+ * - Hard-fail with circuit breaker on errors (no silent hash fallback).
14
+ * - L2-renormalize on receive (don't trust server claims).
15
+ * - Bearer auth from env only; URL userinfo stripped + warned on construct.
16
+ * - Probe + identity fingerprint required before `embed()`; breaker recovery
17
+ * invalidates identity so re-probe runs against a fresh endpoint.
18
+ * - True TCP connect timeout via socket-level setTimeout (not req.setTimeout).
19
+ * - TLS knobs (ca / cert / key / rejectUnauthorized / servername) for self-hosted.
20
+ */
21
+ /**
22
+ * Endpoint identity fingerprint — a SHA-256 of the L2-normalized canary embedding,
23
+ * truncated to the first 16 hex chars. Stable for a given (model, quantization, server)
24
+ * tuple. Changes signal a configuration drift the operator must investigate.
25
+ */
26
+ export interface EndpointIdentity {
27
+ /** Embedding dimension reported by the endpoint */
28
+ dim: number;
29
+ /** Stable fingerprint of the canary embedding (model + quantization signature) */
30
+ fingerprint: string;
31
+ /** Endpoint URL that produced this fingerprint (redacted — no userinfo) */
32
+ endpoint: string;
33
+ }
34
+ /** TLS configuration knobs passed through to https.Agent. */
35
+ export interface EmbedderTlsOptions {
36
+ /** Trusted CA bundle (PEM) or path-loaded buffer. */
37
+ ca?: string | Buffer | Array<string | Buffer>;
38
+ /** Client cert (PEM). */
39
+ cert?: string | Buffer;
40
+ /** Client key (PEM). */
41
+ key?: string | Buffer;
42
+ /** Default true — set false ONLY for explicit dev/test workflows. */
43
+ rejectUnauthorized?: boolean;
44
+ /** SNI override (e.g. for cert-pinned hosts behind an IP). */
45
+ servername?: string;
46
+ }
47
+ export interface EmbedderEndpointClientOptions {
48
+ /** Endpoint URL: http(s)://host:port or unix:/path/to.sock */
49
+ endpoint: string;
50
+ /** Bearer token for Authorization header (typically from AQE_EMBEDDER_TOKEN env) */
51
+ token?: string;
52
+ /** Model identifier sent in the OpenAI request body */
53
+ model?: string;
54
+ /** Expected embedding dimension; probe fails if mismatched */
55
+ expectedDim?: number;
56
+ /** Connect timeout in ms (default 5000). True TCP connect timeout — not idle. */
57
+ connectTimeoutMs?: number;
58
+ /** Per-request timeout in ms (default 30000). Idle-after-connect. */
59
+ requestTimeoutMs?: number;
60
+ /** Circuit breaker: failures within window before tripping (default 3) */
61
+ failureThreshold?: number;
62
+ /** Circuit breaker: failure window in ms (default 60_000) */
63
+ failureWindowMs?: number;
64
+ /** TLS overrides for https transport. Ignored for http/unix. */
65
+ tlsOptions?: EmbedderTlsOptions;
66
+ }
67
+ /**
68
+ * Parsed endpoint — either an HTTP(S) URL or a Unix socket path.
69
+ */
70
+ interface ParsedEndpoint {
71
+ transport: 'http' | 'https' | 'unix';
72
+ socketPath?: string;
73
+ host?: string;
74
+ port?: number;
75
+ protocol?: 'http:' | 'https:';
76
+ /** URL with userinfo stripped, safe for logs. */
77
+ safeUrl: string;
78
+ }
79
+ /**
80
+ * Strip user:password@ from a URL for safe logging.
81
+ * Returns the original string for non-URL inputs (unix paths).
82
+ */
83
+ export declare function redactEndpoint(endpoint: string): string;
84
+ export declare function parseEndpoint(endpoint: string): ParsedEndpoint;
85
+ /**
86
+ * OpenAI-compatible embeddings client with keep-alive, circuit breaker, and identity probe.
87
+ */
88
+ export declare class EmbedderEndpointClient {
89
+ private readonly parsed;
90
+ private readonly agent;
91
+ private readonly breaker;
92
+ private readonly opts;
93
+ private cachedIdentity;
94
+ /** True while a probe is in flight — prevents the embed() lazy-probe race. */
95
+ private probeInFlight;
96
+ constructor(options: EmbedderEndpointClientOptions);
97
+ /** Public, redacted endpoint URL for logs/metrics. */
98
+ getSafeEndpoint(): string;
99
+ /**
100
+ * Embed an array of texts. Returns L2-normalized vectors in input order.
101
+ *
102
+ * Gated on `probe()` — if no cached identity exists, probe is run first so the
103
+ * dim/identity boundary check fires on every cold path. Concurrent embed calls
104
+ * share a single in-flight probe.
105
+ *
106
+ * Throws on error — callers MUST NOT fall back to hash embeddings, which would
107
+ * poison the HNSW index with non-comparable vectors.
108
+ */
109
+ embed(texts: string[]): Promise<number[][]>;
110
+ /**
111
+ * Probe the endpoint by embedding a fixed canary. Returns identity fingerprint.
112
+ * Asserts dim === expectedDim. Throws loud on mismatch.
113
+ * Public so operators can re-probe on demand; idempotent under concurrency.
114
+ */
115
+ probe(): Promise<EndpointIdentity>;
116
+ private ensureProbed;
117
+ private doProbe;
118
+ getCachedIdentity(): EndpointIdentity | null;
119
+ getBreakerState(): {
120
+ open: boolean;
121
+ failures: number;
122
+ trippedAt: number | null;
123
+ };
124
+ /**
125
+ * Close the underlying keep-alive agent. Tests should call this in afterEach.
126
+ */
127
+ close(): void;
128
+ private decodeAndNormalize;
129
+ private postEmbeddings;
130
+ private request;
131
+ }
132
+ export {};
133
+ //# sourceMappingURL=embedder-endpoint-client.d.ts.map
@@ -0,0 +1,426 @@
1
+ /**
2
+ * External Embedder Endpoint Client (ADR-097)
3
+ *
4
+ * OpenAI-compatible `/v1/embeddings` client over HTTP and HTTP-over-Unix-socket.
5
+ * When `EmbeddingConfig.endpoint` is set, AQE skips loading `@huggingface/transformers`
6
+ * entirely and routes feature-extraction through this client.
7
+ *
8
+ * Design choices per ADR-097 (revised after devil's-advocate audit):
9
+ * - OpenAI wire format with `encoding_format: 'float'` pinned (interop with TEI /
10
+ * vLLM / llama.cpp / Ollama / LocalAI / LM Studio — float pin avoids the
11
+ * base64 default some servers ship).
12
+ * - HTTP + HTTP-over-Unix (one protocol, two transports — no NDJSON fork).
13
+ * - Hard-fail with circuit breaker on errors (no silent hash fallback).
14
+ * - L2-renormalize on receive (don't trust server claims).
15
+ * - Bearer auth from env only; URL userinfo stripped + warned on construct.
16
+ * - Probe + identity fingerprint required before `embed()`; breaker recovery
17
+ * invalidates identity so re-probe runs against a fresh endpoint.
18
+ * - True TCP connect timeout via socket-level setTimeout (not req.setTimeout).
19
+ * - TLS knobs (ca / cert / key / rejectUnauthorized / servername) for self-hosted.
20
+ */
21
+ import * as http from 'node:http';
22
+ import * as https from 'node:https';
23
+ import { createHash } from 'node:crypto';
24
+ import { URL } from 'node:url';
25
+ import { normalize as l2Normalize } from '../shared/utils/vector-math.js';
26
+ const DEFAULT_OPTIONS = {
27
+ model: 'Xenova/all-MiniLM-L6-v2',
28
+ expectedDim: 384,
29
+ connectTimeoutMs: 5_000,
30
+ requestTimeoutMs: 30_000,
31
+ failureThreshold: 3,
32
+ failureWindowMs: 60_000,
33
+ };
34
+ const CANARY_TEXT = 'AQE embedder endpoint identity canary v1';
35
+ const EMBEDDINGS_PATH = '/v1/embeddings';
36
+ /**
37
+ * Strip user:password@ from a URL for safe logging.
38
+ * Returns the original string for non-URL inputs (unix paths).
39
+ */
40
+ export function redactEndpoint(endpoint) {
41
+ if (endpoint.startsWith('unix:'))
42
+ return endpoint;
43
+ try {
44
+ const u = new URL(endpoint);
45
+ if (u.username || u.password) {
46
+ u.username = '';
47
+ u.password = '';
48
+ return u.toString().replace(/\/$/, '');
49
+ }
50
+ return endpoint;
51
+ }
52
+ catch {
53
+ return endpoint;
54
+ }
55
+ }
56
+ export function parseEndpoint(endpoint) {
57
+ if (endpoint.startsWith('unix:')) {
58
+ const socketPath = endpoint.slice('unix:'.length);
59
+ if (!socketPath.startsWith('/')) {
60
+ throw new Error(`unix endpoint must be an absolute path: ${endpoint}`);
61
+ }
62
+ return { transport: 'unix', socketPath, safeUrl: endpoint };
63
+ }
64
+ const url = new URL(endpoint);
65
+ if (url.protocol !== 'http:' && url.protocol !== 'https:') {
66
+ throw new Error(`unsupported embedder endpoint protocol: ${url.protocol}`);
67
+ }
68
+ const hadUserinfo = Boolean(url.username || url.password);
69
+ if (hadUserinfo) {
70
+ // Warn loudly — userinfo in the URL bypasses the env-only token convention
71
+ // and leaks into Node's default error messages.
72
+ console.warn(`[EmbedderEndpointClient] endpoint URL contained userinfo; stripping. ` +
73
+ `Use AQE_EMBEDDER_TOKEN env var for credentials.`);
74
+ url.username = '';
75
+ url.password = '';
76
+ }
77
+ return {
78
+ transport: url.protocol === 'https:' ? 'https' : 'http',
79
+ host: url.hostname,
80
+ port: url.port ? Number(url.port) : url.protocol === 'https:' ? 443 : 80,
81
+ protocol: url.protocol,
82
+ safeUrl: url.toString().replace(/\/$/, ''),
83
+ };
84
+ }
85
+ /**
86
+ * Circuit breaker state.
87
+ *
88
+ * Tracks failure timestamps within `windowMs`. Opens when count reaches `threshold`.
89
+ * While open, every request fast-fails until the window expires. On recovery
90
+ * (window elapses), the breaker calls `onRecover` so the client can invalidate
91
+ * cached endpoint identity — endpoint restarts often coincide with model swaps.
92
+ */
93
+ class CircuitBreaker {
94
+ threshold;
95
+ windowMs;
96
+ onRecover;
97
+ failures = [];
98
+ trippedAt = null;
99
+ constructor(threshold, windowMs, onRecover = () => { }) {
100
+ this.threshold = threshold;
101
+ this.windowMs = windowMs;
102
+ this.onRecover = onRecover;
103
+ }
104
+ recordSuccess() {
105
+ this.failures = [];
106
+ this.trippedAt = null;
107
+ }
108
+ recordFailure() {
109
+ const now = Date.now();
110
+ this.failures = this.failures.filter((t) => now - t < this.windowMs);
111
+ this.failures.push(now);
112
+ if (this.failures.length >= this.threshold) {
113
+ this.trippedAt = now;
114
+ }
115
+ }
116
+ isOpen() {
117
+ if (this.trippedAt === null)
118
+ return false;
119
+ if (Date.now() - this.trippedAt >= this.windowMs) {
120
+ this.failures = [];
121
+ this.trippedAt = null;
122
+ // Endpoint may have restarted with a different model — force re-probe.
123
+ this.onRecover();
124
+ return false;
125
+ }
126
+ return true;
127
+ }
128
+ /** For tests / observability */
129
+ getState() {
130
+ return { open: this.isOpen(), failures: this.failures.length, trippedAt: this.trippedAt };
131
+ }
132
+ }
133
+ /**
134
+ * OpenAI-compatible embeddings client with keep-alive, circuit breaker, and identity probe.
135
+ */
136
+ export class EmbedderEndpointClient {
137
+ parsed;
138
+ agent;
139
+ breaker;
140
+ opts;
141
+ cachedIdentity = null;
142
+ /** True while a probe is in flight — prevents the embed() lazy-probe race. */
143
+ probeInFlight = null;
144
+ constructor(options) {
145
+ this.opts = {
146
+ endpoint: options.endpoint,
147
+ token: options.token,
148
+ model: options.model ?? DEFAULT_OPTIONS.model,
149
+ expectedDim: options.expectedDim ?? DEFAULT_OPTIONS.expectedDim,
150
+ connectTimeoutMs: options.connectTimeoutMs ?? DEFAULT_OPTIONS.connectTimeoutMs,
151
+ requestTimeoutMs: options.requestTimeoutMs ?? DEFAULT_OPTIONS.requestTimeoutMs,
152
+ failureThreshold: options.failureThreshold ?? DEFAULT_OPTIONS.failureThreshold,
153
+ failureWindowMs: options.failureWindowMs ?? DEFAULT_OPTIONS.failureWindowMs,
154
+ tlsOptions: options.tlsOptions,
155
+ };
156
+ this.parsed = parseEndpoint(options.endpoint);
157
+ if (this.parsed.transport === 'https') {
158
+ // rejectUnauthorized defaults to true; explicit knobs allow self-hosted CAs.
159
+ const tls = options.tlsOptions ?? {};
160
+ this.agent = new https.Agent({
161
+ keepAlive: true,
162
+ ca: tls.ca,
163
+ cert: tls.cert,
164
+ key: tls.key,
165
+ rejectUnauthorized: tls.rejectUnauthorized !== false,
166
+ servername: tls.servername,
167
+ });
168
+ }
169
+ else {
170
+ this.agent = new http.Agent({ keepAlive: true });
171
+ }
172
+ this.breaker = new CircuitBreaker(this.opts.failureThreshold, this.opts.failureWindowMs, () => {
173
+ // On breaker recovery, drop identity so the next embed() re-probes.
174
+ // Endpoint restarts (the common cause of recovery) often change models.
175
+ this.cachedIdentity = null;
176
+ });
177
+ }
178
+ /** Public, redacted endpoint URL for logs/metrics. */
179
+ getSafeEndpoint() {
180
+ return this.parsed.safeUrl;
181
+ }
182
+ /**
183
+ * Embed an array of texts. Returns L2-normalized vectors in input order.
184
+ *
185
+ * Gated on `probe()` — if no cached identity exists, probe is run first so the
186
+ * dim/identity boundary check fires on every cold path. Concurrent embed calls
187
+ * share a single in-flight probe.
188
+ *
189
+ * Throws on error — callers MUST NOT fall back to hash embeddings, which would
190
+ * poison the HNSW index with non-comparable vectors.
191
+ */
192
+ async embed(texts) {
193
+ if (texts.length === 0)
194
+ return [];
195
+ if (this.breaker.isOpen()) {
196
+ throw new Error(`[EmbedderEndpointClient] circuit breaker open for ${this.parsed.safeUrl} — fast-failing`);
197
+ }
198
+ // Identity gate: every embed call must have a verified identity behind it.
199
+ if (this.cachedIdentity === null) {
200
+ await this.ensureProbed();
201
+ }
202
+ try {
203
+ const data = await this.postEmbeddings(texts);
204
+ const vectors = this.decodeAndNormalize(data, texts.length);
205
+ this.breaker.recordSuccess();
206
+ return vectors;
207
+ }
208
+ catch (err) {
209
+ this.breaker.recordFailure();
210
+ throw err;
211
+ }
212
+ }
213
+ /**
214
+ * Probe the endpoint by embedding a fixed canary. Returns identity fingerprint.
215
+ * Asserts dim === expectedDim. Throws loud on mismatch.
216
+ * Public so operators can re-probe on demand; idempotent under concurrency.
217
+ */
218
+ async probe() {
219
+ if (this.probeInFlight)
220
+ return this.probeInFlight;
221
+ this.probeInFlight = this.doProbe().finally(() => {
222
+ this.probeInFlight = null;
223
+ });
224
+ return this.probeInFlight;
225
+ }
226
+ async ensureProbed() {
227
+ if (this.cachedIdentity)
228
+ return this.cachedIdentity;
229
+ return this.probe();
230
+ }
231
+ async doProbe() {
232
+ // Direct HTTP call (NOT via embed()) so we don't recurse on the identity gate.
233
+ let vec;
234
+ try {
235
+ const data = await this.postEmbeddings([CANARY_TEXT]);
236
+ const vectors = this.decodeAndNormalize(data, 1);
237
+ vec = vectors[0];
238
+ this.breaker.recordSuccess();
239
+ }
240
+ catch (err) {
241
+ this.breaker.recordFailure();
242
+ throw err;
243
+ }
244
+ if (!vec || vec.length !== this.opts.expectedDim) {
245
+ throw new Error(`[EmbedderEndpointClient] dim mismatch: expected ${this.opts.expectedDim}, got ${vec?.length ?? 0} from ${this.parsed.safeUrl}`);
246
+ }
247
+ // Fingerprint = SHA-256 of the canary vector's quantized bytes (16 hex chars).
248
+ // Quantize to int16 first so trivial fp noise between identical (model, server)
249
+ // configurations doesn't shift the fingerprint.
250
+ const buf = Buffer.alloc(vec.length * 2);
251
+ for (let i = 0; i < vec.length; i++) {
252
+ const q = Math.max(-32768, Math.min(32767, Math.round(vec[i] * 32767)));
253
+ buf.writeInt16LE(q, i * 2);
254
+ }
255
+ const fingerprint = createHash('sha256').update(buf).digest('hex').slice(0, 16);
256
+ this.cachedIdentity = {
257
+ dim: vec.length,
258
+ fingerprint,
259
+ endpoint: this.parsed.safeUrl,
260
+ };
261
+ return this.cachedIdentity;
262
+ }
263
+ getCachedIdentity() {
264
+ return this.cachedIdentity;
265
+ }
266
+ getBreakerState() {
267
+ return this.breaker.getState();
268
+ }
269
+ /**
270
+ * Close the underlying keep-alive agent. Tests should call this in afterEach.
271
+ */
272
+ close() {
273
+ this.agent.destroy();
274
+ }
275
+ decodeAndNormalize(json, expectedCount) {
276
+ // OpenAI shape: { data: [{ embedding: [...], index: 0 }, ...] }
277
+ if (!json ||
278
+ typeof json !== 'object' ||
279
+ !Array.isArray(json.data)) {
280
+ throw new Error(`[EmbedderEndpointClient] response missing data array`);
281
+ }
282
+ const rawData = json
283
+ .data;
284
+ if (rawData.length !== expectedCount) {
285
+ throw new Error(`[EmbedderEndpointClient] response count mismatch: expected ${expectedCount}, got ${rawData.length}`);
286
+ }
287
+ // OpenAI guarantees `index` field but ordering is not guaranteed — sort defensively.
288
+ // Fall back to array position when index is absent.
289
+ const indexed = rawData.map((item, i) => ({
290
+ idx: typeof item.index === 'number' ? item.index : i,
291
+ embedding: item.embedding,
292
+ }));
293
+ indexed.sort((a, b) => a.idx - b.idx);
294
+ return indexed.map(({ embedding }, i) => {
295
+ // We pinned encoding_format: 'float' in the request, so a base64 string
296
+ // back means the server ignored our request. Fail loud rather than guess.
297
+ if (typeof embedding === 'string') {
298
+ throw new Error(`[EmbedderEndpointClient] received base64 embedding at position ${i} — ` +
299
+ `server ignored encoding_format=float. Configure the server to return float arrays.`);
300
+ }
301
+ if (!Array.isArray(embedding)) {
302
+ throw new Error(`[EmbedderEndpointClient] missing embedding at position ${i}`);
303
+ }
304
+ if (embedding.length !== this.opts.expectedDim) {
305
+ throw new Error(`[EmbedderEndpointClient] dim mismatch at position ${i}: expected ${this.opts.expectedDim}, got ${embedding.length}`);
306
+ }
307
+ // Re-normalize regardless of server claim — cheap and correct.
308
+ return l2Normalize(embedding);
309
+ });
310
+ }
311
+ postEmbeddings(texts) {
312
+ // Pin encoding_format=float so providers that default to base64 (newer
313
+ // OpenAI/Azure for dims>100) don't silently return strings we'd have to
314
+ // guess at. The decoder throws loud on string responses.
315
+ const body = JSON.stringify({
316
+ model: this.opts.model,
317
+ input: texts,
318
+ encoding_format: 'float',
319
+ });
320
+ return this.request(EMBEDDINGS_PATH, body);
321
+ }
322
+ request(path, body) {
323
+ const headers = {
324
+ 'content-type': 'application/json',
325
+ 'content-length': Buffer.byteLength(body),
326
+ accept: 'application/json',
327
+ };
328
+ if (this.opts.token) {
329
+ headers['authorization'] = `Bearer ${this.opts.token}`;
330
+ }
331
+ const baseOptions = {
332
+ method: 'POST',
333
+ path,
334
+ headers,
335
+ agent: this.agent,
336
+ };
337
+ let reqOptions;
338
+ let requestFn;
339
+ if (this.parsed.transport === 'unix') {
340
+ reqOptions = { ...baseOptions, socketPath: this.parsed.socketPath };
341
+ requestFn = http.request;
342
+ }
343
+ else {
344
+ reqOptions = {
345
+ ...baseOptions,
346
+ host: this.parsed.host,
347
+ port: this.parsed.port,
348
+ protocol: this.parsed.protocol,
349
+ };
350
+ requestFn = this.parsed.transport === 'https' ? https.request : http.request;
351
+ }
352
+ const safeUrl = this.parsed.safeUrl;
353
+ const connectTimeoutMs = this.opts.connectTimeoutMs;
354
+ const requestTimeoutMs = this.opts.requestTimeoutMs;
355
+ return new Promise((resolve, reject) => {
356
+ let settled = false;
357
+ const safeResolve = (val) => {
358
+ if (settled)
359
+ return;
360
+ settled = true;
361
+ resolve(val);
362
+ };
363
+ const safeReject = (err) => {
364
+ if (settled)
365
+ return;
366
+ settled = true;
367
+ reject(err);
368
+ };
369
+ const req = requestFn(reqOptions, (res) => {
370
+ const chunks = [];
371
+ res.on('data', (chunk) => chunks.push(Buffer.from(chunk)));
372
+ res.on('end', () => {
373
+ const text = Buffer.concat(chunks).toString('utf-8');
374
+ if (!res.statusCode || res.statusCode < 200 || res.statusCode >= 300) {
375
+ safeReject(new Error(`[EmbedderEndpointClient] HTTP ${res.statusCode} from ${safeUrl}: ${text.slice(0, 200)}`));
376
+ return;
377
+ }
378
+ try {
379
+ const parsed = JSON.parse(text);
380
+ safeResolve(parsed);
381
+ }
382
+ catch (err) {
383
+ safeReject(new Error(`[EmbedderEndpointClient] invalid JSON from ${safeUrl}: ${err.message}`));
384
+ }
385
+ });
386
+ res.on('error', (err) => safeReject(err));
387
+ });
388
+ // True TCP connect timeout: set on the socket itself, fires before any byte
389
+ // is exchanged. req.setTimeout is an idle-after-write timeout — wrong tool
390
+ // for SYN-drop scenarios. Once connected we clear it and let
391
+ // requestTimeoutMs guard the request/response phase.
392
+ req.on('socket', (socket) => {
393
+ // Pre-connect phase: any idle period this long means the SYN handshake
394
+ // is stuck (DNS, ACL drop, blackhole).
395
+ socket.setTimeout(connectTimeoutMs);
396
+ const onConnect = () => {
397
+ // Switch to the post-connect (read/write idle) timeout budget.
398
+ socket.setTimeout(requestTimeoutMs);
399
+ };
400
+ // For brand-new sockets we wait for 'connect'. Pooled (keep-alive)
401
+ // sockets fire 'connect' synchronously already-connected or not at all —
402
+ // for those, jump straight to the request timeout.
403
+ if (socket.connecting) {
404
+ socket.once('connect', onConnect);
405
+ }
406
+ else {
407
+ onConnect();
408
+ }
409
+ socket.on('timeout', () => {
410
+ // Distinguish phase for the error message.
411
+ const phase = socket.connecting ? 'connect' : 'request';
412
+ const limit = socket.connecting ? connectTimeoutMs : requestTimeoutMs;
413
+ const err = new Error(`[EmbedderEndpointClient] ${phase} timeout after ${limit}ms`);
414
+ // Reject FIRST, then destroy. If we destroy first, the 'error' event
415
+ // races us and we might lose the timeout-specific message.
416
+ safeReject(err);
417
+ req.destroy(err);
418
+ });
419
+ });
420
+ req.on('error', (err) => safeReject(err));
421
+ req.write(body);
422
+ req.end();
423
+ });
424
+ }
425
+ }
426
+ //# sourceMappingURL=embedder-endpoint-client.js.map
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Persistent store for ADR-097 embedder endpoint identity.
3
+ *
4
+ * Identity is written into the unified memory.db `kv_store` table under
5
+ * namespace `_system`, key `embedder_identity:<safe_endpoint_url>`. This lets
6
+ * us detect cross-run model drift: if the fingerprint changes between AQE
7
+ * processes, vectors written before the change may not be comparable to vectors
8
+ * written after, and the operator should know.
9
+ *
10
+ * Conforms to the project's unified-persistence rule (no new .db files).
11
+ *
12
+ * Persistence failures are non-fatal — callers wrap us in try/catch and log.
13
+ * We never throw out of these helpers under expected conditions; failure
14
+ * reasons are surfaced as thrown errors only for genuine I/O problems.
15
+ */
16
+ import type { EndpointIdentity } from './embedder-endpoint-client.js';
17
+ /**
18
+ * Load the last persisted identity for the given endpoint URL.
19
+ * Returns null when nothing has been stored yet OR when the kv store is unavailable.
20
+ */
21
+ export declare function loadEmbedderIdentity(endpointUrl: string): EndpointIdentity | null;
22
+ /**
23
+ * Persist the current identity. Overwrites any prior entry for the same endpoint.
24
+ */
25
+ export declare function saveEmbedderIdentity(identity: EndpointIdentity): void;
26
+ /**
27
+ * For tests: close the cached connection so a fresh DB path can be used.
28
+ */
29
+ export declare function resetEmbedderIdentityStore(): void;
30
+ //# sourceMappingURL=embedder-identity-store.d.ts.map