@remnic/core 9.62.1 → 9.62.2

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 (484) hide show
  1. package/dist/access-admin-ops-surface.d.ts +11 -11
  2. package/dist/access-admin-ops-surface.js +26 -26
  3. package/dist/access-audit.js +2 -2
  4. package/dist/access-authorization-probe.d.ts +11 -11
  5. package/dist/access-authorization-probe.js +27 -27
  6. package/dist/access-boundary.d.ts +11 -11
  7. package/dist/access-boundary.js +26 -26
  8. package/dist/access-cli.js +88 -86
  9. package/dist/access-cli.js.map +1 -1
  10. package/dist/access-coding-context-resolution.d.ts +1 -1
  11. package/dist/access-extraction-force-flush.d.ts +11 -11
  12. package/dist/access-extraction-force-flush.js +26 -26
  13. package/dist/access-health-types.d.ts +1 -1
  14. package/dist/access-http-lcm-compaction.d.ts +11 -11
  15. package/dist/access-http-lifecycle-flush.d.ts +11 -11
  16. package/dist/access-http-offline-stream.d.ts +11 -11
  17. package/dist/access-http-query.js +26 -26
  18. package/dist/access-http.d.ts +12 -12
  19. package/dist/access-http.js +36 -36
  20. package/dist/access-identity-continuity-surface.d.ts +9 -9
  21. package/dist/access-identity-continuity-surface.js +26 -26
  22. package/dist/access-lcm-surface.d.ts +11 -11
  23. package/dist/access-lcm-surface.js +26 -26
  24. package/dist/access-mcp.d.ts +11 -11
  25. package/dist/access-mcp.js +31 -31
  26. package/dist/access-memory-search-fanout.d.ts +2 -2
  27. package/dist/{access-namespace-preflight-EMvicnrb.d.ts → access-namespace-preflight-yO4LMGFH.d.ts} +1 -1
  28. package/dist/access-namespace-preflight.d.ts +3 -3
  29. package/dist/access-namespace-preflight.js +26 -26
  30. package/dist/access-observe-write-surface.d.ts +11 -11
  31. package/dist/access-observe-write-surface.js +26 -26
  32. package/dist/access-offline-manifest.d.ts +9 -9
  33. package/dist/access-offline-manifest.js +2 -2
  34. package/dist/access-operations-batch.js +27 -27
  35. package/dist/access-operations.d.ts +11 -11
  36. package/dist/access-operations.js +30 -30
  37. package/dist/access-recall-concurrency.d.ts +11 -11
  38. package/dist/access-recall-concurrency.js +26 -26
  39. package/dist/access-recall-response.d.ts +11 -11
  40. package/dist/access-recall-response.js +26 -26
  41. package/dist/access-recall-surface.d.ts +11 -11
  42. package/dist/access-recall-surface.js +26 -26
  43. package/dist/{access-service-BeDYQQ62.d.ts → access-service-M4LgO141.d.ts} +7 -7
  44. package/dist/access-service-helpers.d.ts +11 -11
  45. package/dist/access-service.d.ts +11 -11
  46. package/dist/access-service.js +26 -26
  47. package/dist/access-surface-catalog.d.ts +11 -11
  48. package/dist/access-surface-catalog.js +28 -28
  49. package/dist/access-wearables-meetings-surface.d.ts +3 -3
  50. package/dist/action-confidence.d.ts +1 -1
  51. package/dist/active-memory-bridge.d.ts +1 -1
  52. package/dist/active-recall.d.ts +1 -1
  53. package/dist/active-recall.js +1 -1
  54. package/dist/ambient-provenance.d.ts +1 -1
  55. package/dist/artifact-search.d.ts +1 -1
  56. package/dist/{auto-sync-FMWQQB3J.js → auto-sync-Z52VWMNC.js} +3 -3
  57. package/dist/behavior-learner.d.ts +1 -1
  58. package/dist/behavior-learner.js +2 -2
  59. package/dist/behavior-signals.d.ts +1 -1
  60. package/dist/bootstrap.d.ts +9 -9
  61. package/dist/briefing-window.d.ts +2 -2
  62. package/dist/briefing.d.ts +2 -2
  63. package/dist/briefing.js +11 -10
  64. package/dist/buffer-surprise-report.d.ts +1 -1
  65. package/dist/buffer-turn-helpers.d.ts +1 -1
  66. package/dist/buffer.d.ts +2 -2
  67. package/dist/bulk-import/index.d.ts +3 -3
  68. package/dist/calibration.d.ts +1 -1
  69. package/dist/capabilities.d.ts +1 -1
  70. package/dist/{catalog-B2SxZ6LU.d.ts → catalog-CyYTf_ok.d.ts} +1 -1
  71. package/dist/causal-behavior.d.ts +1 -1
  72. package/dist/causal-behavior.js +3 -3
  73. package/dist/causal-chain.js +3 -3
  74. package/dist/causal-consolidation.d.ts +1 -1
  75. package/dist/causal-consolidation.js +14 -14
  76. package/dist/causal-retrieval.js +3 -3
  77. package/dist/causal-trajectory-graph.d.ts +1 -1
  78. package/dist/causal-trajectory.js +2 -2
  79. package/dist/{chunk-B2QHVLJO.js → chunk-256FBCVX.js} +22 -10
  80. package/dist/chunk-256FBCVX.js.map +1 -0
  81. package/dist/{chunk-QP2IZTUR.js → chunk-2TYIAKU5.js} +2 -2
  82. package/dist/{chunk-QNMNNFKD.js → chunk-347ZR6D4.js} +2 -2
  83. package/dist/{chunk-76YNCJ5H.js → chunk-3F3CVVDS.js} +2 -2
  84. package/dist/{chunk-KCFZOSR6.js → chunk-3MA7JVXN.js} +4 -4
  85. package/dist/{chunk-KHQ57QLJ.js → chunk-46WM6JX2.js} +7 -3
  86. package/dist/chunk-46WM6JX2.js.map +1 -0
  87. package/dist/chunk-47DU4SGJ.js +92 -0
  88. package/dist/chunk-47DU4SGJ.js.map +1 -0
  89. package/dist/{chunk-HKYNBEL4.js → chunk-4FFROSFG.js} +37 -14
  90. package/dist/{chunk-HKYNBEL4.js.map → chunk-4FFROSFG.js.map} +1 -1
  91. package/dist/{chunk-TLUSSS2F.js → chunk-4HO3542O.js} +2 -2
  92. package/dist/{chunk-4E67XCT2.js → chunk-4IZ2IT7D.js} +3 -3
  93. package/dist/{chunk-33JBK2XP.js → chunk-5F6HMNMZ.js} +2 -2
  94. package/dist/{chunk-5WQMORU5.js → chunk-5PFGMO33.js} +2 -2
  95. package/dist/{chunk-6HEM6HTQ.js → chunk-6GGTATZF.js} +2 -2
  96. package/dist/{chunk-UIRU3MIJ.js → chunk-7BJYTX6Q.js} +2 -2
  97. package/dist/{chunk-2GRLJMKJ.js → chunk-7DRSWPUV.js} +3 -3
  98. package/dist/{chunk-TVVEYCNW.js → chunk-7K5Q6COX.js} +4 -4
  99. package/dist/{chunk-HXXGZ4KV.js → chunk-ALNZEWGN.js} +2 -2
  100. package/dist/{chunk-5WVUO6QT.js → chunk-AR253JBM.js} +1 -1
  101. package/dist/chunk-AR253JBM.js.map +1 -0
  102. package/dist/{chunk-67MKNKJQ.js → chunk-AYIHDC5S.js} +2 -2
  103. package/dist/{chunk-IXJ5U6ZL.js → chunk-BBHFAVMP.js} +8 -8
  104. package/dist/{chunk-IIRK5V5Z.js → chunk-BHO6RHE5.js} +3 -3
  105. package/dist/{chunk-WANOCU3K.js → chunk-BP6WMYLP.js} +3 -3
  106. package/dist/{chunk-ZJKLGS76.js → chunk-CALURYWR.js} +283 -248
  107. package/dist/chunk-CALURYWR.js.map +1 -0
  108. package/dist/{chunk-JLMH5YMU.js → chunk-CH627RRV.js} +2 -2
  109. package/dist/{chunk-XIABRKF6.js → chunk-CLJ5QS6J.js} +239 -47
  110. package/dist/chunk-CLJ5QS6J.js.map +1 -0
  111. package/dist/{chunk-YLHM5BQQ.js → chunk-DCUMFQYM.js} +171 -8
  112. package/dist/chunk-DCUMFQYM.js.map +1 -0
  113. package/dist/{chunk-ZBJMUXZH.js → chunk-DJ7HMNSL.js} +15 -8
  114. package/dist/chunk-DJ7HMNSL.js.map +1 -0
  115. package/dist/{chunk-WTMG5GAK.js → chunk-DROAPP6N.js} +3 -3
  116. package/dist/{chunk-PBH2Z2NY.js → chunk-DTLF2SLZ.js} +2 -2
  117. package/dist/{chunk-7JAXC526.js → chunk-EFWHCTYJ.js} +2 -2
  118. package/dist/{chunk-3XG4QEA2.js → chunk-FF6E6HOT.js} +39 -39
  119. package/dist/{chunk-NP7FLVZW.js → chunk-G2FCSILA.js} +2 -2
  120. package/dist/{chunk-7PVTOZR4.js → chunk-H23GIXJC.js} +2 -2
  121. package/dist/{chunk-WT6UL3UA.js → chunk-H7PRHUBD.js} +2 -2
  122. package/dist/{chunk-ETCVSZLG.js → chunk-HSBQJRV2.js} +2 -2
  123. package/dist/{chunk-GZRDOVQN.js → chunk-HVKMJAEF.js} +2 -2
  124. package/dist/{chunk-CSOYVTRX.js → chunk-IIPJKCZB.js} +3 -3
  125. package/dist/{chunk-E57E5SCS.js → chunk-IRLH4NM2.js} +3 -3
  126. package/dist/{chunk-4G45LJJP.js → chunk-IZRNVNPV.js} +2 -2
  127. package/dist/{chunk-YSUSUZR4.js → chunk-JCJGYNIS.js} +3 -3
  128. package/dist/{chunk-EU74U4GT.js → chunk-JDI7G6EA.js} +2 -2
  129. package/dist/{chunk-QWPAQLYV.js → chunk-JFLKSD5V.js} +2 -2
  130. package/dist/{chunk-KQS72GCR.js → chunk-LJOIZPJH.js} +2 -2
  131. package/dist/{chunk-U27G4E5G.js → chunk-LLGDVG52.js} +3 -3
  132. package/dist/{chunk-7N7DB4L5.js → chunk-LTJTP5YQ.js} +10 -9
  133. package/dist/chunk-LTJTP5YQ.js.map +1 -0
  134. package/dist/{chunk-XL3TATMJ.js → chunk-OQIRBGUU.js} +21 -12
  135. package/dist/chunk-OQIRBGUU.js.map +1 -0
  136. package/dist/{chunk-JGW2EUCQ.js → chunk-PMRUMGK6.js} +2 -2
  137. package/dist/{chunk-3G6YU5YD.js → chunk-PSNN25DW.js} +2 -2
  138. package/dist/{chunk-LRGSLV7M.js → chunk-PYHOAXTI.js} +4 -4
  139. package/dist/{chunk-75U2FR7U.js → chunk-QCI73Z7C.js} +2 -2
  140. package/dist/{chunk-EHMMRZOZ.js → chunk-QICOU4RY.js} +2 -2
  141. package/dist/{chunk-K4WIUTNH.js → chunk-RFH7U5LT.js} +2 -2
  142. package/dist/{chunk-4SGDYYWV.js → chunk-RPKJHYVE.js} +2 -2
  143. package/dist/{chunk-BHO3IVAN.js → chunk-RYST72N5.js} +12 -1
  144. package/dist/chunk-RYST72N5.js.map +1 -0
  145. package/dist/chunk-T3GIETKV.js +152 -0
  146. package/dist/chunk-T3GIETKV.js.map +1 -0
  147. package/dist/{chunk-DYDACAK2.js → chunk-TGSMU3F2.js} +3 -3
  148. package/dist/{chunk-MJFDJTDC.js → chunk-TIRJV2LW.js} +2 -2
  149. package/dist/{chunk-QRA3XVJX.js → chunk-UDTME32W.js} +2 -2
  150. package/dist/{chunk-LAM6UDFV.js → chunk-WMOJIOIG.js} +2 -2
  151. package/dist/{chunk-LLLY5IBK.js → chunk-WR2YKUIW.js} +2 -2
  152. package/dist/{chunk-KYI3CM42.js → chunk-X6E7TT3A.js} +2 -2
  153. package/dist/{chunk-QN7XQEIT.js → chunk-YIIC5IDU.js} +2 -2
  154. package/dist/{chunk-JDJOAL4B.js → chunk-YSR3DXGC.js} +2 -2
  155. package/dist/{chunk-LBJBNWS2.js → chunk-YTHQHH5U.js} +2 -2
  156. package/dist/{chunk-JF6YSHJM.js → chunk-ZPGHA7EO.js} +12 -12
  157. package/dist/{chunk-VUDALPI5.js → chunk-ZQKXRKMR.js} +19 -5
  158. package/dist/chunk-ZQKXRKMR.js.map +1 -0
  159. package/dist/{chunk-YG56A6XY.js → chunk-ZS4JADYY.js} +3 -3
  160. package/dist/{cli-DB_uakTc.d.ts → cli-Bw9z-KqX.d.ts} +5 -5
  161. package/dist/cli.d.ts +13 -13
  162. package/dist/cli.js +60 -60
  163. package/dist/coding/pre-action-gate.d.ts +1 -1
  164. package/dist/coding/pre-action-gate.js +3 -3
  165. package/dist/compounding/engine.d.ts +2 -2
  166. package/dist/compounding/engine.js +11 -10
  167. package/dist/compounding/preference-consolidator.d.ts +1 -1
  168. package/dist/compression-optimizer.d.ts +1 -1
  169. package/dist/config.d.ts +1 -1
  170. package/dist/config.js +1 -1
  171. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  172. package/dist/connectors/codex-materialize-runner.js +11 -10
  173. package/dist/connectors/codex-materialize.d.ts +1 -1
  174. package/dist/connectors/index.d.ts +1 -1
  175. package/dist/connectors/index.js +11 -10
  176. package/dist/consolidation-provenance-check.d.ts +2 -2
  177. package/dist/consolidation-undo.d.ts +2 -2
  178. package/dist/contradiction/index.d.ts +2 -2
  179. package/dist/converge-config.d.ts +1 -1
  180. package/dist/convergence-refresh.d.ts +2 -2
  181. package/dist/convergence-refresh.js +13 -12
  182. package/dist/conversation-index/backend.d.ts +1 -1
  183. package/dist/conversation-index/chunker.d.ts +1 -1
  184. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  185. package/dist/conversation-index/indexer.d.ts +1 -1
  186. package/dist/conversation-index/search.d.ts +1 -1
  187. package/dist/corpus-watermark.d.ts +1 -1
  188. package/dist/corpus-watermark.js +13 -12
  189. package/dist/day-summary.d.ts +1 -1
  190. package/dist/delinearize.d.ts +1 -1
  191. package/dist/dependency-propagation-config.d.ts +1 -1
  192. package/dist/{dependency-propagation-delivery-DcOVpK3y.d.ts → dependency-propagation-delivery-BxhvAppj.d.ts} +1 -1
  193. package/dist/direct-answer-wiring.d.ts +1 -1
  194. package/dist/direct-answer-wiring.js +3 -3
  195. package/dist/direct-answer.d.ts +1 -1
  196. package/dist/direct-answer.js +2 -2
  197. package/dist/embedding-fallback.d.ts +1 -1
  198. package/dist/enrichment/index.d.ts +1 -1
  199. package/dist/entity-origin-fields.d.ts +1 -1
  200. package/dist/entity-retrieval.d.ts +2 -2
  201. package/dist/entity-retrieval.js +11 -10
  202. package/dist/entity-schema.d.ts +1 -1
  203. package/dist/episodic-context.d.ts +92 -0
  204. package/dist/episodic-context.js +16 -0
  205. package/dist/episodic-context.js.map +1 -0
  206. package/dist/explicit-capture.d.ts +9 -9
  207. package/dist/external-wiki-access.d.ts +11 -11
  208. package/dist/external-wiki-access.js +27 -27
  209. package/dist/external-wiki-collection-registration.d.ts +1 -1
  210. package/dist/external-wiki-collection.d.ts +1 -1
  211. package/dist/external-wiki-mcp-tools.d.ts +11 -11
  212. package/dist/extraction-error-classification.d.ts +1 -1
  213. package/dist/extraction-faithfulness.d.ts +1 -1
  214. package/dist/extraction-judge-telemetry.d.ts +1 -1
  215. package/dist/extraction-judge-training.d.ts +1 -1
  216. package/dist/extraction-judge.d.ts +1 -1
  217. package/dist/extraction-liveness.d.ts +1 -1
  218. package/dist/extraction-normalization.d.ts +1 -1
  219. package/dist/extraction-normalization.js +2 -2
  220. package/dist/extraction-prompt.d.ts +1 -1
  221. package/dist/extraction-source-grounding-rules.d.ts +1 -1
  222. package/dist/extraction-source-grounding.d.ts +1 -1
  223. package/dist/extraction.d.ts +1 -1
  224. package/dist/extraction.js +14 -14
  225. package/dist/fallback-llm.d.ts +1 -1
  226. package/dist/{forget-5TWK7CZT.js → forget-SZ2BXDGF.js} +2 -2
  227. package/dist/graph-dashboard-diff.d.ts +1 -1
  228. package/dist/graph-dashboard-key.d.ts +1 -1
  229. package/dist/graph-dashboard-parser.d.ts +1 -1
  230. package/dist/graph-edge-reinforcement.d.ts +1 -1
  231. package/dist/graph-path-reconstruction.d.ts +1 -1
  232. package/dist/graph-path-scoring.d.ts +1 -1
  233. package/dist/graph-snapshot.d.ts +1 -1
  234. package/dist/graph.d.ts +1 -1
  235. package/dist/harmonic-construction.js +2 -2
  236. package/dist/harmonic-retrieval.js +2 -2
  237. package/dist/importance.d.ts +1 -1
  238. package/dist/importers/index.d.ts +1 -1
  239. package/dist/in-flight-reads.d.ts +1 -1
  240. package/dist/index.d.ts +21 -21
  241. package/dist/index.js +100 -98
  242. package/dist/intent.d.ts +1 -1
  243. package/dist/lcm/engine.d.ts +8 -2
  244. package/dist/lcm/engine.js +4 -4
  245. package/dist/lcm/index.d.ts +1 -1
  246. package/dist/lcm/index.js +9 -9
  247. package/dist/lcm/tools.d.ts +1 -1
  248. package/dist/lifecycle.d.ts +1 -1
  249. package/dist/live-connectors-runner.d.ts +1 -1
  250. package/dist/local-llm.d.ts +1 -1
  251. package/dist/local-model-endpoint.d.ts +1 -1
  252. package/dist/maintenance/memory-governance.d.ts +1 -1
  253. package/dist/maintenance/memory-governance.js +11 -10
  254. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  255. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +11 -10
  256. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  257. package/dist/maintenance/rebuild-memory-projection.js +12 -11
  258. package/dist/{maintenance-5c1olVtB.d.ts → maintenance-uJb74j64.d.ts} +3 -3
  259. package/dist/mcp-memory-inspector-app.d.ts +11 -11
  260. package/dist/memory-action-policy.d.ts +1 -1
  261. package/dist/memory-cache.d.ts +1 -1
  262. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  263. package/dist/memory-projection-store.d.ts +1 -1
  264. package/dist/memory-provenance.d.ts +1 -1
  265. package/dist/memory-snapshot.d.ts +1 -1
  266. package/dist/memory-worth-outcomes.d.ts +2 -2
  267. package/dist/models-json.d.ts +1 -1
  268. package/dist/namespaces/migrate.d.ts +3 -3
  269. package/dist/namespaces/migrate.js +12 -11
  270. package/dist/namespaces/principal.d.ts +1 -1
  271. package/dist/namespaces/search.d.ts +1 -1
  272. package/dist/namespaces/search.js +6 -5
  273. package/dist/namespaces/storage.d.ts +3 -3
  274. package/dist/namespaces/storage.js +11 -10
  275. package/dist/native-knowledge.d.ts +1 -1
  276. package/dist/offline-sync-impression-drain.d.ts +1 -1
  277. package/dist/operator-doctor-corpus.d.ts +1 -1
  278. package/dist/operator-doctor-corpus.js +14 -13
  279. package/dist/operator-doctor-replica.d.ts +1 -1
  280. package/dist/operator-toolkit.d.ts +3 -3
  281. package/dist/operator-toolkit.js +19 -18
  282. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  283. package/dist/orchestration/maintenance.d.ts +4 -4
  284. package/dist/orchestration/maintenance.js +16 -15
  285. package/dist/{orchestrator-HPuY6I4i.d.ts → orchestrator-CFi-5JSR.d.ts} +23 -8
  286. package/dist/orchestrator.d.ts +9 -9
  287. package/dist/orchestrator.js +88 -86
  288. package/dist/patterns-cli.d.ts +1 -1
  289. package/dist/{pipeline-CvVe1Q2_.d.ts → pipeline-BdF3ferY.d.ts} +1 -1
  290. package/dist/policy-runtime.d.ts +1 -1
  291. package/dist/policy-runtime.js +3 -3
  292. package/dist/proactive-contention.d.ts +1 -1
  293. package/dist/provenance.d.ts +1 -1
  294. package/dist/{public-http-D0JKFkyf.d.ts → public-http-DK-QwaBu.d.ts} +1 -1
  295. package/dist/{qmd-Bd0Tp76_.d.ts → qmd-D_62bYNl.d.ts} +1 -1
  296. package/dist/qmd-preflight.d.ts +2 -2
  297. package/dist/qmd-recall-cache.d.ts +1 -1
  298. package/dist/qmd.d.ts +2 -2
  299. package/dist/recall-concurrency-config.d.ts +1 -1
  300. package/dist/recall-disclosure-escalation.d.ts +1 -1
  301. package/dist/recall-explain-renderer.d.ts +1 -1
  302. package/dist/recall-explain-renderer.js +3 -3
  303. package/dist/recall-memory-map.d.ts +1 -1
  304. package/dist/recall-planner-llm.d.ts +1 -1
  305. package/dist/recall-query-policy.js +2 -2
  306. package/dist/recall-state.d.ts +1 -1
  307. package/dist/recall-tag-filter.d.ts +1 -1
  308. package/dist/recall-timings.d.ts +1 -1
  309. package/dist/recall-tokenization.d.ts +3 -1
  310. package/dist/recall-tokenization.js +5 -1
  311. package/dist/recall-xray-cli.d.ts +1 -1
  312. package/dist/recall-xray-cli.js +4 -4
  313. package/dist/recall-xray-renderer.d.ts +1 -1
  314. package/dist/recall-xray-renderer.js +3 -3
  315. package/dist/recall-xray.d.ts +1 -1
  316. package/dist/recall-xray.js +2 -2
  317. package/dist/reconcile/cursor.d.ts +1 -1
  318. package/dist/reconcile/manifest.d.ts +10 -1
  319. package/dist/reconcile/manifest.js +1 -1
  320. package/dist/reconcile/plan.d.ts +1 -1
  321. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  322. package/dist/replay/normalizers/claude.d.ts +1 -1
  323. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  324. package/dist/replay/normalizers/shared.d.ts +1 -1
  325. package/dist/replay/runner.d.ts +1 -1
  326. package/dist/replay/types.d.ts +1 -1
  327. package/dist/replica-divergence.d.ts +1 -1
  328. package/dist/replica-peers-config.d.ts +1 -1
  329. package/dist/resolve-auth-token.d.ts +1 -1
  330. package/dist/resume-bundles.js +4 -4
  331. package/dist/retrieval-agents.d.ts +2 -2
  332. package/dist/retrieval-tiers.d.ts +1 -1
  333. package/dist/routing/engine.d.ts +1 -1
  334. package/dist/routing/store.d.ts +1 -1
  335. package/dist/salvage-envelope.d.ts +1 -1
  336. package/dist/{scope-profiles-ClLtm9gK.d.ts → scope-profiles-CeMv7pP0.d.ts} +1 -1
  337. package/dist/search/embed-helper.d.ts +1 -1
  338. package/dist/search/factory.d.ts +1 -1
  339. package/dist/search/factory.js +5 -4
  340. package/dist/search/index.d.ts +1 -1
  341. package/dist/search/index.js +9 -8
  342. package/dist/search/lancedb-backend.d.ts +14 -1
  343. package/dist/search/lancedb-backend.js +1 -1
  344. package/dist/search/meilisearch-backend.d.ts +1 -1
  345. package/dist/search/noop-backend.d.ts +1 -1
  346. package/dist/search/orama-backend.d.ts +22 -1
  347. package/dist/search/orama-backend.js +2 -1
  348. package/dist/search/port.d.ts +1 -1
  349. package/dist/search/remote-backend.d.ts +1 -1
  350. package/dist/{semantic-consolidation-B1EkeEDj.d.ts → semantic-consolidation-B-85brYj.d.ts} +1 -1
  351. package/dist/semantic-consolidation.d.ts +2 -2
  352. package/dist/semantic-consolidation.js +12 -12
  353. package/dist/semantic-rule-promotion.js +11 -10
  354. package/dist/semantic-rule-verifier.d.ts +1 -1
  355. package/dist/semantic-rule-verifier.js +11 -11
  356. package/dist/{service-Cf3ANQj9.d.ts → service-CoO0HA2E.d.ts} +2 -2
  357. package/dist/session-observer-bands.d.ts +1 -1
  358. package/dist/session-observer-state.d.ts +1 -1
  359. package/dist/shared-context/manager.d.ts +1 -1
  360. package/dist/signal.d.ts +1 -1
  361. package/dist/source-agent-qualifier.d.ts +1 -1
  362. package/dist/source-agent-qualifier.js +11 -10
  363. package/dist/{storage-DS2O_6Qt.d.ts → storage-BVAVitkO.d.ts} +1 -1
  364. package/dist/storage.d.ts +2 -2
  365. package/dist/storage.js +10 -9
  366. package/dist/summarizer.d.ts +1 -1
  367. package/dist/summary-snapshot.d.ts +1 -1
  368. package/dist/support-passport/index.d.ts +14 -14
  369. package/dist/support-passport/index.js +29 -29
  370. package/dist/temporal-supersession.d.ts +2 -2
  371. package/dist/temporal-timeline-recall.d.ts +1 -1
  372. package/dist/temporal-validity.d.ts +1 -1
  373. package/dist/threading.d.ts +1 -1
  374. package/dist/tier-migration.d.ts +2 -2
  375. package/dist/tier-routing.d.ts +1 -1
  376. package/dist/topics.d.ts +1 -1
  377. package/dist/transcript.d.ts +1 -1
  378. package/dist/transfer/import-sqlite.js +2 -2
  379. package/dist/trust-score-stage.d.ts +1 -1
  380. package/dist/trust-score.d.ts +1 -1
  381. package/dist/trust-zones.js +2 -2
  382. package/dist/{types-BOANGhCJ.d.ts → types-DWHOxlZP.d.ts} +3 -0
  383. package/dist/types.d.ts +1 -1
  384. package/dist/types.js +1 -1
  385. package/dist/user-message-cleaning.d.ts +23 -0
  386. package/dist/user-message-cleaning.js +10 -0
  387. package/dist/user-message-cleaning.js.map +1 -0
  388. package/dist/utility-runtime.d.ts +1 -1
  389. package/dist/verified-recall.js +11 -11
  390. package/dist/work-product-ledger.js +2 -2
  391. package/dist/write-envelope.d.ts +1 -1
  392. package/package.json +12 -2
  393. package/src/access-service-offline-file-content.test.ts +1 -0
  394. package/src/config.ts +11 -0
  395. package/src/episodic-context-recall.integration.test.ts +169 -0
  396. package/src/episodic-context.test.ts +266 -0
  397. package/src/episodic-context.ts +274 -0
  398. package/src/lcm/engine.ts +18 -1
  399. package/src/lifecycle/tombstones.test.ts +134 -0
  400. package/src/lifecycle/tombstones.ts +29 -2
  401. package/src/orchestration/episodic-context-section.ts +255 -0
  402. package/src/orchestration/recall-internal-deps.ts +2 -0
  403. package/src/orchestration/recall-internal.ts +40 -25
  404. package/src/orchestration/recall-result-formatter.ts +37 -0
  405. package/src/recall-tokenization.ts +14 -8
  406. package/src/reconcile/manifest.test.ts +133 -4
  407. package/src/reconcile/manifest.ts +43 -7
  408. package/src/search/factory.ts +1 -0
  409. package/src/search/lancedb-backend.ts +24 -16
  410. package/src/search/orama-backend.test.ts +208 -1
  411. package/src/search/orama-backend.ts +133 -18
  412. package/src/search/orama-cjk-tokenizer.test.ts +108 -0
  413. package/src/search/orama-cjk-tokenizer.ts +143 -0
  414. package/src/storage/tombstone-migration-sources.test.ts +116 -0
  415. package/src/storage/tombstone-migration-sources.ts +90 -0
  416. package/src/storage.ts +13 -34
  417. package/src/types.ts +3 -3
  418. package/src/user-message-cleaning.ts +139 -0
  419. package/dist/chunk-5WVUO6QT.js.map +0 -1
  420. package/dist/chunk-7N7DB4L5.js.map +0 -1
  421. package/dist/chunk-B2QHVLJO.js.map +0 -1
  422. package/dist/chunk-BHO3IVAN.js.map +0 -1
  423. package/dist/chunk-KHQ57QLJ.js.map +0 -1
  424. package/dist/chunk-VUDALPI5.js.map +0 -1
  425. package/dist/chunk-XIABRKF6.js.map +0 -1
  426. package/dist/chunk-XL3TATMJ.js.map +0 -1
  427. package/dist/chunk-YLHM5BQQ.js.map +0 -1
  428. package/dist/chunk-ZBJMUXZH.js.map +0 -1
  429. package/dist/chunk-ZJKLGS76.js.map +0 -1
  430. /package/dist/{auto-sync-FMWQQB3J.js.map → auto-sync-Z52VWMNC.js.map} +0 -0
  431. /package/dist/{chunk-QP2IZTUR.js.map → chunk-2TYIAKU5.js.map} +0 -0
  432. /package/dist/{chunk-QNMNNFKD.js.map → chunk-347ZR6D4.js.map} +0 -0
  433. /package/dist/{chunk-76YNCJ5H.js.map → chunk-3F3CVVDS.js.map} +0 -0
  434. /package/dist/{chunk-KCFZOSR6.js.map → chunk-3MA7JVXN.js.map} +0 -0
  435. /package/dist/{chunk-TLUSSS2F.js.map → chunk-4HO3542O.js.map} +0 -0
  436. /package/dist/{chunk-4E67XCT2.js.map → chunk-4IZ2IT7D.js.map} +0 -0
  437. /package/dist/{chunk-33JBK2XP.js.map → chunk-5F6HMNMZ.js.map} +0 -0
  438. /package/dist/{chunk-5WQMORU5.js.map → chunk-5PFGMO33.js.map} +0 -0
  439. /package/dist/{chunk-6HEM6HTQ.js.map → chunk-6GGTATZF.js.map} +0 -0
  440. /package/dist/{chunk-UIRU3MIJ.js.map → chunk-7BJYTX6Q.js.map} +0 -0
  441. /package/dist/{chunk-2GRLJMKJ.js.map → chunk-7DRSWPUV.js.map} +0 -0
  442. /package/dist/{chunk-TVVEYCNW.js.map → chunk-7K5Q6COX.js.map} +0 -0
  443. /package/dist/{chunk-HXXGZ4KV.js.map → chunk-ALNZEWGN.js.map} +0 -0
  444. /package/dist/{chunk-67MKNKJQ.js.map → chunk-AYIHDC5S.js.map} +0 -0
  445. /package/dist/{chunk-IXJ5U6ZL.js.map → chunk-BBHFAVMP.js.map} +0 -0
  446. /package/dist/{chunk-IIRK5V5Z.js.map → chunk-BHO6RHE5.js.map} +0 -0
  447. /package/dist/{chunk-WANOCU3K.js.map → chunk-BP6WMYLP.js.map} +0 -0
  448. /package/dist/{chunk-JLMH5YMU.js.map → chunk-CH627RRV.js.map} +0 -0
  449. /package/dist/{chunk-WTMG5GAK.js.map → chunk-DROAPP6N.js.map} +0 -0
  450. /package/dist/{chunk-PBH2Z2NY.js.map → chunk-DTLF2SLZ.js.map} +0 -0
  451. /package/dist/{chunk-7JAXC526.js.map → chunk-EFWHCTYJ.js.map} +0 -0
  452. /package/dist/{chunk-3XG4QEA2.js.map → chunk-FF6E6HOT.js.map} +0 -0
  453. /package/dist/{chunk-NP7FLVZW.js.map → chunk-G2FCSILA.js.map} +0 -0
  454. /package/dist/{chunk-7PVTOZR4.js.map → chunk-H23GIXJC.js.map} +0 -0
  455. /package/dist/{chunk-WT6UL3UA.js.map → chunk-H7PRHUBD.js.map} +0 -0
  456. /package/dist/{chunk-ETCVSZLG.js.map → chunk-HSBQJRV2.js.map} +0 -0
  457. /package/dist/{chunk-GZRDOVQN.js.map → chunk-HVKMJAEF.js.map} +0 -0
  458. /package/dist/{chunk-CSOYVTRX.js.map → chunk-IIPJKCZB.js.map} +0 -0
  459. /package/dist/{chunk-E57E5SCS.js.map → chunk-IRLH4NM2.js.map} +0 -0
  460. /package/dist/{chunk-4G45LJJP.js.map → chunk-IZRNVNPV.js.map} +0 -0
  461. /package/dist/{chunk-YSUSUZR4.js.map → chunk-JCJGYNIS.js.map} +0 -0
  462. /package/dist/{chunk-EU74U4GT.js.map → chunk-JDI7G6EA.js.map} +0 -0
  463. /package/dist/{chunk-QWPAQLYV.js.map → chunk-JFLKSD5V.js.map} +0 -0
  464. /package/dist/{chunk-KQS72GCR.js.map → chunk-LJOIZPJH.js.map} +0 -0
  465. /package/dist/{chunk-U27G4E5G.js.map → chunk-LLGDVG52.js.map} +0 -0
  466. /package/dist/{chunk-JGW2EUCQ.js.map → chunk-PMRUMGK6.js.map} +0 -0
  467. /package/dist/{chunk-3G6YU5YD.js.map → chunk-PSNN25DW.js.map} +0 -0
  468. /package/dist/{chunk-LRGSLV7M.js.map → chunk-PYHOAXTI.js.map} +0 -0
  469. /package/dist/{chunk-75U2FR7U.js.map → chunk-QCI73Z7C.js.map} +0 -0
  470. /package/dist/{chunk-EHMMRZOZ.js.map → chunk-QICOU4RY.js.map} +0 -0
  471. /package/dist/{chunk-K4WIUTNH.js.map → chunk-RFH7U5LT.js.map} +0 -0
  472. /package/dist/{chunk-4SGDYYWV.js.map → chunk-RPKJHYVE.js.map} +0 -0
  473. /package/dist/{chunk-DYDACAK2.js.map → chunk-TGSMU3F2.js.map} +0 -0
  474. /package/dist/{chunk-MJFDJTDC.js.map → chunk-TIRJV2LW.js.map} +0 -0
  475. /package/dist/{chunk-QRA3XVJX.js.map → chunk-UDTME32W.js.map} +0 -0
  476. /package/dist/{chunk-LAM6UDFV.js.map → chunk-WMOJIOIG.js.map} +0 -0
  477. /package/dist/{chunk-LLLY5IBK.js.map → chunk-WR2YKUIW.js.map} +0 -0
  478. /package/dist/{chunk-KYI3CM42.js.map → chunk-X6E7TT3A.js.map} +0 -0
  479. /package/dist/{chunk-QN7XQEIT.js.map → chunk-YIIC5IDU.js.map} +0 -0
  480. /package/dist/{chunk-JDJOAL4B.js.map → chunk-YSR3DXGC.js.map} +0 -0
  481. /package/dist/{chunk-LBJBNWS2.js.map → chunk-YTHQHH5U.js.map} +0 -0
  482. /package/dist/{chunk-JF6YSHJM.js.map → chunk-ZPGHA7EO.js.map} +0 -0
  483. /package/dist/{chunk-YG56A6XY.js.map → chunk-ZS4JADYY.js.map} +0 -0
  484. /package/dist/{forget-5TWK7CZT.js.map → forget-SZ2BXDGF.js.map} +0 -0
@@ -18,12 +18,30 @@ import {
18
18
  export const RECONCILE_MANIFEST_FORMAT = "remnic-reconcile-manifest";
19
19
  export const RECONCILE_MANIFEST_SCHEMA_VERSION = 1;
20
20
  const CONTENT_HASH_NORMALIZER_VERSION = 4;
21
+ /**
22
+ * Version of the identity-resolution LOGIC (alias recovery, candidate
23
+ * ordering), independent of the content normalizer: a cached manifest entry
24
+ * written before an identity-resolution change carries an older value and is
25
+ * reparsed even when its normalizerVersion still matches (issue #2367
26
+ * review round 2). Bump when parsedMemoryIdentity's output shape or
27
+ * semantics change.
28
+ */
29
+ const IDENTITY_RESOLUTION_VERSION = 2;
21
30
 
22
31
  export interface ReconcileMemoryIdentity {
23
32
  id: string;
24
33
  category: string;
25
34
  contentHash: string;
35
+ /**
36
+ * Recovered current-normalizer identities for a record whose persisted hash
37
+ * is ambiguous under the legacy normalizer (issue #2367). The persisted
38
+ * hash stays primary; these participate in duplicate bucketing so a
39
+ * replica carrying the current form of the same fact still collapses.
40
+ */
41
+ contentHashAliases?: readonly string[];
42
+ /** See IDENTITY_RESOLUTION_VERSION; absent on pre-versioning cache entries. */
26
43
  normalizerVersion?: number;
44
+ identityResolutionVersion?: number;
27
45
  status: MemoryStatus;
28
46
  }
29
47
 
@@ -88,17 +106,34 @@ function parsedMemoryIdentity(
88
106
  const legacyMatch = [...candidates].reverse().find(
89
107
  (content) => computeLegacyContentHash(content) === storedHash
90
108
  );
91
- const contentHash = currentMatch
92
- ? ContentHashIndex.computeHash(currentMatch)
93
- : legacyMatch
94
- ? ContentHashIndex.computeHash(legacyMatch)
95
- : storedHash ?? bodyHash;
109
+ let contentHash: string;
110
+ let contentHashAliases: string[] | undefined;
111
+ if (currentMatch) {
112
+ contentHash = ContentHashIndex.computeHash(currentMatch);
113
+ } else if (legacyMatch && normalizeLegacyContent(legacyMatch).length > 0) {
114
+ // A non-empty legacy equality is ambiguous (issue #2367): the persisted
115
+ // hash may be an explicit contentHashSource identity that merely collides
116
+ // with the body's ASCII skeleton under the lossy legacy normalizer, and
117
+ // nothing in the record proves which it is. Keep the persisted hash as
118
+ // the primary identity and expose the recovered current identity as an
119
+ // alias so replicas carrying either form still collapse.
120
+ contentHash = storedHash ?? bodyHash;
121
+ const recovered = ContentHashIndex.computeHash(legacyMatch);
122
+ if (recovered !== contentHash) contentHashAliases = [recovered];
123
+ } else {
124
+ // An EMPTY legacy skeleton identifies nothing (every non-ASCII body maps
125
+ // to it), so preserving it would collapse unrelated records. Recovering
126
+ // the current identity here is repair, not replacement.
127
+ contentHash = legacyMatch ? ContentHashIndex.computeHash(legacyMatch) : storedHash ?? bodyHash;
128
+ }
96
129
 
97
130
  return {
98
131
  id: parsed.frontmatter.id,
99
132
  category: parsed.frontmatter.category,
100
133
  contentHash,
134
+ ...(contentHashAliases ? { contentHashAliases } : {}),
101
135
  normalizerVersion: CONTENT_HASH_NORMALIZER_VERSION,
136
+ identityResolutionVersion: IDENTITY_RESOLUTION_VERSION,
102
137
  status: inferMemoryStatus(parsed.frontmatter, filePath),
103
138
  };
104
139
  }
@@ -136,7 +171,8 @@ export async function buildReconcileManifest(options: BuildReconcileManifestOpti
136
171
  if (
137
172
  cached?.sha256.toLowerCase() === file.sha256.toLowerCase() &&
138
173
  (cached.memory === undefined ||
139
- cached.memory.normalizerVersion === CONTENT_HASH_NORMALIZER_VERSION)
174
+ (cached.memory.normalizerVersion === CONTENT_HASH_NORMALIZER_VERSION &&
175
+ cached.memory.identityResolutionVersion === IDENTITY_RESOLUTION_VERSION))
140
176
  ) {
141
177
  files.push({ ...file, ...(cached.memory ? { memory: cached.memory } : {}) });
142
178
  continue;
@@ -168,7 +204,7 @@ function activeFactByPath(manifest: ReconcileManifest | undefined): Map<string,
168
204
  }
169
205
 
170
206
  function memoryIdentityHashes(memory: ReconcileMemoryIdentity): string[] {
171
- return [memory.contentHash];
207
+ return [memory.contentHash, ...(memory.contentHashAliases ?? [])];
172
208
  }
173
209
 
174
210
  function contentHashRows(
@@ -79,6 +79,7 @@ function resolveNonQmdBackend(config: PluginConfig): SearchBackend | undefined {
79
79
  embedHelper,
80
80
  memoryDir: config.memoryDir,
81
81
  embeddingDimension: config.oramaEmbeddingDimension!,
82
+ cjkSegmentationEnabled: config.oramaCjkSegmentation !== false,
82
83
  });
83
84
  }
84
85
 
@@ -221,12 +221,8 @@ export class LanceDbBackend implements SearchBackend {
221
221
  rows.length > 0 && rows.every((row) => row.vectorProvider === embeddingProviderIdentity),
222
222
  );
223
223
  if (isSearchAborted(execution)) return;
224
- // Create FTS index on content column
225
- try {
226
- await table.createIndex("content", { config: this.lanceIndex.fts() });
227
- } catch {
228
- // FTS index creation may fail on some platforms — degrade gracefully
229
- }
224
+ // FTS index on the content column.
225
+ await this.createFtsIndex(table);
230
226
  if (collection === this.collection) this.table = table;
231
227
  } catch (err) {
232
228
  log.debug(`LanceDbBackend update failed: ${err}`);
@@ -365,11 +361,7 @@ export class LanceDbBackend implements SearchBackend {
365
361
  vectorProvider: "",
366
362
  };
367
363
  const newTable = await db.createTable(collection, [emptyRow]);
368
- try {
369
- await newTable.createIndex("content", { config: this.lanceIndex.fts() });
370
- } catch {
371
- // FTS index creation may fail — degrade gracefully
372
- }
364
+ await this.createFtsIndex(newTable);
373
365
  try {
374
366
  await newTable.delete("docid = '__placeholder__'");
375
367
  } catch {
@@ -424,11 +416,7 @@ export class LanceDbBackend implements SearchBackend {
424
416
  };
425
417
  this.table = await db.createTable(this.collection, [emptyRow]);
426
418
  // Create FTS index on content column
427
- try {
428
- await this.table.createIndex("content", { config: this.lanceIndex.fts() });
429
- } catch {
430
- // FTS index creation may fail — degrade gracefully
431
- }
419
+ await this.createFtsIndex(this.table);
432
420
  // Remove placeholder row
433
421
  try {
434
422
  await this.table.delete("docid = '__placeholder__'");
@@ -438,6 +426,26 @@ export class LanceDbBackend implements SearchBackend {
438
426
  return this.table;
439
427
  }
440
428
 
429
+ /**
430
+ * Create the FTS index on the content column with the default tokenizer.
431
+ *
432
+ * Known limitation (issue #2187): tantivy's default tokenizer does not
433
+ * segment space-free scripts (CJK/Thai), so lexical recall over those
434
+ * scripts is near zero here. LanceDB's `baseTokenizer: "ngram"` option is
435
+ * not script-aware — it would n-gram English content too, degrading
436
+ * precision and bloating the index — so no CJK-capable configuration is
437
+ * available in the current @lancedb/lancedb API. Non-English lexical recall
438
+ * on this backend rides on the vector tier instead. See
439
+ * docs/search-backends.md ("Non-English content").
440
+ */
441
+ private async createFtsIndex(table: any): Promise<void> {
442
+ try {
443
+ await table.createIndex("content", { config: this.lanceIndex.fts() });
444
+ } catch {
445
+ // FTS index creation may fail on some platforms — degrade gracefully
446
+ }
447
+ }
448
+
441
449
  private async searchTable(
442
450
  table: any,
443
451
  query: string,
@@ -1,8 +1,46 @@
1
1
  import assert from "node:assert/strict";
2
+ import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
3
+ import os from "node:os";
2
4
  import path from "node:path";
3
5
  import test from "node:test";
4
6
 
5
- import { resolveOramaCollectionDbFilePath } from "./orama-backend.js";
7
+ import { EmbedHelper } from "./embed-helper.js";
8
+ import { OramaBackend, resolveOramaCollectionDbFilePath } from "./orama-backend.js";
9
+ import type { PluginConfig } from "../types.js";
10
+
11
+ function noEmbedHelper(): EmbedHelper {
12
+ return new EmbedHelper({} as PluginConfig);
13
+ }
14
+
15
+ async function writeMemoryFact(
16
+ memoryDir: string,
17
+ fileName: string,
18
+ content: string,
19
+ ): Promise<void> {
20
+ await mkdir(path.join(memoryDir, "facts"), { recursive: true });
21
+ await writeFile(path.join(memoryDir, "facts", fileName), content, "utf8");
22
+ }
23
+
24
+ async function createBackend(
25
+ memoryDir: string,
26
+ dbPath: string,
27
+ cjkSegmentationEnabled?: boolean,
28
+ options: { update?: boolean } = {},
29
+ ): Promise<OramaBackend> {
30
+ const backend = new OramaBackend({
31
+ dbPath,
32
+ collection: "openclaw-engram",
33
+ embedHelper: noEmbedHelper(),
34
+ memoryDir,
35
+ embeddingDimension: 4,
36
+ cjkSegmentationEnabled,
37
+ });
38
+ assert.equal(await backend.probe(), true);
39
+ if (options.update !== false) {
40
+ await backend.update();
41
+ }
42
+ return backend;
43
+ }
6
44
 
7
45
  test("Orama collection filenames cannot escape dbPath", () => {
8
46
  const dbPath = path.join("/tmp", "remnic-orama-db");
@@ -25,3 +63,172 @@ test("Orama collection filenames cannot escape dbPath", () => {
25
63
  );
26
64
  }
27
65
  });
66
+
67
+ test("Orama lexical search finds a Japanese fact with no embeddings, at parity with English (issue #2187)", async () => {
68
+ const root = await mkdtemp(path.join(os.tmpdir(), "remnic-orama-cjk-"));
69
+ try {
70
+ await writeMemoryFact(
71
+ root,
72
+ "japanese-fact.md",
73
+ "---\nid: mem-japanese-fact\n---\n東京都庁の所在地は新宿区にある。最寄り駅は都庁前駅だ。",
74
+ );
75
+ await writeMemoryFact(
76
+ root,
77
+ "english-fact.md",
78
+ "---\nid: mem-english-fact\n---\nThe Tokyo Metropolitan Government Office is located in Shinjuku. The nearest station is Tochomae.",
79
+ );
80
+
81
+ const backend = await createBackend(root, path.join(root, "orama-db"));
82
+
83
+ const japanese = await backend.bm25Search("東京都庁の所在地");
84
+ const english = await backend.bm25Search("Tokyo Metropolitan Government Office location");
85
+
86
+ assert.equal(japanese.some((r) => r.docid === "mem-japanese-fact"), true);
87
+ assert.equal(english.some((r) => r.docid === "mem-english-fact"), true);
88
+ } finally {
89
+ await rm(root, { recursive: true, force: true });
90
+ }
91
+ });
92
+
93
+ test("Orama CJK tokenizer rebuilds stale pre-CJK indexes on first open (issue #2187)", async () => {
94
+ const root = await mkdtemp(path.join(os.tmpdir(), "remnic-orama-rebuild-"));
95
+ try {
96
+ await writeMemoryFact(
97
+ root,
98
+ "japanese-fact.md",
99
+ "---\nid: mem-japanese-fact\n---\n東京都庁の所在地は新宿区にある。",
100
+ );
101
+ await writeMemoryFact(
102
+ root,
103
+ "russian-fact.md",
104
+ "---\nid: mem-russian-fact\n---\nПравительство Токио находится в Синдзюку.",
105
+ );
106
+ await writeMemoryFact(
107
+ root,
108
+ "english-fact.md",
109
+ "---\nid: mem-english-fact\n---\nNebula-472 deploy finished in production.",
110
+ );
111
+
112
+ // Phase 1: index with the pre-CJK stock tokenizer (marker "english").
113
+ const legacyBackend = await createBackend(root, path.join(root, "orama-db"), false);
114
+ const legacyJapanese = await legacyBackend.bm25Search("東京都庁の所在地");
115
+ assert.equal(
116
+ legacyJapanese.some((r) => r.docid === "mem-japanese-fact"),
117
+ false,
118
+ "stock tokenizer must not match Japanese phrases",
119
+ );
120
+ const legacyEnglish = await legacyBackend.bm25Search("Nebula-472 deploy");
121
+ assert.equal(legacyEnglish.some((r) => r.docid === "mem-english-fact"), true);
122
+
123
+ // Phase 2: reopen with CJK segmentation on and NO update() call — the
124
+ // stale marker alone must trigger the in-place rebuild during probe().
125
+ const rebuiltBackend = await createBackend(root, path.join(root, "orama-db"), true, {
126
+ update: false,
127
+ });
128
+ const rebuiltJapanese = await rebuiltBackend.bm25Search("東京都庁の所在地");
129
+ assert.equal(rebuiltJapanese.some((r) => r.docid === "mem-japanese-fact"), true);
130
+
131
+ // Non-CJK non-Latin scripts are re-indexed too (whole-word terms), not
132
+ // just CJK/Thai.
133
+ const rebuiltRussian = await rebuiltBackend.bm25Search("Правительство Токио");
134
+ assert.equal(rebuiltRussian.some((r) => r.docid === "mem-russian-fact"), true);
135
+
136
+ // English-corpus behavior is unchanged by the rebuild.
137
+ const rebuiltEnglish = await rebuiltBackend.bm25Search("Nebula-472 deploy");
138
+ assert.equal(rebuiltEnglish.some((r) => r.docid === "mem-english-fact"), true);
139
+ } finally {
140
+ await rm(root, { recursive: true, force: true });
141
+ }
142
+ });
143
+
144
+ test("Orama English-only corpora are not re-indexed when the tokenizer version advances (issue #2187)", async () => {
145
+ const root = await mkdtemp(path.join(os.tmpdir(), "remnic-orama-english-"));
146
+ try {
147
+ await writeMemoryFact(
148
+ root,
149
+ "english-fact.md",
150
+ "---\nid: mem-english-fact\n---\nNebula-472 deploy finished in production.",
151
+ );
152
+
153
+ const legacyBackend = await createBackend(root, path.join(root, "orama-db"), false);
154
+ assert.equal(
155
+ (await legacyBackend.bm25Search("Nebula-472 deploy")).some((r) => r.docid === "mem-english-fact"),
156
+ true,
157
+ );
158
+
159
+ const upgradedBackend = await createBackend(root, path.join(root, "orama-db"), true);
160
+ assert.equal(
161
+ (await upgradedBackend.bm25Search("Nebula-472 deploy")).some((r) => r.docid === "mem-english-fact"),
162
+ true,
163
+ "English recall must survive the tokenizer upgrade",
164
+ );
165
+ } finally {
166
+ await rm(root, { recursive: true, force: true });
167
+ }
168
+ });
169
+
170
+ test("Orama downgrades persisted CJK indexes when segmentation is disabled (issue #2187)", async () => {
171
+ const root = await mkdtemp(path.join(os.tmpdir(), "remnic-orama-downgrade-"));
172
+ try {
173
+ await writeMemoryFact(
174
+ root,
175
+ "japanese-fact.md",
176
+ "---\nid: mem-japanese-fact\n---\n東京都庁の所在地は新宿区にある。",
177
+ );
178
+
179
+ // Phase 1: index with CJK segmentation on (marker "english+cjk-v1").
180
+ const cjkBackend = await createBackend(root, path.join(root, "orama-db"), true);
181
+ assert.equal(
182
+ (await cjkBackend.bm25Search("東京都庁の所在地")).some((r) => r.docid === "mem-japanese-fact"),
183
+ true,
184
+ "CJK tokenizer must match Japanese phrases before the downgrade",
185
+ );
186
+
187
+ // Phase 2: reopen with segmentation disabled and NO update() call — the
188
+ // persisted CJK marker alone must trigger the stock re-index.
189
+ const downgraded = await createBackend(root, path.join(root, "orama-db"), false, {
190
+ update: false,
191
+ });
192
+ assert.equal(
193
+ (await downgraded.bm25Search("東京都庁の所在地")).some((r) => r.docid === "mem-japanese-fact"),
194
+ false,
195
+ "stock tokenizer must not match Japanese phrases after the downgrade",
196
+ );
197
+ } finally {
198
+ await rm(root, { recursive: true, force: true });
199
+ }
200
+ });
201
+
202
+ test("Orama rebuild gate inspects every indexed string field, not only content (issue #2187)", async () => {
203
+ const root = await mkdtemp(path.join(os.tmpdir(), "remnic-orama-pathfield-"));
204
+ try {
205
+ // The only non-Latin text is the FILENAME, which lands in the indexed
206
+ // path field; the body is pure English.
207
+ await writeMemoryFact(
208
+ root,
209
+ "東京-fact.md",
210
+ "---\nid: mem-path-only\n---\nAn English body with no non-Latin characters.",
211
+ );
212
+
213
+ // Phase 1: pre-CJK stock index — the CJK filename never becomes a term.
214
+ const legacyBackend = await createBackend(root, path.join(root, "orama-db"), false);
215
+ assert.equal(
216
+ (await legacyBackend.bm25Search("東京")).some((r) => r.docid === "mem-path-only"),
217
+ false,
218
+ "stock tokenizer must not match the CJK filename",
219
+ );
220
+
221
+ // Phase 2: reopen with segmentation on and NO update() call — the
222
+ // path field alone must gate the in-place re-index.
223
+ const rebuilt = await createBackend(root, path.join(root, "orama-db"), true, {
224
+ update: false,
225
+ });
226
+ assert.equal(
227
+ (await rebuilt.bm25Search("東京")).some((r) => r.docid === "mem-path-only"),
228
+ true,
229
+ "non-Latin text in the path field must gate the rebuild",
230
+ );
231
+ } finally {
232
+ await rm(root, { recursive: true, force: true });
233
+ }
234
+ });
@@ -9,17 +9,28 @@ import {
9
9
  type SearchQueryOptions,
10
10
  type SearchResult,
11
11
  } from "./port.js";
12
- import type { EmbedHelper, EmbedProviderIdentity, EmbedWithProviderResult } from "./embed-helper.js";
13
- import { scanMemoryDir } from "./document-scanner.js";
14
- import { isSearchAborted, throwIfSearchAborted } from "./abort.js";
15
-
16
- export interface OramaBackendOptions {
17
- dbPath: string;
18
- collection: string;
19
- embedHelper: EmbedHelper;
20
- memoryDir: string;
21
- embeddingDimension: number;
22
- }
12
+ import type { EmbedHelper, EmbedProviderIdentity, EmbedWithProviderResult } from "./embed-helper.js";
13
+ import { scanMemoryDir } from "./document-scanner.js";
14
+ import { isSearchAborted, throwIfSearchAborted } from "./abort.js";
15
+ import {
16
+ containsNonLegacyTokenizerChars,
17
+ createCjkCapableTokenizer,
18
+ ORAMA_CJK_TOKENIZER_LANGUAGE,
19
+ } from "./orama-cjk-tokenizer.js";
20
+
21
+ export interface OramaBackendOptions {
22
+ dbPath: string;
23
+ collection: string;
24
+ embedHelper: EmbedHelper;
25
+ memoryDir: string;
26
+ embeddingDimension: number;
27
+ /**
28
+ * Segment space-free scripts (CJK/Thai) in the lexical index. Default
29
+ * `true`; `false` restores the stock English-only tokenizer (issue #2187).
30
+ */
31
+ cjkSegmentationEnabled?: boolean;
32
+ }
33
+
23
34
 
24
35
  const ORAMA_COLLECTION_FILENAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
25
36
 
@@ -57,6 +68,7 @@ export class OramaBackend implements SearchBackend {
57
68
  private readonly embedHelper: EmbedHelper;
58
69
  private readonly memoryDir: string;
59
70
  private readonly embeddingDimension: number;
71
+ private readonly cjkSegmentationEnabled: boolean;
60
72
  private available = false;
61
73
  private db: any = null;
62
74
  private oramaModule: any = null;
@@ -72,6 +84,7 @@ export class OramaBackend implements SearchBackend {
72
84
  this.embedHelper = opts.embedHelper;
73
85
  this.memoryDir = opts.memoryDir;
74
86
  this.embeddingDimension = opts.embeddingDimension;
87
+ this.cjkSegmentationEnabled = opts.cjkSegmentationEnabled !== false;
75
88
  }
76
89
 
77
90
  async probe(): Promise<boolean> {
@@ -127,6 +140,11 @@ export class OramaBackend implements SearchBackend {
127
140
  }
128
141
  }
129
142
 
143
+ /**
144
+ * Full-text (FTS) search only. With the stock tokenizer this cannot match
145
+ * space-free CJK/Thai text lexically — hybrid or vector search provides
146
+ * the fallback for those scripts (issue #2187).
147
+ */
130
148
  async bm25Search(query: string, collection?: string, maxResults?: number, execution?: SearchExecutionOptions): Promise<SearchResult[]> {
131
149
  if (isSearchAborted(execution)) return [];
132
150
  const db = await this.ensureDbForCollection(collection ?? this.collection);
@@ -403,8 +421,11 @@ export class OramaBackend implements SearchBackend {
403
421
  return this.db;
404
422
  }
405
423
 
406
- this.db = await this.migrateLegacyVectorProviderSchema(
407
- await this.persistModule.restore("json", raw),
424
+ this.db = await this.applyTokenizerVersion(
425
+ await this.migrateLegacyVectorProviderSchema(
426
+ await this.persistModule.restore("json", raw),
427
+ this.collection,
428
+ ),
408
429
  this.collection,
409
430
  );
410
431
  return this.db;
@@ -426,8 +447,11 @@ export class OramaBackend implements SearchBackend {
426
447
  return await this.createDb();
427
448
  }
428
449
 
429
- return await this.migrateLegacyVectorProviderSchema(
430
- await this.persistModule.restore("json", raw),
450
+ return await this.applyTokenizerVersion(
451
+ await this.migrateLegacyVectorProviderSchema(
452
+ await this.persistModule.restore("json", raw),
453
+ collection,
454
+ ),
431
455
  collection,
432
456
  );
433
457
  }
@@ -442,7 +466,95 @@ export class OramaBackend implements SearchBackend {
442
466
  vectorProvider: "string",
443
467
  vector: `vector[${this.embeddingDimension}]`,
444
468
  };
445
- return await create({ schema });
469
+ if (!this.cjkSegmentationEnabled) {
470
+ return await create({ schema });
471
+ }
472
+ return await create({
473
+ schema,
474
+ components: { tokenizer: createCjkCapableTokenizer(this.oramaModule) },
475
+ });
476
+ }
477
+
478
+ /**
479
+ * Attach the CJK-capable tokenizer to a restored index and rebuild the
480
+ * full-text index when it predates CJK tokenization. Orama persists
481
+ * `tokenizer.language` with the index, so a marker other than
482
+ * `ORAMA_CJK_TOKENIZER_LANGUAGE` identifies an index whose terms were
483
+ * produced by the stock English tokenizer. Corpora whose content the stock
484
+ * tokenizer and this tokenizer treat identically (pure legacy Latin) need
485
+ * no re-indexing — only the version marker is rewritten for them.
486
+ */
487
+ private async applyTokenizerVersion(db: any, collection: string): Promise<any> {
488
+ const persistedLanguage =
489
+ db?.tokenizer?.language && typeof db.tokenizer.language === "string"
490
+ ? db.tokenizer.language
491
+ : "";
492
+ if (this.cjkSegmentationEnabled) {
493
+ db.tokenizer = createCjkCapableTokenizer(this.oramaModule);
494
+ if (persistedLanguage === ORAMA_CJK_TOKENIZER_LANGUAGE) return db;
495
+ } else {
496
+ // Segmentation disabled: a database persisted under the CJK tokenizer
497
+ // keeps its CJK terms unless it is re-indexed under the stock one, so
498
+ // downgrade it instead of returning it unchanged (issue #2187 round 2).
499
+ if (persistedLanguage !== ORAMA_CJK_TOKENIZER_LANGUAGE) return db;
500
+ db.tokenizer = this.oramaModule.components.tokenizer.createTokenizer({ language: "english" });
501
+ }
502
+
503
+
504
+ try {
505
+ const { search: oramaSearch, count, update: oramaUpdate } = this.oramaModule;
506
+ const existingCount = await count(db);
507
+ if (existingCount === 0) {
508
+ await this.persistDbForCollection(db, collection);
509
+ return db;
510
+ }
511
+ const allHits = await oramaSearch(db, { term: "", limit: existingCount + 100 });
512
+ const hits = allHits.hits ?? [];
513
+ const hasNonLegacyContent = hits.some((hit: any) => {
514
+ const doc = this.getStoredDocument(db, hit);
515
+ // Orama full-text queries every string field by default, so every
516
+ // indexed string field gates the rebuild — non-Latin text that only
517
+ // rides in snippet/path/id would otherwise keep stale terms
518
+ // (issue #2187 review round 2).
519
+ for (const field of [doc.content, doc.snippet, doc.path, doc.id, doc.vectorProvider]) {
520
+ if (typeof field === "string" && containsNonLegacyTokenizerChars(field)) return true;
521
+ }
522
+ return false;
523
+ });
524
+ if (hasNonLegacyContent) {
525
+ // Re-index every document in place (Orama update is remove+insert,
526
+ // so content is re-tokenized; vectors are carried through). A single
527
+ // failing document must not block the rest of the corpus: it keeps
528
+ // its pre-upgrade terms, which is no worse than before the upgrade.
529
+ for (const hit of hits) {
530
+ try {
531
+ const doc = this.getStoredDocument(db, hit);
532
+ const vector = this.getStoredVector(db, hit, doc);
533
+ await oramaUpdate(db, hit.id, {
534
+ id: typeof doc.id === "string" && doc.id.length > 0 ? doc.id : String(hit.id),
535
+ path: typeof doc.path === "string" ? doc.path : "",
536
+ content: typeof doc.content === "string" ? doc.content : "",
537
+ snippet:
538
+ typeof doc.snippet === "string"
539
+ ? doc.snippet
540
+ : typeof doc.content === "string"
541
+ ? doc.content.slice(0, 200)
542
+ : "",
543
+ vectorProvider: typeof doc.vectorProvider === "string" ? doc.vectorProvider : "",
544
+ vector: vector ?? this.zeroVector(),
545
+ });
546
+ } catch (docErr) {
547
+ log.debug(
548
+ `OramaBackend tokenizer-version re-index skipped document ${hit.id} in ${collection}: ${docErr}`,
549
+ );
550
+ }
551
+ }
552
+ }
553
+ await this.persistDbForCollection(db, collection);
554
+ } catch (err) {
555
+ log.debug(`OramaBackend tokenizer-version rebuild for ${collection} failed: ${err}`);
556
+ }
557
+ return db;
446
558
  }
447
559
 
448
560
  private async migrateLegacyVectorProviderSchema(db: any, collection: string): Promise<any> {
@@ -526,8 +638,11 @@ export class OramaBackend implements SearchBackend {
526
638
  await this.ensureModules();
527
639
  const raw = await readFile(filePath, "utf-8");
528
640
  const collection = path.basename(filePath, ".msp");
529
- return await this.migrateLegacyVectorProviderSchema(
530
- await this.persistModule.restore("json", raw),
641
+ return await this.applyTokenizerVersion(
642
+ await this.migrateLegacyVectorProviderSchema(
643
+ await this.persistModule.restore("json", raw),
644
+ collection,
645
+ ),
531
646
  collection,
532
647
  );
533
648
  } catch (err) {