@remnic/core 9.69.105 → 10.0.1

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 (259) hide show
  1. package/dist/access-admin-ops-surface.js +35 -33
  2. package/dist/access-authorization-probe.js +36 -34
  3. package/dist/access-boundary.js +35 -33
  4. package/dist/access-cli.js +96 -94
  5. package/dist/access-cli.js.map +1 -1
  6. package/dist/access-extraction-force-flush.js +35 -33
  7. package/dist/access-http-briefing.js +36 -34
  8. package/dist/access-http-query.js +37 -35
  9. package/dist/access-http.js +54 -52
  10. package/dist/access-identity-continuity-surface.js +35 -33
  11. package/dist/access-lcm-surface.js +35 -33
  12. package/dist/access-mcp.js +44 -42
  13. package/dist/access-namespace-preflight.js +35 -33
  14. package/dist/access-observe-write-category.js +4 -4
  15. package/dist/access-observe-write-surface.js +35 -33
  16. package/dist/access-operations-batch.js +36 -34
  17. package/dist/access-operations.js +43 -41
  18. package/dist/access-recall-concurrency.js +35 -33
  19. package/dist/access-recall-response.js +35 -33
  20. package/dist/access-recall-surface.js +35 -33
  21. package/dist/access-schema.js +3 -3
  22. package/dist/access-service.js +35 -33
  23. package/dist/access-surface-catalog.js +37 -35
  24. package/dist/access-surface-catalog.js.map +1 -1
  25. package/dist/active-recall.js +11 -9
  26. package/dist/active-recall.js.map +1 -1
  27. package/dist/adapters/index.js +4 -4
  28. package/dist/adapters/registry.js +2 -2
  29. package/dist/briefing.js +10 -8
  30. package/dist/buffer.js +7 -5
  31. package/dist/{capsule-crypto-YO5QJ6L3.js → capsule-crypto-7FJQINUR.js} +2 -2
  32. package/dist/causal-consolidation.js +11 -9
  33. package/dist/causal-consolidation.js.map +1 -1
  34. package/dist/{chunk-JWFTPRYD.js → chunk-2EZB2DL5.js} +2 -2
  35. package/dist/{chunk-BXLOS5AJ.js → chunk-2NLLXCJG.js} +2 -2
  36. package/dist/{chunk-QKCGOECM.js → chunk-34G4U6HS.js} +2 -2
  37. package/dist/{chunk-YI6XIFQV.js → chunk-34TSXVQS.js} +2 -2
  38. package/dist/{chunk-7YQR6XHY.js → chunk-3I375S4J.js} +58 -58
  39. package/dist/{chunk-XQWKB6PY.js → chunk-3UP6NP4C.js} +2 -2
  40. package/dist/{chunk-OFGTRDWX.js → chunk-47I2EK6G.js} +2 -2
  41. package/dist/{chunk-HWGFTTPS.js → chunk-5FLFPTDK.js} +2 -2
  42. package/dist/{chunk-LHDSCWDK.js → chunk-7AUC2YSU.js} +13 -13
  43. package/dist/{chunk-AU43D3IT.js → chunk-7DB7KYSR.js} +4 -4
  44. package/dist/{chunk-VDX2J7OX.js → chunk-7LCGFUMB.js} +4 -4
  45. package/dist/{chunk-CNBGAFDY.js → chunk-A7V7GZ7F.js} +2 -2
  46. package/dist/{chunk-SWXPR5SE.js → chunk-B2UCJX76.js} +2 -2
  47. package/dist/{chunk-KYUVFCT2.js → chunk-BCTDTVSR.js} +2 -2
  48. package/dist/{chunk-6WRHNA4I.js → chunk-BKPV47BK.js} +36 -36
  49. package/dist/{chunk-QAIVTLL2.js → chunk-BLHPADUX.js} +2 -2
  50. package/dist/{chunk-PRNR47DI.js → chunk-BOT276JC.js} +2 -2
  51. package/dist/{chunk-O43AAJFQ.js → chunk-CRZ7BU6R.js} +2 -2
  52. package/dist/{chunk-2OFDC3AK.js → chunk-DDPPV3KA.js} +2 -2
  53. package/dist/{chunk-VYIBRCVW.js → chunk-DHQUQ34W.js} +2 -2
  54. package/dist/{chunk-7NBUE5VY.js → chunk-DPX3J2N4.js} +2 -2
  55. package/dist/{chunk-EWWK65CI.js → chunk-DX3ZODO3.js} +2 -2
  56. package/dist/{chunk-SFDBLCZV.js → chunk-DYZHVVJM.js} +30 -30
  57. package/dist/{chunk-B454SHPU.js → chunk-E7FN5N5E.js} +2 -2
  58. package/dist/{chunk-AWSP3WNM.js → chunk-EJJMDLVB.js} +2 -2
  59. package/dist/{chunk-KFHEZJQZ.js → chunk-EPFNPPWH.js} +2 -2
  60. package/dist/{chunk-VDVHIRCK.js → chunk-EUYNHJTK.js} +2 -2
  61. package/dist/{chunk-T32YYUT2.js → chunk-FB6FQT4P.js} +2 -2
  62. package/dist/{chunk-XTN54NML.js → chunk-G3T6YMBO.js} +4 -4
  63. package/dist/{chunk-JC7QQ2DJ.js → chunk-GS6LTJFW.js} +2 -2
  64. package/dist/{chunk-WR66CTVU.js → chunk-GYLDYYRA.js} +4 -4
  65. package/dist/{chunk-PQKZLBCJ.js → chunk-GZRTH3WZ.js} +1 -1
  66. package/dist/{chunk-STQC2FYQ.js → chunk-HNU5CZ7E.js} +6 -6
  67. package/dist/{chunk-E4XLFYHV.js → chunk-HPEONBM3.js} +2 -2
  68. package/dist/{chunk-B3OFQP5Y.js → chunk-IB63OVUB.js} +24 -249
  69. package/dist/chunk-IB63OVUB.js.map +1 -0
  70. package/dist/chunk-IM2GO42H.js +312 -0
  71. package/dist/chunk-IM2GO42H.js.map +1 -0
  72. package/dist/{chunk-EZ3F4YIN.js → chunk-JLUS56YZ.js} +5 -5
  73. package/dist/{chunk-UHESJ6TQ.js → chunk-KEGUXZNY.js} +3 -3
  74. package/dist/{chunk-UHESJ6TQ.js.map → chunk-KEGUXZNY.js.map} +1 -1
  75. package/dist/{chunk-J3ZJBX7I.js → chunk-KM2HQZR3.js} +2 -2
  76. package/dist/{chunk-2MMBJE53.js → chunk-LI3OM3NP.js} +7 -7
  77. package/dist/{chunk-MZOQ26LH.js → chunk-LQGX5TCI.js} +2 -2
  78. package/dist/{chunk-KMN2JE4D.js → chunk-LTDWZ2HC.js} +2 -2
  79. package/dist/{chunk-T6RQNV7E.js → chunk-MJ737UIA.js} +2 -2
  80. package/dist/{chunk-7X7A7KVN.js → chunk-NLYOOGZ7.js} +2 -2
  81. package/dist/{chunk-PZ2QQULY.js → chunk-NVZRIHW5.js} +8 -8
  82. package/dist/{chunk-NT2Q6AHC.js → chunk-PCO3P7WJ.js} +2 -2
  83. package/dist/{chunk-VO2BNAA2.js → chunk-PXDEIJL5.js} +2 -2
  84. package/dist/{chunk-LXJZUNLX.js → chunk-QHHWJVVW.js} +2 -2
  85. package/dist/{chunk-XLWMNDQR.js → chunk-QJWZJ7HL.js} +3 -3
  86. package/dist/{chunk-73R4HOOK.js → chunk-QPG72IPU.js} +3 -3
  87. package/dist/{chunk-SIGDETMB.js → chunk-R4NGLTUS.js} +2 -2
  88. package/dist/{chunk-TRN56SPQ.js → chunk-R6NHHKXE.js} +2 -2
  89. package/dist/{chunk-ATFFWIKL.js → chunk-RGGXSN5A.js} +2 -2
  90. package/dist/{chunk-IOMLGJHG.js → chunk-RWZXVCGX.js} +5 -5
  91. package/dist/{chunk-PQ7EB5AD.js → chunk-S3BB34NI.js} +3 -3
  92. package/dist/{chunk-QX3K3INR.js → chunk-SBBZXDVJ.js} +2 -2
  93. package/dist/{chunk-G5I5ZT6O.js → chunk-SFDKLEIY.js} +2 -2
  94. package/dist/{chunk-ZLQ37WJX.js → chunk-SIGAGKNE.js} +8 -2
  95. package/dist/{chunk-ZLQ37WJX.js.map → chunk-SIGAGKNE.js.map} +1 -1
  96. package/dist/chunk-TPSLVZHS.js +102 -0
  97. package/dist/chunk-TPSLVZHS.js.map +1 -0
  98. package/dist/{chunk-TXTRHF3B.js → chunk-TVPDF6CZ.js} +2 -2
  99. package/dist/{chunk-A6WNTVA7.js → chunk-UP3XXGEN.js} +2 -2
  100. package/dist/{chunk-S2GR3T7W.js → chunk-UT7WE7RM.js} +2 -2
  101. package/dist/{chunk-BKVCTTEN.js → chunk-V3NKVYUD.js} +2 -2
  102. package/dist/{chunk-CGBE3N7T.js → chunk-VH76UQK3.js} +2 -2
  103. package/dist/{chunk-Z6EZCN6Z.js → chunk-VKQI47DJ.js} +8 -8
  104. package/dist/{chunk-KV7LFOPF.js → chunk-VSPBXHGR.js} +2 -2
  105. package/dist/{chunk-ZRUC7FD3.js → chunk-VXCTQ3B3.js} +2 -2
  106. package/dist/{chunk-QUNCLKHM.js → chunk-WIVBNNA3.js} +2 -2
  107. package/dist/{chunk-OWV6LKNZ.js → chunk-WWUFQ3AG.js} +2 -2
  108. package/dist/{chunk-DQEMWVMT.js → chunk-X7Y7WX73.js} +1 -1
  109. package/dist/{chunk-GQ6ZF4LD.js → chunk-XG4XXI66.js} +2 -2
  110. package/dist/{chunk-ISX7GVZE.js → chunk-YRULQW5J.js} +4 -4
  111. package/dist/{chunk-VV2MVHCJ.js → chunk-YX5F4V7H.js} +2 -2
  112. package/dist/{chunk-JRDL3FGM.js → chunk-YY5FM5M7.js} +3 -3
  113. package/dist/cli.js +70 -68
  114. package/dist/coding/export-okf-codegraph.js +9 -7
  115. package/dist/coding/export-okf-codegraph.js.map +1 -1
  116. package/dist/compounding/engine.js +10 -8
  117. package/dist/config-qmd.js +1 -1
  118. package/dist/config.js +11 -9
  119. package/dist/connectors/codex-materialize-runner.js +10 -8
  120. package/dist/connectors/index.js +10 -8
  121. package/dist/convergence-refresh.js +12 -10
  122. package/dist/corpus-watermark.js +12 -10
  123. package/dist/deep-recall-http-glue.js +4 -4
  124. package/dist/deep-recall.js +2 -2
  125. package/dist/entity-retrieval.js +10 -8
  126. package/dist/external-wiki-access.js +36 -34
  127. package/dist/extraction.js +14 -12
  128. package/dist/harmonic-retrieval.js +1 -1
  129. package/dist/index.js +118 -116
  130. package/dist/lcm/engine.js +3 -3
  131. package/dist/lcm/index.js +9 -9
  132. package/dist/location/index.js +12 -10
  133. package/dist/maintenance/memory-governance.js +10 -8
  134. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +10 -8
  135. package/dist/maintenance/rebuild-memory-projection.js +11 -9
  136. package/dist/memory-browse-operations.js +36 -34
  137. package/dist/memory-browse.js +7 -5
  138. package/dist/namespaces/migrate.js +11 -9
  139. package/dist/namespaces/search.js +8 -6
  140. package/dist/namespaces/storage.js +10 -8
  141. package/dist/operator-doctor-corpus.js +13 -11
  142. package/dist/operator-toolkit.js +20 -18
  143. package/dist/orchestration/maintenance.js +18 -16
  144. package/dist/orchestrator.js +98 -96
  145. package/dist/qmd-daemon-session.d.ts +45 -0
  146. package/dist/qmd-daemon-session.d.ts.map +1 -0
  147. package/dist/qmd-daemon-session.js +12 -0
  148. package/dist/qmd-daemon-session.js.map +1 -0
  149. package/dist/qmd-mcp-cancel.d.ts +21 -0
  150. package/dist/qmd-mcp-cancel.d.ts.map +1 -0
  151. package/dist/qmd-mcp-cancel.js +11 -0
  152. package/dist/qmd-mcp-cancel.js.map +1 -0
  153. package/dist/qmd-preflight.d.ts +3 -1
  154. package/dist/qmd-preflight.d.ts.map +1 -1
  155. package/dist/qmd-preflight.js +3 -1
  156. package/dist/qmd.d.ts +5 -29
  157. package/dist/qmd.d.ts.map +1 -1
  158. package/dist/qmd.js +6 -2
  159. package/dist/recall-navigation-operations.js +36 -34
  160. package/dist/recall-navigation.js +35 -33
  161. package/dist/recall-state-view-admission.js +7 -5
  162. package/dist/recall-why-service.js +7 -5
  163. package/dist/resume-bundles.js +12 -10
  164. package/dist/search/factory.js +7 -5
  165. package/dist/search/index.js +11 -9
  166. package/dist/semantic-consolidation.js +11 -9
  167. package/dist/semantic-rule-promotion.js +10 -8
  168. package/dist/semantic-rule-verifier.js +10 -8
  169. package/dist/source-agent-qualifier.js +13 -11
  170. package/dist/standup/build.js +10 -8
  171. package/dist/storage.js +9 -7
  172. package/dist/support-passport/index.js +38 -36
  173. package/dist/transfer/backup.js +2 -2
  174. package/dist/transfer/capsule-export.js +2 -2
  175. package/dist/transfer/capsule-import.js +2 -2
  176. package/dist/transfer/export-okf.js +10 -8
  177. package/dist/verified-recall.js +10 -8
  178. package/dist/who-knows-cli.js +11 -9
  179. package/dist/who-knows.js +10 -8
  180. package/package.json +2 -2
  181. package/src/config-qmd.ts +2 -2
  182. package/src/qmd-daemon-session.ts +369 -0
  183. package/src/qmd-mcp-cancel.test.ts +408 -0
  184. package/src/qmd-mcp-cancel.ts +130 -0
  185. package/src/qmd-preflight.ts +10 -1
  186. package/src/qmd-rank-compare.test.ts +100 -0
  187. package/src/qmd.test.ts +16 -1
  188. package/src/qmd.ts +18 -297
  189. package/dist/chunk-B3OFQP5Y.js.map +0 -1
  190. /package/dist/{capsule-crypto-YO5QJ6L3.js.map → capsule-crypto-7FJQINUR.js.map} +0 -0
  191. /package/dist/{chunk-JWFTPRYD.js.map → chunk-2EZB2DL5.js.map} +0 -0
  192. /package/dist/{chunk-BXLOS5AJ.js.map → chunk-2NLLXCJG.js.map} +0 -0
  193. /package/dist/{chunk-QKCGOECM.js.map → chunk-34G4U6HS.js.map} +0 -0
  194. /package/dist/{chunk-YI6XIFQV.js.map → chunk-34TSXVQS.js.map} +0 -0
  195. /package/dist/{chunk-7YQR6XHY.js.map → chunk-3I375S4J.js.map} +0 -0
  196. /package/dist/{chunk-XQWKB6PY.js.map → chunk-3UP6NP4C.js.map} +0 -0
  197. /package/dist/{chunk-OFGTRDWX.js.map → chunk-47I2EK6G.js.map} +0 -0
  198. /package/dist/{chunk-HWGFTTPS.js.map → chunk-5FLFPTDK.js.map} +0 -0
  199. /package/dist/{chunk-LHDSCWDK.js.map → chunk-7AUC2YSU.js.map} +0 -0
  200. /package/dist/{chunk-AU43D3IT.js.map → chunk-7DB7KYSR.js.map} +0 -0
  201. /package/dist/{chunk-VDX2J7OX.js.map → chunk-7LCGFUMB.js.map} +0 -0
  202. /package/dist/{chunk-CNBGAFDY.js.map → chunk-A7V7GZ7F.js.map} +0 -0
  203. /package/dist/{chunk-SWXPR5SE.js.map → chunk-B2UCJX76.js.map} +0 -0
  204. /package/dist/{chunk-KYUVFCT2.js.map → chunk-BCTDTVSR.js.map} +0 -0
  205. /package/dist/{chunk-6WRHNA4I.js.map → chunk-BKPV47BK.js.map} +0 -0
  206. /package/dist/{chunk-QAIVTLL2.js.map → chunk-BLHPADUX.js.map} +0 -0
  207. /package/dist/{chunk-PRNR47DI.js.map → chunk-BOT276JC.js.map} +0 -0
  208. /package/dist/{chunk-O43AAJFQ.js.map → chunk-CRZ7BU6R.js.map} +0 -0
  209. /package/dist/{chunk-2OFDC3AK.js.map → chunk-DDPPV3KA.js.map} +0 -0
  210. /package/dist/{chunk-VYIBRCVW.js.map → chunk-DHQUQ34W.js.map} +0 -0
  211. /package/dist/{chunk-7NBUE5VY.js.map → chunk-DPX3J2N4.js.map} +0 -0
  212. /package/dist/{chunk-EWWK65CI.js.map → chunk-DX3ZODO3.js.map} +0 -0
  213. /package/dist/{chunk-SFDBLCZV.js.map → chunk-DYZHVVJM.js.map} +0 -0
  214. /package/dist/{chunk-B454SHPU.js.map → chunk-E7FN5N5E.js.map} +0 -0
  215. /package/dist/{chunk-AWSP3WNM.js.map → chunk-EJJMDLVB.js.map} +0 -0
  216. /package/dist/{chunk-KFHEZJQZ.js.map → chunk-EPFNPPWH.js.map} +0 -0
  217. /package/dist/{chunk-VDVHIRCK.js.map → chunk-EUYNHJTK.js.map} +0 -0
  218. /package/dist/{chunk-T32YYUT2.js.map → chunk-FB6FQT4P.js.map} +0 -0
  219. /package/dist/{chunk-XTN54NML.js.map → chunk-G3T6YMBO.js.map} +0 -0
  220. /package/dist/{chunk-JC7QQ2DJ.js.map → chunk-GS6LTJFW.js.map} +0 -0
  221. /package/dist/{chunk-WR66CTVU.js.map → chunk-GYLDYYRA.js.map} +0 -0
  222. /package/dist/{chunk-PQKZLBCJ.js.map → chunk-GZRTH3WZ.js.map} +0 -0
  223. /package/dist/{chunk-STQC2FYQ.js.map → chunk-HNU5CZ7E.js.map} +0 -0
  224. /package/dist/{chunk-E4XLFYHV.js.map → chunk-HPEONBM3.js.map} +0 -0
  225. /package/dist/{chunk-EZ3F4YIN.js.map → chunk-JLUS56YZ.js.map} +0 -0
  226. /package/dist/{chunk-J3ZJBX7I.js.map → chunk-KM2HQZR3.js.map} +0 -0
  227. /package/dist/{chunk-2MMBJE53.js.map → chunk-LI3OM3NP.js.map} +0 -0
  228. /package/dist/{chunk-MZOQ26LH.js.map → chunk-LQGX5TCI.js.map} +0 -0
  229. /package/dist/{chunk-KMN2JE4D.js.map → chunk-LTDWZ2HC.js.map} +0 -0
  230. /package/dist/{chunk-T6RQNV7E.js.map → chunk-MJ737UIA.js.map} +0 -0
  231. /package/dist/{chunk-7X7A7KVN.js.map → chunk-NLYOOGZ7.js.map} +0 -0
  232. /package/dist/{chunk-PZ2QQULY.js.map → chunk-NVZRIHW5.js.map} +0 -0
  233. /package/dist/{chunk-NT2Q6AHC.js.map → chunk-PCO3P7WJ.js.map} +0 -0
  234. /package/dist/{chunk-VO2BNAA2.js.map → chunk-PXDEIJL5.js.map} +0 -0
  235. /package/dist/{chunk-LXJZUNLX.js.map → chunk-QHHWJVVW.js.map} +0 -0
  236. /package/dist/{chunk-XLWMNDQR.js.map → chunk-QJWZJ7HL.js.map} +0 -0
  237. /package/dist/{chunk-73R4HOOK.js.map → chunk-QPG72IPU.js.map} +0 -0
  238. /package/dist/{chunk-SIGDETMB.js.map → chunk-R4NGLTUS.js.map} +0 -0
  239. /package/dist/{chunk-TRN56SPQ.js.map → chunk-R6NHHKXE.js.map} +0 -0
  240. /package/dist/{chunk-ATFFWIKL.js.map → chunk-RGGXSN5A.js.map} +0 -0
  241. /package/dist/{chunk-IOMLGJHG.js.map → chunk-RWZXVCGX.js.map} +0 -0
  242. /package/dist/{chunk-PQ7EB5AD.js.map → chunk-S3BB34NI.js.map} +0 -0
  243. /package/dist/{chunk-QX3K3INR.js.map → chunk-SBBZXDVJ.js.map} +0 -0
  244. /package/dist/{chunk-G5I5ZT6O.js.map → chunk-SFDKLEIY.js.map} +0 -0
  245. /package/dist/{chunk-TXTRHF3B.js.map → chunk-TVPDF6CZ.js.map} +0 -0
  246. /package/dist/{chunk-A6WNTVA7.js.map → chunk-UP3XXGEN.js.map} +0 -0
  247. /package/dist/{chunk-S2GR3T7W.js.map → chunk-UT7WE7RM.js.map} +0 -0
  248. /package/dist/{chunk-BKVCTTEN.js.map → chunk-V3NKVYUD.js.map} +0 -0
  249. /package/dist/{chunk-CGBE3N7T.js.map → chunk-VH76UQK3.js.map} +0 -0
  250. /package/dist/{chunk-Z6EZCN6Z.js.map → chunk-VKQI47DJ.js.map} +0 -0
  251. /package/dist/{chunk-KV7LFOPF.js.map → chunk-VSPBXHGR.js.map} +0 -0
  252. /package/dist/{chunk-ZRUC7FD3.js.map → chunk-VXCTQ3B3.js.map} +0 -0
  253. /package/dist/{chunk-QUNCLKHM.js.map → chunk-WIVBNNA3.js.map} +0 -0
  254. /package/dist/{chunk-OWV6LKNZ.js.map → chunk-WWUFQ3AG.js.map} +0 -0
  255. /package/dist/{chunk-DQEMWVMT.js.map → chunk-X7Y7WX73.js.map} +0 -0
  256. /package/dist/{chunk-GQ6ZF4LD.js.map → chunk-XG4XXI66.js.map} +0 -0
  257. /package/dist/{chunk-ISX7GVZE.js.map → chunk-YRULQW5J.js.map} +0 -0
  258. /package/dist/{chunk-VV2MVHCJ.js.map → chunk-YX5F4V7H.js.map} +0 -0
  259. /package/dist/{chunk-JRDL3FGM.js.map → chunk-YY5FM5M7.js.map} +0 -0
package/src/qmd.test.ts CHANGED
@@ -14,6 +14,7 @@ import {
14
14
  resolveQmdCapabilities,
15
15
  QmdClient,
16
16
  shouldAutoUpgradeQmd,
17
+ autoUpgradeInstallsStockPackage,
17
18
  } from "./qmd.js";
18
19
 
19
20
  test("parseQmdVersion extracts semantic version from qmd output", () => {
@@ -62,6 +63,10 @@ test("resolveQmdCapabilities gates qmd 2.5 features by installed version", () =>
62
63
  assert.equal(v251.doctor, true);
63
64
  assert.equal(v251.outputFormatFlag, false);
64
65
 
66
+ const v283 = resolveQmdCapabilities("qmd 2.8.3");
67
+ assert.equal(v283.outputFormatFlag, true);
68
+ assert.equal(v283.doctor, true);
69
+
65
70
  const v20 = resolveQmdCapabilities("qmd 2.0.0");
66
71
  assert.equal(v20.stableSdk, true);
67
72
  assert.equal(v20.unifiedSearch, true);
@@ -124,11 +129,21 @@ test("buildDefaultStructuredSearches returns empty for blank queries under any s
124
129
  assert.deepEqual(buildDefaultStructuredSearches(" ", undefined, "lex"), []);
125
130
  });
126
131
 
132
+ test("auto-upgrade never installs stock npm for versions that need the patched build", () => {
133
+ assert.equal(autoUpgradeInstallsStockPackage("2.5.3"), true);
134
+ assert.equal(autoUpgradeInstallsStockPackage("2.8.2"), true);
135
+ assert.equal(autoUpgradeInstallsStockPackage("2.8.3"), false);
136
+ assert.equal(autoUpgradeInstallsStockPackage("2.9.0"), false);
137
+ });
138
+
127
139
  test("shouldAutoUpgradeQmd only upgrades below Remnic supported version", () => {
128
140
  assert.equal(shouldAutoUpgradeQmd("qmd 2.1.0", "2.5.3"), true);
129
141
  assert.equal(shouldAutoUpgradeQmd("qmd 2.5.3", "2.5.3"), false);
130
142
  assert.equal(shouldAutoUpgradeQmd("qmd 2.6.0", "2.5.3"), false);
131
143
  assert.equal(shouldAutoUpgradeQmd("not installed", "2.5.3"), false);
144
+ assert.equal(shouldAutoUpgradeQmd("qmd 2.5.3", "2.8.3"), true);
145
+ assert.equal(shouldAutoUpgradeQmd("qmd 2.8.2", "2.8.3"), true);
146
+ assert.equal(shouldAutoUpgradeQmd("qmd 2.8.3", "2.8.3"), false);
132
147
  });
133
148
 
134
149
  test("getQmdCommandName preserves write command detection behind qmd 2.5 index prefix", () => {
@@ -476,7 +491,7 @@ test("QmdClient auto-upgrade throttle key is scoped by qmd target", async () =>
476
491
 
477
492
  test("parseConfig exposes qmd 2.5 integration defaults and opt-in auto upgrade", () => {
478
493
  const defaults = parseConfig({});
479
- assert.equal(defaults.qmdSupportedVersion, "2.5.3");
494
+ assert.equal(defaults.qmdSupportedVersion, "2.8.3");
480
495
  assert.equal(defaults.qmdAutoUpgradeEnabled, false);
481
496
  assert.equal(defaults.qmdChunkStrategy, "auto");
482
497
  assert.equal(defaults.qmdQueryRerankEnabled, true);
package/src/qmd.ts CHANGED
@@ -4,6 +4,8 @@ import path from "node:path";
4
4
  import { abortError, isAbortError, throwIfAborted } from "./abort-error.js";
5
5
  import { log } from "./logger.js";
6
6
  import { clearQmdResultCaches, getCachedQmdSearch, setCachedQmdSearch } from "./memory-cache.js";
7
+ import { QmdDaemonSession } from "./qmd-daemon-session.js";
8
+ import { createInflightJoiner } from "./qmd-mcp-cancel.js";
7
9
  import {
8
10
  QMD_PROBE_RETRY_BACKOFF_MS,
9
11
  QMD_PROBE_TIMEOUT_MS,
@@ -17,6 +19,7 @@ import {
17
19
  qmdVersionToString,
18
20
  resolveQmdCapabilities,
19
21
  shouldAutoUpgradeQmd,
22
+ autoUpgradeInstallsStockPackage,
20
23
  versionAtLeast,
21
24
  } from "./qmd-preflight.js";
22
25
  import { EMPTY_QMD_STATUS, type QmdStatusReport, embedQmdFiles, fetchQmdStatus } from "./qmd-status.js";
@@ -40,6 +43,7 @@ export {
40
43
  QMD_SUPPORTED_VERSION,
41
44
  resolveQmdCapabilities,
42
45
  shouldAutoUpgradeQmd,
46
+ autoUpgradeInstallsStockPackage,
43
47
  versionAtLeast,
44
48
  };
45
49
 
@@ -664,302 +668,6 @@ function killBoundedChild(child: CommandChildProcess): void {
664
668
 
665
669
  export { runCommandWithTimeout as runCommandWithTimeoutForTest };
666
670
 
667
- // ---------------------------------------------------------------------------
668
- // QMD Stdio Daemon Session (MCP over stdio child process)
669
- // ---------------------------------------------------------------------------
670
-
671
- let nextJsonRpcId = 1;
672
-
673
- class QmdDaemonSession {
674
- private child: CommandChildProcess | null = null;
675
- private initialized = false;
676
- private buffer = "";
677
- private startPromise: Promise<boolean> | null = null;
678
- private pendingRequests = new Map<
679
- number,
680
- {
681
- resolve: (value: unknown) => void;
682
- reject: (reason: Error) => void;
683
- timer: ReturnType<typeof setTimeout>;
684
- cleanup: () => void;
685
- }
686
- >();
687
- private readonly qmdPath: string;
688
- private readonly runtimeEnv: QmdRuntimeEnv;
689
- private readonly indexName?: string;
690
-
691
- constructor(qmdPath: string, runtimeEnv: QmdRuntimeEnv = {}, indexName?: string) {
692
- this.qmdPath = qmdPath;
693
- this.runtimeEnv = runtimeEnv;
694
- this.indexName = indexName?.trim() || undefined;
695
- }
696
-
697
- /** Spawn the qmd mcp child process and perform MCP handshake. */
698
- async start(): Promise<boolean> {
699
- if (this.child && !this.child.killed && this.initialized) {
700
- return true;
701
- }
702
- if (this.startPromise) {
703
- return this.startPromise;
704
- }
705
- this.startPromise = (async () => {
706
- // Reuse already-running uninitialized process to avoid zombie accumulation.
707
- const processAlreadyRunning = this.child != null && !this.child.killed;
708
- if (!processAlreadyRunning) {
709
- if (this.child) {
710
- this.cleanup({ killChild: true });
711
- }
712
- try {
713
- const args = this.indexName ? ["--index", this.indexName, "mcp"] : ["mcp"];
714
- const child = launchProcess(this.qmdPath, args, {
715
- env: mergeEnv({ NO_COLOR: "1", ...this.runtimeEnv }),
716
- stdio: ["pipe", "pipe", "pipe"],
717
- });
718
- this.child = child;
719
- this.buffer = "";
720
-
721
- child.stdout?.on("data", (data: Buffer) => {
722
- if (this.child !== child) return;
723
- this.handleStdoutData(data);
724
- });
725
- child.stderr?.on("data", (data: Buffer) => {
726
- if (this.child !== child) return;
727
- const msg = data.toString().trim();
728
- if (msg) log.debug(`QMD mcp stderr: ${stripControlChars(msg)}`);
729
- });
730
- child.stdin?.on("error", (err) => {
731
- // Swallow EPIPE/ERR_STREAM_DESTROYED from killed child processes.
732
- log.debug(`QMD mcp stdin error (suppressed): ${err.message}`);
733
- });
734
- child.on("error", (err) => {
735
- if (this.child !== child) return;
736
- log.debug(`QMD mcp process error: ${err.message}`);
737
- this.cleanup({ child });
738
- });
739
- child.on("close", (code) => {
740
- if (this.child !== child) return;
741
- log.debug(`QMD mcp process exited (code ${code})`);
742
- this.cleanup({ child });
743
- });
744
- } catch (err) {
745
- log.debug(`QMD mcp: failed to spawn process: ${err}`);
746
- this.cleanup({ killChild: true });
747
- return false;
748
- }
749
- } else {
750
- log.debug("QMD mcp: process already running, retrying handshake");
751
- }
752
-
753
- try {
754
- // Use a generous timeout — large collections (75K+ files) can take 60-90s
755
- // to load their vector index. We keep the process alive across retries so
756
- // only one mcp instance is running at a time.
757
- const result = await this.sendRequest(
758
- "initialize",
759
- {
760
- protocolVersion: "2024-11-05",
761
- capabilities: {},
762
- clientInfo: { name: "openclaw-remnic", version: "1.0.0" },
763
- },
764
- 60_000
765
- );
766
- if (!result) {
767
- // Null result (non-timeout failure) — kill and let the next probe respawn.
768
- this.cleanup({ killChild: true });
769
- return false;
770
- }
771
- this.sendNotification("notifications/initialized");
772
- this.initialized = true;
773
- log.info("QMD mcp: stdio session initialized");
774
- return true;
775
- } catch (err) {
776
- const msg = err instanceof Error ? err.message : String(err);
777
- if (/timed out/i.test(msg)) {
778
- // Handshake timeout — process is still loading. Keep it alive for the
779
- // next retry (daemonRecheckIntervalMs). Do NOT kill and respawn.
780
- log.debug(`QMD mcp: handshake timed out — process still loading, will retry later`);
781
- // Reset initialized flag but leave child running.
782
- this.initialized = false;
783
- } else {
784
- log.debug(`QMD mcp: failed to start stdio session: ${err}`);
785
- this.cleanup({ killChild: true });
786
- }
787
- return false;
788
- } finally {
789
- this.startPromise = null;
790
- }
791
- })();
792
- return this.startPromise;
793
- }
794
-
795
- /** Call an MCP tool and return the parsed result. */
796
- async callTool(
797
- name: string,
798
- args: Record<string, unknown>,
799
- timeoutMs = 30_000,
800
- signal?: AbortSignal
801
- ): Promise<unknown> {
802
- if (!this.child || this.child.killed || !this.initialized) {
803
- throw new Error("QMD mcp process not running");
804
- }
805
- return this.sendRequest("tools/call", { name, arguments: args }, timeoutMs, signal);
806
- }
807
-
808
- /** Kill stdio process and clear state so the next probe can restart. */
809
- invalidate(): void {
810
- this.cleanup({ killChild: true });
811
- }
812
-
813
- /** Kill stdio process and wait briefly for the child handle to close. */
814
- async close(timeoutMs = 1_000): Promise<void> {
815
- const target = this.child;
816
- if (!target) {
817
- this.cleanup({ killChild: true });
818
- return;
819
- }
820
-
821
- let closed = false;
822
- const closedPromise = new Promise<void>((resolve) => {
823
- target.once("close", () => {
824
- closed = true;
825
- resolve();
826
- });
827
- });
828
-
829
- this.cleanup({ killChild: true });
830
- await Promise.race([closedPromise, sleep(timeoutMs)]);
831
- if (!closed) {
832
- try {
833
- target.kill("SIGKILL");
834
- } catch {
835
- // Ignore process-kill races during shutdown.
836
- }
837
- await Promise.race([closedPromise, sleep(250)]);
838
- }
839
- }
840
-
841
- isActive(): boolean {
842
- return this.child !== null && !this.child.killed && this.initialized;
843
- }
844
-
845
- /** True while the process is spawned but the MCP handshake has not yet completed. */
846
- isLoading(): boolean {
847
- return this.child !== null && !this.child.killed && !this.initialized;
848
- }
849
-
850
- private sendRequest(
851
- method: string,
852
- params: Record<string, unknown>,
853
- timeoutMs: number,
854
- signal?: AbortSignal
855
- ): Promise<unknown> {
856
- return new Promise((resolve, reject) => {
857
- throwIfAborted(signal, `QMD mcp ${method} aborted before request`);
858
- if (!this.child || !this.child.stdin || this.child.killed) {
859
- reject(new Error("QMD mcp process not available"));
860
- return;
861
- }
862
-
863
- const id = nextJsonRpcId++;
864
- const timer = setTimeout(() => {
865
- this.pendingRequests.delete(id);
866
- cleanup();
867
- reject(new Error(`QMD mcp ${method} timed out after ${timeoutMs}ms`));
868
- }, timeoutMs);
869
- const onAbort = () => {
870
- clearTimeout(timer);
871
- this.pendingRequests.delete(id);
872
- cleanup();
873
- reject(abortError(`QMD mcp ${method} aborted`));
874
- };
875
- const cleanup = () => {
876
- signal?.removeEventListener("abort", onAbort);
877
- };
878
-
879
- this.pendingRequests.set(id, { resolve, reject, timer, cleanup });
880
- signal?.addEventListener("abort", onAbort, { once: true });
881
- const message = JSON.stringify({ jsonrpc: "2.0", id, method, params }) + "\n";
882
- this.child.stdin.write(message, (err) => {
883
- if (err) {
884
- clearTimeout(timer);
885
- this.pendingRequests.delete(id);
886
- cleanup();
887
- reject(new Error(`Failed to write to QMD mcp stdin: ${err.message}`));
888
- }
889
- });
890
- });
891
- }
892
-
893
- private sendNotification(method: string, params?: Record<string, unknown>): void {
894
- if (!this.child || !this.child.stdin || this.child.killed) return;
895
- if (this.child.stdin.destroyed) return;
896
- const msg: Record<string, unknown> = { jsonrpc: "2.0", method };
897
- if (params) msg.params = params;
898
- try {
899
- this.child.stdin.write(JSON.stringify(msg) + "\n");
900
- } catch {
901
- // Ignore EPIPE / write-after-close
902
- }
903
- }
904
-
905
- private handleStdoutData(data: Buffer): void {
906
- this.buffer += data.toString();
907
- let newlineIdx: number;
908
- while ((newlineIdx = this.buffer.indexOf("\n")) !== -1) {
909
- const line = this.buffer.slice(0, newlineIdx).trim();
910
- this.buffer = this.buffer.slice(newlineIdx + 1);
911
- if (!line) continue;
912
- try {
913
- const msg = JSON.parse(line);
914
- this.handleMessage(msg);
915
- } catch {
916
- log.debug(`QMD mcp: unparseable stdout: ${truncateForLog(line, 200)}`);
917
- }
918
- }
919
- }
920
-
921
- private handleMessage(msg: Record<string, unknown>): void {
922
- if (msg.id !== undefined && msg.id !== null) {
923
- const pending = this.pendingRequests.get(msg.id as number);
924
- if (pending) {
925
- clearTimeout(pending.timer);
926
- this.pendingRequests.delete(msg.id as number);
927
- pending.cleanup();
928
- if (msg.error) {
929
- pending.reject(new Error(JSON.stringify(msg.error)));
930
- } else {
931
- pending.resolve(msg.result);
932
- }
933
- }
934
- return;
935
- }
936
- if (msg.method) {
937
- log.debug(`QMD mcp notification: ${msg.method}`);
938
- }
939
- }
940
-
941
- private cleanup(opts?: { killChild?: boolean; child?: CommandChildProcess | null }): void {
942
- const target = opts?.child ?? this.child;
943
- if (!target) return;
944
- if (opts?.child && this.child !== opts.child) {
945
- return;
946
- }
947
- if (opts?.killChild && !target.killed) {
948
- target.kill("SIGTERM");
949
- }
950
- this.initialized = false;
951
- for (const [, pending] of this.pendingRequests) {
952
- clearTimeout(pending.timer);
953
- pending.cleanup();
954
- pending.reject(new Error("QMD mcp process terminated"));
955
- }
956
- this.pendingRequests.clear();
957
- this.startPromise = null;
958
- this.child = null;
959
- this.buffer = "";
960
- }
961
- }
962
-
963
671
  /** Matches `#<hex-docid> <score>% <rest-of-line>` — rest is split in a second pass. */
964
672
  const QMD_RESULT_LINE_RE = /^#([0-9a-fA-F]+)\s+(\d+)%\s+(.+)/;
965
673
 
@@ -1188,6 +896,8 @@ export class QmdClient implements SearchBackend {
1188
896
 
1189
897
  // Daemon mode fields
1190
898
  private daemonSession: QmdDaemonSession | null = null;
899
+ /** Identical in-flight search() calls share one daemon query. Cancel fires only when every waiter aborts. */
900
+ private readonly daemonSearchJoiner = createInflightJoiner<QmdSearchResult[] | null>();
1191
901
  private daemonAvailable = false;
1192
902
  private daemonSessionPath: string | null = null;
1193
903
  private lastDaemonCheckAtMs = 0;
@@ -1525,6 +1235,15 @@ export class QmdClient implements SearchBackend {
1525
1235
  return;
1526
1236
  }
1527
1237
 
1238
+ if (!autoUpgradeInstallsStockPackage(this.qmdSupportedVersion)) {
1239
+ const status = `skipped: ${this.qmdSupportedVersion} needs the pinned patched build, not stock npm`;
1240
+ recordAutoUpgradeStatus(state, targetKey, status);
1241
+ log.warn(
1242
+ `QMD auto-upgrade skipped: ${QMD_PACKAGE_NAME}@${this.qmdSupportedVersion} from npm lacks the patches Remnic needs and would migrate the index before a backup; follow docs/qmd-2.8.3.md.`
1243
+ );
1244
+ return;
1245
+ }
1246
+
1528
1247
  if (signal?.aborted) return;
1529
1248
  const packageSpec = `${QMD_PACKAGE_NAME}@${this.qmdSupportedVersion}`;
1530
1249
  try {
@@ -1956,7 +1675,9 @@ export class QmdClient implements SearchBackend {
1956
1675
  if (this.daemonAvailable) {
1957
1676
  let results: QmdSearchResult[] | null;
1958
1677
  try {
1959
- results = await this.searchViaDaemon(trimmed, col, n, searchOptions, execution?.signal);
1678
+ results = await this.daemonSearchJoiner.join(cacheKey, execution?.signal, (sharedSignal) =>
1679
+ this.searchViaDaemon(trimmed, col, n, searchOptions, sharedSignal)
1680
+ );
1960
1681
  } catch (err) {
1961
1682
  if (isCallerCancellation(err, execution?.signal)) {
1962
1683
  throw isAbortError(err) ? err : abortError("QMD daemon search aborted");