@remnic/core 9.3.771 → 9.4.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 (491) hide show
  1. package/dist/access-admin-ops-surface.d.ts +5 -5
  2. package/dist/access-admin-ops-surface.js +36 -35
  3. package/dist/access-boundary.d.ts +5 -5
  4. package/dist/access-boundary.js +37 -36
  5. package/dist/access-cli.js +109 -108
  6. package/dist/access-cli.js.map +1 -1
  7. package/dist/access-http.d.ts +5 -5
  8. package/dist/access-http.js +48 -47
  9. package/dist/access-identity-continuity-surface.d.ts +4 -4
  10. package/dist/access-identity-continuity-surface.js +36 -35
  11. package/dist/access-lcm-surface.d.ts +5 -5
  12. package/dist/access-lcm-surface.js +36 -35
  13. package/dist/access-mcp.d.ts +5 -5
  14. package/dist/access-mcp.js +44 -43
  15. package/dist/access-observe-write-surface.d.ts +5 -5
  16. package/dist/access-observe-write-surface.js +36 -35
  17. package/dist/access-operations-batch.js +41 -40
  18. package/dist/access-operations.d.ts +5 -5
  19. package/dist/access-operations.js +43 -42
  20. package/dist/access-recall-surface.d.ts +5 -5
  21. package/dist/access-recall-surface.js +36 -35
  22. package/dist/access-schema.js +3 -3
  23. package/dist/{access-service-CdW6B2qQ.d.ts → access-service-m-2VO_Ig.d.ts} +3 -3
  24. package/dist/access-service.d.ts +5 -5
  25. package/dist/access-service.js +36 -35
  26. package/dist/access-surface-catalog.d.ts +5 -5
  27. package/dist/action-confidence.d.ts +1 -1
  28. package/dist/active-memory-bridge.d.ts +1 -1
  29. package/dist/active-recall.d.ts +1 -1
  30. package/dist/active-recall.js +2 -2
  31. package/dist/adapters/index.js +4 -4
  32. package/dist/adapters/registry.js +2 -2
  33. package/dist/{auto-sync-2SOUW4JW.js → auto-sync-HMHQHUAG.js} +9 -9
  34. package/dist/behavior-learner.d.ts +1 -1
  35. package/dist/behavior-signals.d.ts +1 -1
  36. package/dist/bootstrap.d.ts +4 -4
  37. package/dist/bootstrap.js +2 -2
  38. package/dist/boxes.js +2 -2
  39. package/dist/briefing.d.ts +1 -1
  40. package/dist/briefing.js +12 -12
  41. package/dist/buffer-surprise-report.d.ts +1 -1
  42. package/dist/buffer.d.ts +1 -1
  43. package/dist/buffer.js +2 -2
  44. package/dist/calibration.d.ts +1 -1
  45. package/dist/calibration.js +4 -4
  46. package/dist/capabilities.d.ts +1 -1
  47. package/dist/{catalog-bflYNWsM.d.ts → catalog-BxWokdC2.d.ts} +1 -1
  48. package/dist/causal-behavior.d.ts +1 -1
  49. package/dist/causal-behavior.js +4 -4
  50. package/dist/causal-chain.js +4 -4
  51. package/dist/causal-consolidation.d.ts +1 -1
  52. package/dist/causal-consolidation.js +17 -17
  53. package/dist/causal-retrieval.js +4 -4
  54. package/dist/causal-trajectory-graph.d.ts +1 -1
  55. package/dist/causal-trajectory-graph.js +1 -1
  56. package/dist/causal-trajectory.js +1 -1
  57. package/dist/{chunk-PSNMICC2.js → chunk-27FLVMDC.js} +14 -14
  58. package/dist/{chunk-7FL4CNPV.js → chunk-2A3OXAP2.js} +2 -2
  59. package/dist/{chunk-U5HD7BB2.js → chunk-2FOD2YY3.js} +10 -10
  60. package/dist/{chunk-GG6AJN7A.js → chunk-2IZAGAJR.js} +2 -2
  61. package/dist/{chunk-6Y4JTNX7.js → chunk-2MR3MFQB.js} +2 -2
  62. package/dist/{chunk-AU7Q3LSC.js → chunk-2QSZNTDO.js} +4 -4
  63. package/dist/{chunk-IBAU2RZN.js → chunk-2U2A5HF4.js} +11 -5
  64. package/dist/chunk-2U2A5HF4.js.map +1 -0
  65. package/dist/chunk-37CTGERM.js +62 -0
  66. package/dist/chunk-37CTGERM.js.map +1 -0
  67. package/dist/{chunk-MYNRJGOY.js → chunk-3F4N4WDH.js} +76 -111
  68. package/dist/chunk-3F4N4WDH.js.map +1 -0
  69. package/dist/{chunk-7OSULYN2.js → chunk-4BFRBP45.js} +2 -2
  70. package/dist/{chunk-DQC3ZZYM.js → chunk-4KJLYTLS.js} +2 -2
  71. package/dist/{chunk-DMKMQTBH.js → chunk-4P4626RY.js} +5 -5
  72. package/dist/{chunk-GY3SKOS4.js → chunk-5EZXHU36.js} +2 -2
  73. package/dist/{chunk-OW4UXZNP.js → chunk-5QZDMSSN.js} +61 -61
  74. package/dist/chunk-64UDOIMI.js +121 -0
  75. package/dist/chunk-64UDOIMI.js.map +1 -0
  76. package/dist/{chunk-OTMAYEY5.js → chunk-66FLU5BT.js} +3 -3
  77. package/dist/{chunk-J2QYB2D5.js → chunk-6BISDEN6.js} +7 -7
  78. package/dist/{chunk-CXBFYSQY.js → chunk-6ZIETXZ2.js} +3 -3
  79. package/dist/{chunk-KYYL4U6X.js → chunk-7N2RUBAP.js} +3 -3
  80. package/dist/{chunk-U3TRHUSJ.js → chunk-7QWMTOIF.js} +45 -45
  81. package/dist/{chunk-L24JROPR.js → chunk-7WSLR2CU.js} +2 -2
  82. package/dist/{chunk-T4AWNIXJ.js → chunk-7Z2DZNWN.js} +18 -9
  83. package/dist/{chunk-T4AWNIXJ.js.map → chunk-7Z2DZNWN.js.map} +1 -1
  84. package/dist/{chunk-EXM3CQTZ.js → chunk-A3GOMRJG.js} +2 -2
  85. package/dist/{chunk-DCWIQFNA.js → chunk-AKUCU7CI.js} +7 -7
  86. package/dist/{chunk-XHYGJVXL.js → chunk-AXTXN4T6.js} +2 -2
  87. package/dist/{chunk-L42FA4BU.js → chunk-BGTAL46Y.js} +2 -2
  88. package/dist/{chunk-5QANTTY2.js → chunk-BRDJ2HFP.js} +2 -2
  89. package/dist/{chunk-7VFZTJ7K.js → chunk-BV2TIZ4F.js} +2 -2
  90. package/dist/{chunk-QMN3CIFS.js → chunk-CGS7UKWM.js} +2 -2
  91. package/dist/{chunk-LZ73Y56P.js → chunk-CLX5VDNY.js} +8 -8
  92. package/dist/{chunk-KYC3RLYJ.js → chunk-CXLNZXG5.js} +1 -1
  93. package/dist/{chunk-YOELDDBF.js → chunk-CZAA5N5S.js} +4 -4
  94. package/dist/{chunk-XG4NBBRW.js → chunk-CZAZX7JP.js} +5 -5
  95. package/dist/{chunk-QOGXUNWL.js → chunk-CZGIIADK.js} +7 -7
  96. package/dist/{chunk-QRDOSYOR.js → chunk-DBRYEIGY.js} +2 -2
  97. package/dist/{chunk-6QODJKOV.js → chunk-DGYCWCQ7.js} +3 -3
  98. package/dist/{chunk-RFZW7NID.js → chunk-DR6PEJU3.js} +4 -4
  99. package/dist/{chunk-UC4YOAC2.js → chunk-E5BK6CGV.js} +2 -2
  100. package/dist/{chunk-TKZ3AL5V.js → chunk-EHK6KZHK.js} +2 -2
  101. package/dist/{chunk-X5NUL5N4.js → chunk-EPGWWCZF.js} +3 -3
  102. package/dist/{chunk-JZ7P26GF.js → chunk-F53UF7CI.js} +2 -2
  103. package/dist/{chunk-SJHM6I4J.js → chunk-FC77VUX5.js} +2 -2
  104. package/dist/{chunk-DKTSR7EK.js → chunk-FDPZVY6D.js} +2 -2
  105. package/dist/{chunk-OUXPVWTZ.js → chunk-FLVL4L3L.js} +5 -5
  106. package/dist/{chunk-ZI3YYOOV.js → chunk-FZGGZAAU.js} +2 -2
  107. package/dist/{chunk-TQT3USCG.js → chunk-HG32URJJ.js} +2 -2
  108. package/dist/{chunk-ZQNCHPTZ.js → chunk-HLTAPHZZ.js} +2 -2
  109. package/dist/{chunk-LU7ATMRV.js → chunk-HRCACVHL.js} +3 -3
  110. package/dist/{chunk-LOPZ2DWR.js → chunk-I73G4UH7.js} +2 -2
  111. package/dist/{chunk-MJE4XV4A.js → chunk-IC6QX5TC.js} +2 -2
  112. package/dist/{chunk-27TJRC2Y.js → chunk-ILFJ7AVS.js} +7 -7
  113. package/dist/{chunk-VUA4S7P6.js → chunk-JIKJPDQJ.js} +4 -4
  114. package/dist/{chunk-BKTC7JCA.js → chunk-JLR3JSTL.js} +3 -3
  115. package/dist/{chunk-VQ34TERH.js → chunk-JZHHREBL.js} +2 -2
  116. package/dist/{chunk-IQVQJJL7.js → chunk-K2ZLHESQ.js} +2 -2
  117. package/dist/{chunk-PWFWCGOO.js → chunk-KAWTOYAW.js} +2 -2
  118. package/dist/{chunk-YRZMCPC5.js → chunk-KCJ5H6XQ.js} +4 -4
  119. package/dist/{chunk-DJECGBBM.js → chunk-KQDNAXOM.js} +2 -2
  120. package/dist/{chunk-WIWPSQYU.js → chunk-KQPJLK3X.js} +2 -2
  121. package/dist/{chunk-XNWLD3RR.js → chunk-LOR6ZM5R.js} +3 -3
  122. package/dist/{chunk-EGLUVV6B.js → chunk-M7GGMGMZ.js} +10 -10
  123. package/dist/{chunk-YTU7WKYN.js → chunk-MNUHL34L.js} +3 -3
  124. package/dist/{chunk-ZCWIH4LH.js → chunk-MRHFJV44.js} +2 -2
  125. package/dist/{chunk-W4H5A3TJ.js → chunk-MTR7BZQN.js} +3 -3
  126. package/dist/{chunk-PNLCEFE4.js → chunk-MTWKDOVO.js} +2 -2
  127. package/dist/{chunk-TECYUPFB.js → chunk-NG7YBCJO.js} +4 -4
  128. package/dist/{chunk-OSMBC3JU.js → chunk-O2EL7EGG.js} +2 -2
  129. package/dist/{chunk-HW5EF6LV.js → chunk-O7BBFJLP.js} +2 -2
  130. package/dist/{chunk-EHQ5HO5T.js → chunk-OBMR4VIX.js} +1 -1
  131. package/dist/{chunk-VFHDUFH5.js → chunk-OHDJ34CC.js} +2 -2
  132. package/dist/{chunk-6SHAUM5S.js → chunk-OUMTBFSQ.js} +4 -4
  133. package/dist/{chunk-27CQIO7T.js → chunk-P6SYWE4G.js} +57 -10
  134. package/dist/chunk-P6SYWE4G.js.map +1 -0
  135. package/dist/{chunk-EEKDRAWX.js → chunk-PRTA6444.js} +2 -2
  136. package/dist/{chunk-IQ7WCZRW.js → chunk-PUBTHW5O.js} +3 -3
  137. package/dist/{chunk-AGNBY3VG.js → chunk-PYHOAXTI.js} +2 -2
  138. package/dist/{chunk-UUH4YQOF.js → chunk-QLULYKWZ.js} +2 -2
  139. package/dist/{chunk-DBSMLRTO.js → chunk-QT2RZNRT.js} +2 -2
  140. package/dist/{chunk-HM6UJPPO.js → chunk-QWGNDWKB.js} +2 -2
  141. package/dist/{chunk-KCQA46NR.js → chunk-R5VAVVHP.js} +2 -2
  142. package/dist/{chunk-SXN3LCUT.js → chunk-RHOZ5LLO.js} +100 -4
  143. package/dist/chunk-RHOZ5LLO.js.map +1 -0
  144. package/dist/{chunk-6KYMPV2O.js → chunk-RL6NEVXT.js} +45 -2
  145. package/dist/chunk-RL6NEVXT.js.map +1 -0
  146. package/dist/{chunk-O7GOFAM3.js → chunk-RP7YXA67.js} +2 -2
  147. package/dist/{chunk-BVKCV2ZY.js → chunk-SMX5267P.js} +2 -2
  148. package/dist/{chunk-XBZQRZ6G.js → chunk-TN7THW5U.js} +2 -2
  149. package/dist/{chunk-JRZV3767.js → chunk-UI4FVU6T.js} +2 -2
  150. package/dist/{chunk-VGUOEDTU.js → chunk-V3UE5I5F.js} +2 -2
  151. package/dist/{chunk-7WV3F5DQ.js → chunk-V7IZKJI3.js} +2 -2
  152. package/dist/{chunk-VL7DP3OW.js → chunk-VFSP73LP.js} +2 -2
  153. package/dist/{chunk-C2DDH5UN.js → chunk-X4A62ET7.js} +14 -14
  154. package/dist/{chunk-WRBDUNSW.js → chunk-XN3TUUX2.js} +3 -3
  155. package/dist/{chunk-NNL4LJAD.js → chunk-XZ5I7OZR.js} +5 -5
  156. package/dist/{chunk-K2I3AWBR.js → chunk-YDSWRD33.js} +5 -5
  157. package/dist/{chunk-3NN73CM7.js → chunk-YFBTVOMB.js} +3 -3
  158. package/dist/{chunk-44YXWE35.js → chunk-YPEMNNNY.js} +2 -2
  159. package/dist/{chunk-ZZMRXJFY.js → chunk-ZIDSD6VC.js} +2 -2
  160. package/dist/{chunk-BMANIB5B.js → chunk-ZPOROUTX.js} +3 -3
  161. package/dist/{cli-Dfnc66gs.d.ts → cli-EiBBOt3r.d.ts} +3 -3
  162. package/dist/cli.d.ts +6 -6
  163. package/dist/cli.js +74 -73
  164. package/dist/compounding/engine.d.ts +1 -1
  165. package/dist/compounding/engine.js +13 -13
  166. package/dist/compounding/preference-consolidator.d.ts +1 -1
  167. package/dist/compounding/preference-consolidator.js +1 -1
  168. package/dist/compression-optimizer.d.ts +1 -1
  169. package/dist/config.d.ts +1 -1
  170. package/dist/config.js +2 -2
  171. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  172. package/dist/connectors/codex-materialize-runner.js +13 -13
  173. package/dist/connectors/codex-materialize.d.ts +1 -1
  174. package/dist/connectors/codex-materialize.js +2 -2
  175. package/dist/connectors/index.d.ts +1 -1
  176. package/dist/connectors/index.js +14 -14
  177. package/dist/consolidation-provenance-check.d.ts +1 -1
  178. package/dist/consolidation-undo.d.ts +1 -1
  179. package/dist/contradiction/index.d.ts +1 -1
  180. package/dist/contradiction/index.js +3 -3
  181. package/dist/{contradiction-scan-3FJYWS3G.js → contradiction-scan-SSKCAMLX.js} +3 -3
  182. package/dist/conversation-index/backend.d.ts +1 -1
  183. package/dist/conversation-index/backend.js +5 -5
  184. package/dist/conversation-index/chunker.d.ts +1 -1
  185. package/dist/conversation-index/cleanup.js +2 -2
  186. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  187. package/dist/conversation-index/faiss-adapter.js +2 -2
  188. package/dist/conversation-index/indexer.d.ts +1 -1
  189. package/dist/conversation-index/indexer.js +2 -2
  190. package/dist/conversation-index/search.d.ts +1 -1
  191. package/dist/conversation-index/search.js +2 -2
  192. package/dist/day-summary.d.ts +1 -1
  193. package/dist/day-summary.js +2 -2
  194. package/dist/delinearize.d.ts +1 -1
  195. package/dist/direct-answer-wiring.d.ts +1 -1
  196. package/dist/direct-answer.d.ts +1 -1
  197. package/dist/embedding-fallback.d.ts +1 -1
  198. package/dist/embedding-fallback.js +2 -2
  199. package/dist/enrichment/index.d.ts +1 -1
  200. package/dist/entity-retrieval.d.ts +1 -1
  201. package/dist/entity-retrieval.js +13 -13
  202. package/dist/entity-schema.d.ts +1 -1
  203. package/dist/explicit-capture.d.ts +4 -4
  204. package/dist/extraction-faithfulness.d.ts +1 -1
  205. package/dist/extraction-faithfulness.js +5 -5
  206. package/dist/extraction-judge-telemetry.d.ts +1 -1
  207. package/dist/extraction-judge-telemetry.js +2 -2
  208. package/dist/extraction-judge-training.d.ts +1 -1
  209. package/dist/extraction-judge-training.js +2 -2
  210. package/dist/extraction-judge.d.ts +1 -1
  211. package/dist/extraction-judge.js +5 -5
  212. package/dist/extraction.d.ts +1 -1
  213. package/dist/extraction.js +9 -9
  214. package/dist/fallback-llm.d.ts +1 -1
  215. package/dist/fallback-llm.js +4 -4
  216. package/dist/{forget-OEE5OELK.js → forget-KHF7A44H.js} +3 -3
  217. package/dist/graph-dashboard-diff.d.ts +1 -1
  218. package/dist/graph-dashboard-key.d.ts +1 -1
  219. package/dist/graph-dashboard-parser.d.ts +1 -1
  220. package/dist/{graph-edge-decay-RXUCJIN4.js → graph-edge-decay-FO7AM4UR.js} +3 -3
  221. package/dist/graph-edge-reinforcement.d.ts +1 -1
  222. package/dist/graph-snapshot.d.ts +1 -1
  223. package/dist/graph-snapshot.js +2 -2
  224. package/dist/graph.d.ts +1 -1
  225. package/dist/graph.js +1 -1
  226. package/dist/identity-continuity.d.ts +1 -1
  227. package/dist/importance.d.ts +1 -1
  228. package/dist/index.d.ts +17 -12
  229. package/dist/index.js +124 -123
  230. package/dist/intent.d.ts +1 -1
  231. package/dist/lcm/archive.js +2 -2
  232. package/dist/lcm/engine.d.ts +1 -1
  233. package/dist/lcm/engine.js +7 -7
  234. package/dist/lcm/index.d.ts +1 -1
  235. package/dist/lcm/index.js +9 -9
  236. package/dist/lcm/schema.js +3 -3
  237. package/dist/lcm/summarizer.js +3 -3
  238. package/dist/lcm/tools.d.ts +1 -1
  239. package/dist/lifecycle.d.ts +1 -1
  240. package/dist/live-connectors-runner.d.ts +1 -1
  241. package/dist/local-llm.d.ts +1 -1
  242. package/dist/local-llm.js +2 -2
  243. package/dist/local-model-endpoint.d.ts +1 -1
  244. package/dist/logger.d.ts +8 -2
  245. package/dist/logger.js +1 -1
  246. package/dist/maintenance/memory-governance.d.ts +1 -1
  247. package/dist/maintenance/memory-governance.js +12 -12
  248. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +12 -12
  249. package/dist/maintenance/rebuild-memory-projection.js +14 -14
  250. package/dist/mcp-memory-inspector-app.d.ts +5 -5
  251. package/dist/memory-action-policy.d.ts +1 -1
  252. package/dist/memory-cache.d.ts +1 -1
  253. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  254. package/dist/memory-projection-store.d.ts +23 -3
  255. package/dist/memory-projection-store.js +9 -2
  256. package/dist/memory-provenance.d.ts +1 -1
  257. package/dist/memory-worth-outcomes.d.ts +1 -1
  258. package/dist/model-registry.js +2 -2
  259. package/dist/models-json.d.ts +1 -1
  260. package/dist/models-json.js +2 -2
  261. package/dist/namespaces/migrate.d.ts +2 -2
  262. package/dist/namespaces/migrate.js +27 -26
  263. package/dist/namespaces/principal.d.ts +1 -1
  264. package/dist/namespaces/search.d.ts +1 -1
  265. package/dist/namespaces/search.js +15 -14
  266. package/dist/namespaces/storage.d.ts +2 -2
  267. package/dist/namespaces/storage.js +12 -12
  268. package/dist/native-knowledge.d.ts +1 -1
  269. package/dist/native-knowledge.js +2 -2
  270. package/dist/negative.js +2 -2
  271. package/dist/operator-toolkit.d.ts +11 -2
  272. package/dist/operator-toolkit.js +36 -33
  273. package/dist/orchestration/compression-guideline-coordinator.d.ts +1 -1
  274. package/dist/orchestration/compression-guideline-coordinator.js +2 -2
  275. package/dist/orchestration/maintenance.d.ts +2 -2
  276. package/dist/orchestration/maintenance.js +14 -14
  277. package/dist/{orchestrator-Y9wyG4jK.d.ts → orchestrator-B2Y28Z9t.d.ts} +3 -3
  278. package/dist/orchestrator.d.ts +4 -4
  279. package/dist/orchestrator.js +109 -108
  280. package/dist/patterns-cli.d.ts +1 -1
  281. package/dist/policy-runtime.d.ts +1 -1
  282. package/dist/profiling.js +2 -2
  283. package/dist/provenance.d.ts +1 -1
  284. package/dist/{purge-IHRX4Z7X.js → purge-NDWV6WYD.js} +4 -3
  285. package/dist/{purge-IHRX4Z7X.js.map → purge-NDWV6WYD.js.map} +1 -1
  286. package/dist/qmd-Db9mOkzB.d.ts +330 -0
  287. package/dist/qmd-preflight.d.ts +5 -0
  288. package/dist/qmd-preflight.js +31 -0
  289. package/dist/qmd-recall-cache.d.ts +1 -1
  290. package/dist/qmd.d.ts +3 -305
  291. package/dist/qmd.js +11 -9
  292. package/dist/recall-disclosure-escalation.d.ts +1 -1
  293. package/dist/recall-explain-renderer.d.ts +1 -1
  294. package/dist/recall-planner-llm.d.ts +1 -1
  295. package/dist/recall-planner-llm.js +4 -4
  296. package/dist/recall-qos.js +2 -2
  297. package/dist/recall-state.d.ts +1 -1
  298. package/dist/recall-state.js +2 -2
  299. package/dist/recall-tag-filter.d.ts +1 -1
  300. package/dist/recall-timings.d.ts +1 -1
  301. package/dist/recall-xray-cli.d.ts +1 -1
  302. package/dist/recall-xray-renderer.d.ts +1 -1
  303. package/dist/recall-xray.d.ts +1 -1
  304. package/dist/relevance.js +2 -2
  305. package/dist/{resolution-33PIX3TT.js → resolution-VH4NGENZ.js} +3 -3
  306. package/dist/resolution-VH4NGENZ.js.map +1 -0
  307. package/dist/resolve-auth-token.d.ts +1 -1
  308. package/dist/resolve-provider-secret.js +2 -2
  309. package/dist/resume-bundles.js +4 -4
  310. package/dist/retrieval-agents.d.ts +2 -2
  311. package/dist/retrieval-agents.js +2 -2
  312. package/dist/retrieval-tiers.d.ts +1 -1
  313. package/dist/routing/engine.d.ts +1 -1
  314. package/dist/routing/store.d.ts +1 -1
  315. package/dist/routing/store.js +2 -2
  316. package/dist/runtime/better-sqlite.d.ts +17 -1
  317. package/dist/runtime/better-sqlite.js +5 -3
  318. package/dist/schemas.d.ts +22 -22
  319. package/dist/search/embed-helper.d.ts +1 -1
  320. package/dist/search/embed-helper.js +2 -2
  321. package/dist/search/factory.d.ts +1 -1
  322. package/dist/search/factory.js +14 -13
  323. package/dist/search/index.d.ts +1 -1
  324. package/dist/search/index.js +18 -17
  325. package/dist/search/lancedb-backend.d.ts +1 -1
  326. package/dist/search/lancedb-backend.js +3 -3
  327. package/dist/search/meilisearch-backend.d.ts +1 -1
  328. package/dist/search/meilisearch-backend.js +3 -3
  329. package/dist/search/noop-backend.d.ts +1 -1
  330. package/dist/search/orama-backend.d.ts +1 -1
  331. package/dist/search/orama-backend.js +3 -3
  332. package/dist/search/port.d.ts +1 -1
  333. package/dist/search/remote-backend.d.ts +1 -1
  334. package/dist/search/remote-backend.js +2 -2
  335. package/dist/{semantic-consolidation-bfXJNKVf.d.ts → semantic-consolidation-BDVIbLRw.d.ts} +1 -1
  336. package/dist/semantic-consolidation.d.ts +2 -2
  337. package/dist/semantic-consolidation.js +14 -14
  338. package/dist/semantic-rule-promotion.js +12 -12
  339. package/dist/semantic-rule-verifier.d.ts +1 -1
  340. package/dist/semantic-rule-verifier.js +12 -12
  341. package/dist/session-observer-bands.d.ts +1 -1
  342. package/dist/session-observer-state.d.ts +1 -1
  343. package/dist/session-observer-state.js +2 -2
  344. package/dist/session-transcript-migration.js +3 -3
  345. package/dist/shared-context/manager.d.ts +1 -1
  346. package/dist/shared-context/manager.js +2 -2
  347. package/dist/signal.d.ts +1 -1
  348. package/dist/storage-guards.js +2 -2
  349. package/dist/storage.d.ts +1 -1
  350. package/dist/storage.js +11 -11
  351. package/dist/summarizer.d.ts +1 -1
  352. package/dist/summarizer.js +7 -7
  353. package/dist/summary-snapshot.d.ts +1 -1
  354. package/dist/temporal-supersession.d.ts +1 -1
  355. package/dist/temporal-supersession.js +2 -2
  356. package/dist/temporal-validity.d.ts +1 -1
  357. package/dist/threading.d.ts +1 -1
  358. package/dist/threading.js +2 -2
  359. package/dist/tier-migration.d.ts +1 -1
  360. package/dist/tier-routing.d.ts +1 -1
  361. package/dist/topics.d.ts +1 -1
  362. package/dist/transcript.d.ts +1 -1
  363. package/dist/transcript.js +2 -2
  364. package/dist/transfer/autodetect.js +1 -1
  365. package/dist/transfer/backup.js +1 -1
  366. package/dist/transfer/capsule-export.js +2 -2
  367. package/dist/transfer/export-sqlite.js +2 -2
  368. package/dist/transfer/import-sqlite.js +2 -2
  369. package/dist/transfer/types.d.ts +12 -12
  370. package/dist/trust-score-stage.d.ts +1 -1
  371. package/dist/trust-score.d.ts +1 -1
  372. package/dist/{types-D1iBqhJA.d.ts → types-ljkd82rn.d.ts} +13 -1
  373. package/dist/types.d.ts +1 -1
  374. package/dist/utility-runtime.d.ts +1 -1
  375. package/dist/verified-recall.js +13 -13
  376. package/package.json +2 -2
  377. package/src/logger.test.ts +120 -0
  378. package/src/logger.ts +37 -9
  379. package/src/memory-projection-open-failure.test.ts +322 -0
  380. package/src/memory-projection-store.ts +179 -2
  381. package/src/operator-toolkit.ts +64 -0
  382. package/src/qmd-preflight.test.ts +197 -0
  383. package/src/qmd-preflight.ts +167 -0
  384. package/src/qmd.ts +115 -129
  385. package/src/runtime/better-sqlite.test.ts +54 -0
  386. package/src/runtime/better-sqlite.ts +83 -3
  387. package/src/wearables/cleanup.test.ts +56 -0
  388. package/src/wearables/cleanup.ts +22 -1
  389. package/src/wearables/config.test.ts +25 -0
  390. package/src/wearables/config.ts +31 -4
  391. package/src/wearables/types.ts +12 -1
  392. package/dist/chunk-27CQIO7T.js.map +0 -1
  393. package/dist/chunk-6KYMPV2O.js.map +0 -1
  394. package/dist/chunk-IBAU2RZN.js.map +0 -1
  395. package/dist/chunk-MYNRJGOY.js.map +0 -1
  396. package/dist/chunk-NU3CSQ4H.js +0 -48
  397. package/dist/chunk-NU3CSQ4H.js.map +0 -1
  398. package/dist/chunk-SXN3LCUT.js.map +0 -1
  399. /package/dist/{auto-sync-2SOUW4JW.js.map → auto-sync-HMHQHUAG.js.map} +0 -0
  400. /package/dist/{chunk-PSNMICC2.js.map → chunk-27FLVMDC.js.map} +0 -0
  401. /package/dist/{chunk-7FL4CNPV.js.map → chunk-2A3OXAP2.js.map} +0 -0
  402. /package/dist/{chunk-U5HD7BB2.js.map → chunk-2FOD2YY3.js.map} +0 -0
  403. /package/dist/{chunk-GG6AJN7A.js.map → chunk-2IZAGAJR.js.map} +0 -0
  404. /package/dist/{chunk-6Y4JTNX7.js.map → chunk-2MR3MFQB.js.map} +0 -0
  405. /package/dist/{chunk-AU7Q3LSC.js.map → chunk-2QSZNTDO.js.map} +0 -0
  406. /package/dist/{chunk-7OSULYN2.js.map → chunk-4BFRBP45.js.map} +0 -0
  407. /package/dist/{chunk-DQC3ZZYM.js.map → chunk-4KJLYTLS.js.map} +0 -0
  408. /package/dist/{chunk-DMKMQTBH.js.map → chunk-4P4626RY.js.map} +0 -0
  409. /package/dist/{chunk-GY3SKOS4.js.map → chunk-5EZXHU36.js.map} +0 -0
  410. /package/dist/{chunk-OW4UXZNP.js.map → chunk-5QZDMSSN.js.map} +0 -0
  411. /package/dist/{chunk-OTMAYEY5.js.map → chunk-66FLU5BT.js.map} +0 -0
  412. /package/dist/{chunk-J2QYB2D5.js.map → chunk-6BISDEN6.js.map} +0 -0
  413. /package/dist/{chunk-CXBFYSQY.js.map → chunk-6ZIETXZ2.js.map} +0 -0
  414. /package/dist/{chunk-KYYL4U6X.js.map → chunk-7N2RUBAP.js.map} +0 -0
  415. /package/dist/{chunk-U3TRHUSJ.js.map → chunk-7QWMTOIF.js.map} +0 -0
  416. /package/dist/{chunk-L24JROPR.js.map → chunk-7WSLR2CU.js.map} +0 -0
  417. /package/dist/{chunk-EXM3CQTZ.js.map → chunk-A3GOMRJG.js.map} +0 -0
  418. /package/dist/{chunk-DCWIQFNA.js.map → chunk-AKUCU7CI.js.map} +0 -0
  419. /package/dist/{chunk-XHYGJVXL.js.map → chunk-AXTXN4T6.js.map} +0 -0
  420. /package/dist/{chunk-L42FA4BU.js.map → chunk-BGTAL46Y.js.map} +0 -0
  421. /package/dist/{chunk-5QANTTY2.js.map → chunk-BRDJ2HFP.js.map} +0 -0
  422. /package/dist/{chunk-7VFZTJ7K.js.map → chunk-BV2TIZ4F.js.map} +0 -0
  423. /package/dist/{chunk-QMN3CIFS.js.map → chunk-CGS7UKWM.js.map} +0 -0
  424. /package/dist/{chunk-LZ73Y56P.js.map → chunk-CLX5VDNY.js.map} +0 -0
  425. /package/dist/{chunk-KYC3RLYJ.js.map → chunk-CXLNZXG5.js.map} +0 -0
  426. /package/dist/{chunk-YOELDDBF.js.map → chunk-CZAA5N5S.js.map} +0 -0
  427. /package/dist/{chunk-XG4NBBRW.js.map → chunk-CZAZX7JP.js.map} +0 -0
  428. /package/dist/{chunk-QOGXUNWL.js.map → chunk-CZGIIADK.js.map} +0 -0
  429. /package/dist/{chunk-QRDOSYOR.js.map → chunk-DBRYEIGY.js.map} +0 -0
  430. /package/dist/{chunk-6QODJKOV.js.map → chunk-DGYCWCQ7.js.map} +0 -0
  431. /package/dist/{chunk-RFZW7NID.js.map → chunk-DR6PEJU3.js.map} +0 -0
  432. /package/dist/{chunk-UC4YOAC2.js.map → chunk-E5BK6CGV.js.map} +0 -0
  433. /package/dist/{chunk-TKZ3AL5V.js.map → chunk-EHK6KZHK.js.map} +0 -0
  434. /package/dist/{chunk-X5NUL5N4.js.map → chunk-EPGWWCZF.js.map} +0 -0
  435. /package/dist/{chunk-JZ7P26GF.js.map → chunk-F53UF7CI.js.map} +0 -0
  436. /package/dist/{chunk-SJHM6I4J.js.map → chunk-FC77VUX5.js.map} +0 -0
  437. /package/dist/{chunk-DKTSR7EK.js.map → chunk-FDPZVY6D.js.map} +0 -0
  438. /package/dist/{chunk-OUXPVWTZ.js.map → chunk-FLVL4L3L.js.map} +0 -0
  439. /package/dist/{chunk-ZI3YYOOV.js.map → chunk-FZGGZAAU.js.map} +0 -0
  440. /package/dist/{chunk-TQT3USCG.js.map → chunk-HG32URJJ.js.map} +0 -0
  441. /package/dist/{chunk-ZQNCHPTZ.js.map → chunk-HLTAPHZZ.js.map} +0 -0
  442. /package/dist/{chunk-LU7ATMRV.js.map → chunk-HRCACVHL.js.map} +0 -0
  443. /package/dist/{chunk-LOPZ2DWR.js.map → chunk-I73G4UH7.js.map} +0 -0
  444. /package/dist/{chunk-MJE4XV4A.js.map → chunk-IC6QX5TC.js.map} +0 -0
  445. /package/dist/{chunk-27TJRC2Y.js.map → chunk-ILFJ7AVS.js.map} +0 -0
  446. /package/dist/{chunk-VUA4S7P6.js.map → chunk-JIKJPDQJ.js.map} +0 -0
  447. /package/dist/{chunk-BKTC7JCA.js.map → chunk-JLR3JSTL.js.map} +0 -0
  448. /package/dist/{chunk-VQ34TERH.js.map → chunk-JZHHREBL.js.map} +0 -0
  449. /package/dist/{chunk-IQVQJJL7.js.map → chunk-K2ZLHESQ.js.map} +0 -0
  450. /package/dist/{chunk-PWFWCGOO.js.map → chunk-KAWTOYAW.js.map} +0 -0
  451. /package/dist/{chunk-YRZMCPC5.js.map → chunk-KCJ5H6XQ.js.map} +0 -0
  452. /package/dist/{chunk-DJECGBBM.js.map → chunk-KQDNAXOM.js.map} +0 -0
  453. /package/dist/{chunk-WIWPSQYU.js.map → chunk-KQPJLK3X.js.map} +0 -0
  454. /package/dist/{chunk-XNWLD3RR.js.map → chunk-LOR6ZM5R.js.map} +0 -0
  455. /package/dist/{chunk-EGLUVV6B.js.map → chunk-M7GGMGMZ.js.map} +0 -0
  456. /package/dist/{chunk-YTU7WKYN.js.map → chunk-MNUHL34L.js.map} +0 -0
  457. /package/dist/{chunk-ZCWIH4LH.js.map → chunk-MRHFJV44.js.map} +0 -0
  458. /package/dist/{chunk-W4H5A3TJ.js.map → chunk-MTR7BZQN.js.map} +0 -0
  459. /package/dist/{chunk-PNLCEFE4.js.map → chunk-MTWKDOVO.js.map} +0 -0
  460. /package/dist/{chunk-TECYUPFB.js.map → chunk-NG7YBCJO.js.map} +0 -0
  461. /package/dist/{chunk-OSMBC3JU.js.map → chunk-O2EL7EGG.js.map} +0 -0
  462. /package/dist/{chunk-HW5EF6LV.js.map → chunk-O7BBFJLP.js.map} +0 -0
  463. /package/dist/{chunk-EHQ5HO5T.js.map → chunk-OBMR4VIX.js.map} +0 -0
  464. /package/dist/{chunk-VFHDUFH5.js.map → chunk-OHDJ34CC.js.map} +0 -0
  465. /package/dist/{chunk-6SHAUM5S.js.map → chunk-OUMTBFSQ.js.map} +0 -0
  466. /package/dist/{chunk-EEKDRAWX.js.map → chunk-PRTA6444.js.map} +0 -0
  467. /package/dist/{chunk-IQ7WCZRW.js.map → chunk-PUBTHW5O.js.map} +0 -0
  468. /package/dist/{chunk-AGNBY3VG.js.map → chunk-PYHOAXTI.js.map} +0 -0
  469. /package/dist/{chunk-UUH4YQOF.js.map → chunk-QLULYKWZ.js.map} +0 -0
  470. /package/dist/{chunk-DBSMLRTO.js.map → chunk-QT2RZNRT.js.map} +0 -0
  471. /package/dist/{chunk-HM6UJPPO.js.map → chunk-QWGNDWKB.js.map} +0 -0
  472. /package/dist/{chunk-KCQA46NR.js.map → chunk-R5VAVVHP.js.map} +0 -0
  473. /package/dist/{chunk-O7GOFAM3.js.map → chunk-RP7YXA67.js.map} +0 -0
  474. /package/dist/{chunk-BVKCV2ZY.js.map → chunk-SMX5267P.js.map} +0 -0
  475. /package/dist/{chunk-XBZQRZ6G.js.map → chunk-TN7THW5U.js.map} +0 -0
  476. /package/dist/{chunk-JRZV3767.js.map → chunk-UI4FVU6T.js.map} +0 -0
  477. /package/dist/{chunk-VGUOEDTU.js.map → chunk-V3UE5I5F.js.map} +0 -0
  478. /package/dist/{chunk-7WV3F5DQ.js.map → chunk-V7IZKJI3.js.map} +0 -0
  479. /package/dist/{chunk-VL7DP3OW.js.map → chunk-VFSP73LP.js.map} +0 -0
  480. /package/dist/{chunk-C2DDH5UN.js.map → chunk-X4A62ET7.js.map} +0 -0
  481. /package/dist/{chunk-WRBDUNSW.js.map → chunk-XN3TUUX2.js.map} +0 -0
  482. /package/dist/{chunk-NNL4LJAD.js.map → chunk-XZ5I7OZR.js.map} +0 -0
  483. /package/dist/{chunk-K2I3AWBR.js.map → chunk-YDSWRD33.js.map} +0 -0
  484. /package/dist/{chunk-3NN73CM7.js.map → chunk-YFBTVOMB.js.map} +0 -0
  485. /package/dist/{chunk-44YXWE35.js.map → chunk-YPEMNNNY.js.map} +0 -0
  486. /package/dist/{chunk-ZZMRXJFY.js.map → chunk-ZIDSD6VC.js.map} +0 -0
  487. /package/dist/{chunk-BMANIB5B.js.map → chunk-ZPOROUTX.js.map} +0 -0
  488. /package/dist/{contradiction-scan-3FJYWS3G.js.map → contradiction-scan-SSKCAMLX.js.map} +0 -0
  489. /package/dist/{forget-OEE5OELK.js.map → forget-KHF7A44H.js.map} +0 -0
  490. /package/dist/{graph-edge-decay-RXUCJIN4.js.map → graph-edge-decay-FO7AM4UR.js.map} +0 -0
  491. /package/dist/{resolution-33PIX3TT.js.map → qmd-preflight.js.map} +0 -0
package/src/qmd.ts CHANGED
@@ -18,6 +18,33 @@ import {
18
18
  } from "./search/port.js";
19
19
  import { launchProcess, type CommandChildProcess } from "./runtime/child-process.js";
20
20
  import { mergeEnv } from "./runtime/env.js";
21
+ import {
22
+ classifyProbeFailure,
23
+ compareQmdVersions,
24
+ getQmdPostInstallProbeTargets,
25
+ parseQmdVersion,
26
+ parseQmdVersionOutput,
27
+ QMD_PROBE_RETRY_BACKOFF_MS,
28
+ QMD_PROBE_TIMEOUT_MS,
29
+ QMD_SUPPORTED_VERSION,
30
+ qmdVersionToString,
31
+ resolveQmdCapabilities,
32
+ shouldAutoUpgradeQmd,
33
+ versionAtLeast,
34
+ type QmdProbeFailureKind,
35
+ } from "./qmd-preflight.js";
36
+ // Re-export version-check / probe-preflight helpers (moved to qmd-preflight.ts,
37
+ // issue #1841) so existing imports from "./qmd.js" keep resolving.
38
+ export {
39
+ compareQmdVersions,
40
+ getQmdPostInstallProbeTargets,
41
+ parseQmdVersion,
42
+ parseQmdVersionOutput,
43
+ QMD_SUPPORTED_VERSION,
44
+ resolveQmdCapabilities,
45
+ shouldAutoUpgradeQmd,
46
+ versionAtLeast,
47
+ };
21
48
 
22
49
  export interface QmdClientOptions {
23
50
  slowLog?: { enabled: boolean; thresholdMs: number };
@@ -133,11 +160,9 @@ const QMD_TIMEOUT_MS = 30_000;
133
160
  // `qmdDaemonTimeoutMs` config knob (issue #1335), e.g. to give CPU-only HyDE
134
161
  // queries more headroom. The effective value lives in `this.daemonTimeoutMs`.
135
162
  const QMD_DAEMON_TIMEOUT_MS = 8_000;
136
- const QMD_PROBE_TIMEOUT_MS = 8_000;
137
163
  const QMD_UPDATE_BACKOFF_MS = 15 * 60 * 1000; // 15m
138
164
  const QMD_EMBED_BACKOFF_MS = 60 * 60 * 1000; // 60m
139
165
  const QMD_CLI_WARN_THROTTLE_MS = 15 * 60 * 1000; // 15m
140
- export const QMD_SUPPORTED_VERSION = "2.5.3";
141
166
  const QMD_PACKAGE_NAME = "@tobilu/qmd";
142
167
  const QMD_AUTO_UPGRADE_TIMEOUT_MS = 120_000;
143
168
  const QMD_AUTO_UPGRADE_CHECK_INTERVAL_MS = 24 * 60 * 60_000;
@@ -269,118 +294,6 @@ function isVectorDimensionMismatchError(err: unknown): boolean {
269
294
  );
270
295
  }
271
296
 
272
- export function parseQmdVersion(version: string | null): QmdVersionTuple | null {
273
- if (!version) return null;
274
- const match = version.match(/v?(\d{1,10})\.(\d{1,10})\.(\d{1,10})/i);
275
- if (!match) return null;
276
- return [
277
- Number.parseInt(match[1] ?? "0", 10),
278
- Number.parseInt(match[2] ?? "0", 10),
279
- Number.parseInt(match[3] ?? "0", 10),
280
- ];
281
- }
282
-
283
- export function parseQmdVersionOutput(stdout: string, stderr: string): string | null {
284
- const lines = `${stdout}\n${stderr}`
285
- .split("\n")
286
- .map((s) => s.trim())
287
- .filter((s) => s.length > 0);
288
- if (lines.length === 0) return null;
289
- const semanticLines = lines.filter((line) => parseQmdVersion(line) !== null);
290
- if (semanticLines.length === 0) return lines[0] ?? null;
291
- return semanticLines.find((line) => /\bqmd\b/i.test(line)) ?? semanticLines[0] ?? null;
292
- }
293
-
294
- export function compareQmdVersions(
295
- left: QmdVersionTuple | null,
296
- right: QmdVersionTuple | null,
297
- ): number {
298
- if (!left && !right) return 0;
299
- if (!left) return -1;
300
- if (!right) return 1;
301
- for (let i = 0; i < 3; i += 1) {
302
- if ((left[i] ?? 0) > (right[i] ?? 0)) return 1;
303
- if ((left[i] ?? 0) < (right[i] ?? 0)) return -1;
304
- }
305
- return 0;
306
- }
307
-
308
- export function versionAtLeast(
309
- current: QmdVersionTuple | null,
310
- target: QmdVersionTuple,
311
- ): boolean {
312
- return compareQmdVersions(current, target) >= 0;
313
- }
314
-
315
- export function resolveQmdCapabilities(version: string | null): QmdCapabilities {
316
- const parsedVersion = parseQmdVersion(version);
317
- const atLeast = (target: QmdVersionTuple): boolean => versionAtLeast(parsedVersion, target);
318
- return {
319
- version,
320
- parsedVersion,
321
- stableSdk: atLeast([2, 0, 0]),
322
- unifiedSearch: atLeast([2, 0, 0]),
323
- getDocumentBody: atLeast([2, 0, 0]),
324
- maintenanceApi: atLeast([2, 0, 0]),
325
- legacySkillInstall: atLeast([2, 0, 1]),
326
- intentHints: atLeast([1, 1, 5]),
327
- explainTraces: atLeast([1, 1, 2]),
328
- candidateLimit: atLeast([1, 1, 2]),
329
- v2McpQueryTool: atLeast([2, 0, 0]),
330
- structuredSearches: atLeast([2, 0, 0]),
331
- queryRerankToggle: atLeast([2, 1, 0]),
332
- chunkStrategy: atLeast([2, 1, 0]),
333
- qmdBench: atLeast([2, 1, 0]),
334
- perCollectionModels: atLeast([2, 1, 0]),
335
- jsonLineNumbers: atLeast([2, 1, 0]),
336
- editorLinks: atLeast([2, 1, 0]),
337
- doctor: atLeast([2, 5, 0]),
338
- versionedSkills: atLeast([2, 5, 0]),
339
- absoluteSnippetLines: atLeast([2, 5, 0]),
340
- fullQueryOutput: atLeast([2, 5, 0]),
341
- forceCpu: atLeast([2, 5, 0]),
342
- gpuBackendOverride: atLeast([2, 5, 0]),
343
- embedParallelism: atLeast([2, 5, 0]),
344
- modelEnvConsistency: atLeast([2, 5, 0]),
345
- scopedEmbed: atLeast([2, 5, 0]),
346
- safeStatusDeviceProbe: atLeast([2, 5, 0]),
347
- mcpIndexSelection: atLeast([2, 5, 0]),
348
- outputFormatFlag: atLeast([2, 5, 3]),
349
- };
350
- }
351
-
352
- export function shouldAutoUpgradeQmd(
353
- installedVersion: string | null,
354
- supportedVersion: string = QMD_SUPPORTED_VERSION,
355
- ): boolean {
356
- const installed = parseQmdVersion(installedVersion);
357
- const supported = parseQmdVersion(supportedVersion);
358
- if (!installed || !supported) return false;
359
- return compareQmdVersions(installed, supported) < 0;
360
- }
361
-
362
- export function getQmdPostInstallProbeTargets(
363
- qmdPath: string,
364
- qmdPathSource: "configured" | "auto-path" | "auto-fallback",
365
- ): Array<{ qmdPath: string; source: "auto-path" | "auto-fallback" }> {
366
- const targets: Array<{ qmdPath: string; source: "auto-path" | "auto-fallback" }> = [
367
- { qmdPath: "qmd", source: "auto-path" },
368
- ];
369
- const normalizedPath = qmdPath.trim();
370
- if (
371
- qmdPathSource === "auto-fallback" &&
372
- normalizedPath.length > 0 &&
373
- normalizedPath !== "qmd"
374
- ) {
375
- targets.push({ qmdPath: normalizedPath, source: "auto-fallback" });
376
- }
377
- return targets;
378
- }
379
-
380
- function qmdVersionToString(version: QmdVersionTuple): string {
381
- return `${version[0]}.${version[1]}.${version[2]}`;
382
- }
383
-
384
297
  function normalizeSearchOptions(options?: SearchQueryOptions): SearchQueryOptions | undefined {
385
298
  if (!options) return undefined;
386
299
  const intent = typeof options.intent === "string" ? options.intent.trim() : "";
@@ -671,7 +584,13 @@ function runCommandWithTimeout(
671
584
  settled = true;
672
585
  cleanup();
673
586
  child.kill("SIGKILL");
674
- reject(new Error(`${label} timed out after ${options.timeoutMs}ms`));
587
+ // Flag the deadline breach so classifyProbeFailure can tell a genuine
588
+ // timeout from a non-zero-exit error whose message merely embeds stderr.
589
+ reject(
590
+ Object.assign(new Error(`${label} timed out after ${options.timeoutMs}ms`), {
591
+ timedOut: true as const,
592
+ }),
593
+ );
675
594
  }, options.timeoutMs);
676
595
  const onAbort = () => {
677
596
  if (settled) return;
@@ -1437,6 +1356,18 @@ export class QmdClient implements SearchBackend {
1437
1356
  }
1438
1357
  }
1439
1358
 
1359
+ /**
1360
+ * Run a single `qmd --version` probe against `qmdPath`. Extracted as its own
1361
+ * method so tests can inject a fake probe runner that exercises the preflight
1362
+ * retry/classification paths without spawning a real qmd binary. Issue #1841.
1363
+ */
1364
+ private runVersionProbe(
1365
+ qmdPath: string,
1366
+ signal?: AbortSignal,
1367
+ ): Promise<{ stdout: string; stderr: string }> {
1368
+ return runQmd(["--version"], QMD_PROBE_TIMEOUT_MS, qmdPath, signal, this.qmdRuntimeEnv);
1369
+ }
1370
+
1440
1371
  private async probeCli(
1441
1372
  options: {
1442
1373
  allowAutoUpgrade?: boolean;
@@ -1490,24 +1421,79 @@ export class QmdClient implements SearchBackend {
1490
1421
  };
1491
1422
 
1492
1423
  if (this.configuredQmdPath) {
1493
- try {
1494
- const result = await runQmd(["--version"], QMD_PROBE_TIMEOUT_MS, this.configuredQmdPath, options.signal, this.qmdRuntimeEnv);
1495
- await recordProbeSuccess(result, this.configuredQmdPath, "configured");
1496
- return true;
1497
- } catch (err) {
1498
- markProbeFailure(err);
1499
- configuredProbeFailure = this.lastCliProbeError;
1500
- // Do not hard-fail here: fall through to PATH/fallback probing.
1501
- // This keeps recall healthy even when configured path is stale.
1502
- this.logCliProbeWarning(
1503
- `QMD: configured qmdPath failed (${this.configuredQmdPath}): ${this.lastCliProbeError}`,
1504
- );
1424
+ const configuredPath = this.configuredQmdPath;
1425
+ // Retry only TRANSIENT (timeout/abort) probes of the configured path: a
1426
+ // binary that resolved and ran before is more likely slow under load than
1427
+ // gone. ENOENT/EACCES is a hard misconfiguration and must fail fast.
1428
+ // Issue #1841.
1429
+ let failureKind: QmdProbeFailureKind = "other";
1430
+ let retries = 0;
1431
+ let callerCancelled = false;
1432
+ for (let attempt = 0; attempt <= QMD_PROBE_RETRY_BACKOFF_MS.length; attempt += 1) {
1433
+ try {
1434
+ const result = await this.runVersionProbe(configuredPath, options.signal);
1435
+ await recordProbeSuccess(result, configuredPath, "configured");
1436
+ return true;
1437
+ } catch (err) {
1438
+ markProbeFailure(err);
1439
+ configuredProbeFailure = this.lastCliProbeError;
1440
+ // Detect CALLER cancellation FIRST: an aborted signal / AbortError is
1441
+ // non-actionable noise — the caller chose to stop. Other QMD paths
1442
+ // treat it via `isCallerCancellation`; do the same here so a cancelled
1443
+ // probe never reads as a transient host-load failure. Issue #1841.
1444
+ if (isCallerCancellation(err, options.signal)) {
1445
+ callerCancelled = true;
1446
+ break;
1447
+ }
1448
+ failureKind = classifyProbeFailure(err);
1449
+ // Never retry a hard misconfiguration (missing/not-executable) — only
1450
+ // transient slowness. (Caller cancellation is handled above.)
1451
+ if (
1452
+ failureKind === "transient" &&
1453
+ attempt < QMD_PROBE_RETRY_BACKOFF_MS.length
1454
+ ) {
1455
+ try {
1456
+ await sleepWithSignal(
1457
+ QMD_PROBE_RETRY_BACKOFF_MS[attempt] ?? 500,
1458
+ options.signal,
1459
+ );
1460
+ } catch {
1461
+ // Aborted mid-backoff: caller cancelled — stop, emit no warning.
1462
+ callerCancelled = true;
1463
+ break;
1464
+ }
1465
+ retries += 1;
1466
+ continue;
1467
+ }
1468
+ break;
1469
+ }
1470
+ }
1471
+ // Distinct operator-facing warnings so a slow binary is not mistaken for
1472
+ // a misconfiguration (and vice versa). Do not hard-fail here: fall through
1473
+ // to PATH/fallback probing so recall stays healthy when config is stale.
1474
+ // Caller cancellation is silent noise (issue #1841): suppress all warnings
1475
+ // for it exactly as the other QMD paths do.
1476
+ if (!callerCancelled) {
1477
+ if (failureKind === "transient") {
1478
+ this.logCliProbeWarning(
1479
+ `QMD: qmdPath ${configuredPath} version check timed out (host may be under load); retried ${retries} time${retries === 1 ? "" : "s"}`,
1480
+ );
1481
+ } else if (failureKind === "missing") {
1482
+ this.logCliProbeWarning(
1483
+ `QMD: configured qmdPath not found or not executable (${configuredPath}): ${this.lastCliProbeError}`,
1484
+ );
1485
+ } else {
1486
+ // Preserve the historical generic message for exit-code/other failures.
1487
+ this.logCliProbeWarning(
1488
+ `QMD: configured qmdPath failed (${configuredPath}): ${this.lastCliProbeError}`,
1489
+ );
1490
+ }
1505
1491
  }
1506
1492
  }
1507
1493
 
1508
1494
  // Try PATH first
1509
1495
  try {
1510
- const result = await runQmd(["--version"], QMD_PROBE_TIMEOUT_MS, "qmd", options.signal, this.qmdRuntimeEnv);
1496
+ const result = await this.runVersionProbe("qmd", options.signal);
1511
1497
  await recordProbeSuccess(result, "qmd", "auto-path");
1512
1498
  return true;
1513
1499
  } catch (err) {
@@ -1515,7 +1501,7 @@ export class QmdClient implements SearchBackend {
1515
1501
  // Try fallback paths
1516
1502
  for (const fallbackPath of this.qmdFallbackPaths) {
1517
1503
  try {
1518
- const result = await runQmd(["--version"], QMD_PROBE_TIMEOUT_MS, fallbackPath, options.signal, this.qmdRuntimeEnv);
1504
+ const result = await this.runVersionProbe(fallbackPath, options.signal);
1519
1505
  await recordProbeSuccess(result, fallbackPath, "auto-fallback");
1520
1506
  log.info(`QMD: found at ${fallbackPath}`);
1521
1507
  return true;
@@ -4,6 +4,7 @@ import {
4
4
  displayErrorDetail,
5
5
  isLikelyBetterSqlite3NativeBindingError,
6
6
  openBetterSqlite3,
7
+ probeBetterSqlite3Driver,
7
8
  } from "./better-sqlite.js";
8
9
 
9
10
  test("isLikelyBetterSqlite3NativeBindingError recognizes missing and mismatched native bindings", () => {
@@ -22,6 +23,50 @@ test("isLikelyBetterSqlite3NativeBindingError recognizes missing and mismatched
22
23
  assert.equal(isLikelyBetterSqlite3NativeBindingError(new Error("SQLITE_BUSY: database is locked")), false);
23
24
  });
24
25
 
26
+ test("isLikelyBetterSqlite3NativeBindingError walks the cause chain of a sanitized wrapper (issue #1848)", () => {
27
+ // Production path: loadBetterSqlite3() catches the ABI error and re-throws a
28
+ // sanitized unavailableError WRAPPER whose message drops the ABI markers. The
29
+ // original error survives only on .cause — the classifier must walk it, or
30
+ // the startup probe / projection doctor / browse warn all MISS the hint.
31
+ const abiCause = new Error(
32
+ "The module was compiled against a different Node.js version using NODE_MODULE_VERSION 127",
33
+ );
34
+ const wrapper = new Error(
35
+ "better-sqlite3 is unavailable. Remnic attempted to load the native SQLite binding and could not.",
36
+ { cause: abiCause },
37
+ );
38
+ assert.equal(isLikelyBetterSqlite3NativeBindingError(wrapper), true);
39
+
40
+ // Deeply nested wrapper (wrapper.cause.cause = ABI error) is still found.
41
+ const deepWrapper = new Error("outer sanitized layer", { cause: wrapper });
42
+ assert.equal(isLikelyBetterSqlite3NativeBindingError(deepWrapper), true);
43
+
44
+ // A wrapper whose cause is NOT a native-binding failure stays negative.
45
+ const benignWrapper = new Error("better-sqlite3 is unavailable.", {
46
+ cause: new Error("SQLITE_BUSY: database is locked"),
47
+ });
48
+ assert.equal(isLikelyBetterSqlite3NativeBindingError(benignWrapper), false);
49
+ });
50
+
51
+ test("isLikelyBetterSqlite3NativeBindingError inspects AggregateError.errors siblings", () => {
52
+ // Module loaders can surface failures as an AggregateError; the ABI mismatch
53
+ // may live in a sibling rather than the aggregate's own message.
54
+ const agg = new AggregateError([
55
+ new Error("some unrelated loader step"),
56
+ new Error("Could not locate the bindings file. Tried: better_sqlite3.node"),
57
+ ]);
58
+ assert.equal(isLikelyBetterSqlite3NativeBindingError(agg), true);
59
+
60
+ const benignAgg = new AggregateError([new Error("unrelated"), new Error("SQLITE_BUSY")]);
61
+ assert.equal(isLikelyBetterSqlite3NativeBindingError(benignAgg), false);
62
+ });
63
+
64
+ test("isLikelyBetterSqlite3NativeBindingError is cycle-safe on a self-referential cause", () => {
65
+ const cyclic = new Error("SQLITE_BUSY: database is locked");
66
+ cyclic.cause = cyclic; // would loop forever without a visited set
67
+ assert.equal(isLikelyBetterSqlite3NativeBindingError(cyclic), false);
68
+ });
69
+
25
70
  test("displayErrorDetail surfaces only error class + code, never the raw message (CodeQL js/stack-trace-exposure)", () => {
26
71
  // MODULE_NOT_FOUND messages embed an absolute "Require stack:" path block.
27
72
  const moduleNotFound = Object.assign(
@@ -59,3 +104,12 @@ test("openBetterSqlite3 can open an in-memory database after install verificatio
59
104
  db.close();
60
105
  }
61
106
  });
107
+
108
+ test("probeBetterSqlite3Driver succeeds (ok=true) under the verified process and warms the ctor cache", () => {
109
+ const probe = probeBetterSqlite3Driver();
110
+ assert.equal(probe.ok, true);
111
+ assert.equal(probe.detail, "");
112
+ assert.equal(probe.nativeBindingMismatch, false);
113
+ // A second probe reuses the warmed cache (no re-load); still ok.
114
+ assert.equal(probeBetterSqlite3Driver().ok, true);
115
+ });
@@ -28,6 +28,35 @@ export function openBetterSqlite3(
28
28
  return new Database(file, options);
29
29
  }
30
30
 
31
+ export interface BetterSqlite3DriverProbe {
32
+ /** true when the native binding loaded successfully under this process. */
33
+ ok: boolean;
34
+ /** Path-free detail string (class + code) from `displayErrorDetail`; "" when ok. */
35
+ detail: string;
36
+ /** true when the failure is classified as a native-binding ABI mismatch. */
37
+ nativeBindingMismatch: boolean;
38
+ }
39
+
40
+ /**
41
+ * Attempt to load the better-sqlite3 native driver under the running process
42
+ * WITHOUT opening a database. Used by the server startup check (issue #1829)
43
+ * to surface a wrong-ABI build loudly instead of letting each memory browse
44
+ * silently fall back to a full-corpus scan. Never throws — callers log the
45
+ * result. A successful probe also warms the ctor cache for later opens.
46
+ */
47
+ export function probeBetterSqlite3Driver(): BetterSqlite3DriverProbe {
48
+ try {
49
+ loadBetterSqlite3();
50
+ return { ok: true, detail: "", nativeBindingMismatch: false };
51
+ } catch (error) {
52
+ return {
53
+ ok: false,
54
+ detail: displayErrorDetail(error),
55
+ nativeBindingMismatch: isLikelyBetterSqlite3NativeBindingError(error),
56
+ };
57
+ }
58
+ }
59
+
31
60
  function requireBetterSqlite3Ctor(require: RuntimeRequire): BetterSqlite3Ctor {
32
61
  const loaded = require("better-sqlite3") as
33
62
  | BetterSqlite3Ctor
@@ -50,9 +79,49 @@ function rawErrorMessage(error: unknown): string {
50
79
  return error instanceof Error ? error.message : String(error ?? "");
51
80
  }
52
81
 
53
- export function isLikelyBetterSqlite3NativeBindingError(error: unknown): boolean {
54
- // Classify on the RAW message so redaction can't strip detection markers
55
- // (e.g. the path containing "better_sqlite3.node").
82
+ /**
83
+ * Iterate an error and every node reachable along its `cause` chain and any
84
+ * `AggregateError.errors` siblings (depth-first), cycle-safe via a visited set.
85
+ *
86
+ * Native-binding failures thrown from openBetterSqlite3 /
87
+ * probeBetterSqlite3Driver are caught and re-thrown as a sanitized
88
+ * `unavailableError` WRAPPER: the wrapper's message drops the ABI markers
89
+ * (NODE_MODULE_VERSION, better_sqlite3.node, …) that live on the ORIGINAL
90
+ * error. So classification must walk `.cause` (and aggregate siblings) instead
91
+ * of inspecting only the top wrapper's message — otherwise startup logs, browse
92
+ * warnings, and the memory_projection doctor check all MISS the native-binding
93
+ * hint (issue #1848).
94
+ */
95
+ function* errorChain(error: unknown): Generator<unknown> {
96
+ const seen = new Set<unknown>();
97
+ const stack: unknown[] = [error];
98
+ while (stack.length > 0) {
99
+ const node = stack.pop();
100
+ if (node === null || node === undefined) continue;
101
+ if (typeof node !== "object") continue;
102
+ if (seen.has(node)) continue;
103
+ seen.add(node);
104
+ yield node;
105
+ // Narrow with `in` (not a cast) so the property access is compiler-checked.
106
+ if ("cause" in node) {
107
+ const cause = node.cause;
108
+ if (cause !== null && cause !== undefined) stack.push(cause);
109
+ }
110
+ if ("errors" in node) {
111
+ const errors = node.errors;
112
+ if (Array.isArray(errors)) {
113
+ for (const member of errors) {
114
+ if (member !== null && member !== undefined) stack.push(member);
115
+ }
116
+ }
117
+ }
118
+ }
119
+ }
120
+
121
+ // True when a single error's RAW message carries a native-binding ABI marker.
122
+ // Raw (not displayErrorDetail) so redaction can't strip detection markers
123
+ // (e.g. the loader path containing "better_sqlite3.node").
124
+ function messageHasNativeBindingMarker(error: unknown): boolean {
56
125
  const detail = rawErrorMessage(error);
57
126
  return (
58
127
  detail.includes("Could not locate the bindings file") ||
@@ -63,6 +132,17 @@ export function isLikelyBetterSqlite3NativeBindingError(error: unknown): boolean
63
132
  );
64
133
  }
65
134
 
135
+ export function isLikelyBetterSqlite3NativeBindingError(error: unknown): boolean {
136
+ // Walk the full cause / aggregate chain so a SANITIZED wrapper
137
+ // (unavailableError) — whose message drops the ABI markers that live on the
138
+ // original error — is still classified. Inspecting only the top-level message
139
+ // misses the real mismatch when the failure was wrapped (issue #1848).
140
+ for (const node of errorChain(error)) {
141
+ if (messageHasNativeBindingMarker(node)) return true;
142
+ }
143
+ return false;
144
+ }
145
+
66
146
  function unavailableError(error: unknown): Error {
67
147
  const detail = displayErrorDetail(error);
68
148
  const nativeBindingHint = isLikelyBetterSqlite3NativeBindingError(error)
@@ -132,3 +132,59 @@ test("input conversation is not mutated", () => {
132
132
  cleanConversation(input, ALL_ON);
133
133
  assert.equal(JSON.stringify(input), before);
134
134
  });
135
+
136
+
137
+ test("merges consecutive same-speaker runs across diarized speakers", () => {
138
+ const result = cleanConversation(
139
+ conversation([
140
+ { speakerKey: "0", text: "Hello there.", startIso: "2026-06-10T10:00:00Z", endIso: "2026-06-10T10:00:03Z" },
141
+ { speakerKey: "0", text: "How are you?", startIso: "2026-06-10T10:00:04Z", endIso: "2026-06-10T10:00:07Z" },
142
+ { speakerKey: "1", text: "Good, thanks.", startIso: "2026-06-10T10:00:08Z", endIso: "2026-06-10T10:00:11Z" },
143
+ { speakerKey: "1", text: "And you?", startIso: "2026-06-10T10:00:12Z", endIso: "2026-06-10T10:00:14Z" },
144
+ { speakerKey: "0", text: "Busy day.", startIso: "2026-06-10T10:00:15Z", endIso: "2026-06-10T10:00:18Z" },
145
+ ]),
146
+ ALL_ON,
147
+ );
148
+ // Three runs: 0+0, 1+1, 0. Generic-label protection is off here, so
149
+ // diarized same-speaker adjacency merges within the gap.
150
+ assert.equal(result.conversation.segments.length, 3);
151
+ assert.equal(result.conversation.segments[0].text, "Hello there. How are you?");
152
+ assert.equal(result.conversation.segments[1].text, "Good, thanks. And you?");
153
+ assert.equal(result.conversation.segments[2].text, "Busy day.");
154
+ assert.equal(result.mergedSegments, 2);
155
+ });
156
+
157
+ test("preserveUtteranceBoundaries keeps generic-labeled utterances distinct (#1811)", () => {
158
+ const settings: WearableCleanupSettings = { ...ALL_ON, preserveUtteranceBoundaries: true };
159
+ const result = cleanConversation(
160
+ conversation([
161
+ { speakerKey: "unknown", text: "First.", startIso: "2026-06-10T10:00:00Z", endIso: "2026-06-10T10:00:02Z" },
162
+ { speakerKey: "unknown", text: "Second.", startIso: "2026-06-10T10:00:03Z", endIso: "2026-06-10T10:00:05Z" },
163
+ { speakerKey: "Unknown", text: "Third.", startIso: "2026-06-10T10:00:06Z", endIso: "2026-06-10T10:00:08Z" },
164
+ { speakerKey: "0", text: "Diarized A.", startIso: "2026-06-10T10:00:09Z", endIso: "2026-06-10T10:00:11Z" },
165
+ { speakerKey: "0", text: "Diarized B.", startIso: "2026-06-10T10:00:12Z", endIso: "2026-06-10T10:00:14Z" },
166
+ ]),
167
+ settings,
168
+ );
169
+ // Generic "unknown"/"Unknown" utterances are NOT merged into one block.
170
+ assert.equal(result.conversation.segments.length, 4);
171
+ assert.deepEqual(
172
+ result.conversation.segments.map((segment) => segment.text),
173
+ ["First.", "Second.", "Third.", "Diarized A. Diarized B."],
174
+ );
175
+ assert.equal(result.mergedSegments, 1);
176
+ });
177
+
178
+ test("preserveUtteranceBoundaries default (off) still collapses generic labels", () => {
179
+ // The flag is opt-in: without it the legacy merge-everything behavior
180
+ // is unchanged for sources that never set it.
181
+ const result = cleanConversation(
182
+ conversation([
183
+ { speakerKey: "unknown", text: "First.", startIso: "2026-06-10T10:00:00Z", endIso: "2026-06-10T10:00:02Z" },
184
+ { speakerKey: "unknown", text: "Second.", startIso: "2026-06-10T10:00:03Z", endIso: "2026-06-10T10:00:05Z" },
185
+ ]),
186
+ ALL_ON,
187
+ );
188
+ assert.equal(result.conversation.segments.length, 1);
189
+ assert.equal(result.conversation.segments[0].text, "First. Second.");
190
+ });
@@ -24,6 +24,14 @@ export interface CleanupResult {
24
24
  /** Merge consecutive same-speaker segments when gaps are below this. */
25
25
  const MERGE_GAP_MS = 30_000;
26
26
 
27
+ /**
28
+ * Speaker labels that carry no real diarization signal. Bee (and other
29
+ * providers that fall back to a placeholder) emit "Unknown"/"unknown"
30
+ * or an empty string when diarization is unavailable; merging on such a
31
+ * label would collapse an entire conversation into one segment (issue #1811).
32
+ */
33
+ const GENERIC_SPEAKER_PATTERN = /^unknown$/i;
34
+
27
35
  /**
28
36
  * Standalone filler tokens stripped when `stripFillers` is on. Matched
29
37
  * case-insensitively on word boundaries, only as whole tokens — "um"
@@ -47,6 +55,9 @@ export function cleanConversation(
47
55
  let segments = conversation.segments.map((segment) => ({ ...segment }));
48
56
  let droppedSegments = 0;
49
57
  let mergedSegments = 0;
58
+ // Optional on the type so other connectors keep the legacy no-op
59
+ // default; absent means "off" (unchanged merge behavior).
60
+ const preserveBoundaries = settings.preserveUtteranceBoundaries === true;
50
61
 
51
62
  if (settings.stripFillers) {
52
63
  for (const segment of segments) {
@@ -86,7 +97,7 @@ export function cleanConversation(
86
97
  const merged: WearableTranscriptSegment[] = [];
87
98
  for (const segment of segments) {
88
99
  const previous = merged[merged.length - 1];
89
- if (previous && canMerge(previous, segment)) {
100
+ if (previous && canMerge(previous, segment, preserveBoundaries)) {
90
101
  previous.text = `${previous.text} ${segment.text}`.trim();
91
102
  if (segment.endIso) previous.endIso = segment.endIso;
92
103
  mergedSegments += 1;
@@ -107,8 +118,18 @@ export function cleanConversation(
107
118
  function canMerge(
108
119
  previous: WearableTranscriptSegment,
109
120
  next: WearableTranscriptSegment,
121
+ preserveUtteranceBoundaries: boolean,
110
122
  ): boolean {
111
123
  if (previous.speakerKey !== next.speakerKey) return false;
124
+ // A generic/low-confidence speaker label ("Unknown", empty) carries no
125
+ // real diarization: merging on it collapses unrelated utterances. When
126
+ // the source opts into boundary preservation, refuse to merge across
127
+ // such a label (issue #1811). The keys are equal here, so checking one
128
+ // suffices; diarized labels still merge normally.
129
+ if (preserveUtteranceBoundaries) {
130
+ const label = previous.speakerKey.trim();
131
+ if (label.length === 0 || GENERIC_SPEAKER_PATTERN.test(label)) return false;
132
+ }
112
133
  const previousEnd = previous.endIso ? Date.parse(previous.endIso) : NaN;
113
134
  const nextStart = next.startIso ? Date.parse(next.startIso) : NaN;
114
135
  // Without timestamps, adjacency is the only signal — still merge.
@@ -44,9 +44,34 @@ test("source settings default to the fully-automated smart pipeline", () => {
44
44
  stripFillers: true,
45
45
  collapseRepeats: true,
46
46
  dropLowQuality: true,
47
+ // Opt-in for Bee only; limitless keeps the legacy default (issue #1811).
48
+ preserveUtteranceBoundaries: false,
47
49
  });
48
50
  });
49
51
 
52
+ test("bee source defaults to preserving utterance boundaries (#1811)", () => {
53
+ const parsed = parseWearablesConfig({
54
+ enabled: true,
55
+ sources: { bee: { enabled: true } },
56
+ });
57
+ assert.equal(parsed.sources.bee.cleanup.preserveUtteranceBoundaries, true);
58
+ });
59
+
60
+ test("cleanup.preserveUtteranceBoundaries is parsed and overrides the source default", () => {
61
+ const parsed = parseWearablesConfig({
62
+ enabled: true,
63
+ sources: { bee: { enabled: true, cleanup: { preserveUtteranceBoundaries: false } } },
64
+ });
65
+ assert.equal(parsed.sources.bee.cleanup.preserveUtteranceBoundaries, false);
66
+ assert.throws(
67
+ () =>
68
+ parseWearablesConfig({
69
+ sources: { bee: { cleanup: { preserveUtteranceBoundaries: "maybe" } } },
70
+ }),
71
+ /cleanup.preserveUtteranceBoundaries/,
72
+ );
73
+ });
74
+
50
75
  test("top-level defaults are full-featured: digest and off-the-record on", () => {
51
76
  const parsed = parseWearablesConfig({});
52
77
  assert.equal(parsed.digestEnabled, true);