@remnic/core 9.66.7 → 9.66.9

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 (474) hide show
  1. package/dist/access-admin-ops-surface.d.ts +11 -11
  2. package/dist/access-admin-ops-surface.js +41 -41
  3. package/dist/access-authorization-probe.d.ts +11 -11
  4. package/dist/access-authorization-probe.js +42 -42
  5. package/dist/access-boundary.d.ts +11 -11
  6. package/dist/access-boundary.js +41 -41
  7. package/dist/access-cli.js +101 -99
  8. package/dist/access-cli.js.map +1 -1
  9. package/dist/access-coding-context-resolution.d.ts +1 -1
  10. package/dist/access-extraction-force-flush.d.ts +11 -11
  11. package/dist/access-extraction-force-flush.js +41 -41
  12. package/dist/access-health-types.d.ts +1 -1
  13. package/dist/access-http-lcm-compaction.d.ts +11 -11
  14. package/dist/access-http-lifecycle-flush.d.ts +11 -11
  15. package/dist/access-http-offline-stream.d.ts +11 -11
  16. package/dist/access-http-query.d.ts +2 -2
  17. package/dist/access-http-query.js +43 -43
  18. package/dist/access-http.d.ts +12 -12
  19. package/dist/access-http.js +58 -57
  20. package/dist/access-identity-continuity-surface.d.ts +9 -9
  21. package/dist/access-identity-continuity-surface.js +41 -41
  22. package/dist/access-lcm-surface.d.ts +11 -11
  23. package/dist/access-lcm-surface.js +41 -41
  24. package/dist/access-mcp-output-schemas.js +1 -1
  25. package/dist/access-mcp-sse.d.ts +20 -0
  26. package/dist/access-mcp-sse.js +8 -0
  27. package/dist/access-mcp-sse.js.map +1 -0
  28. package/dist/access-mcp.d.ts +11 -11
  29. package/dist/access-mcp.js +50 -50
  30. package/dist/access-memory-search-fanout.d.ts +2 -2
  31. package/dist/{access-namespace-preflight-50VIkPhB.d.ts → access-namespace-preflight-S8fhQcCo.d.ts} +1 -1
  32. package/dist/access-namespace-preflight.d.ts +3 -3
  33. package/dist/access-namespace-preflight.js +41 -41
  34. package/dist/access-observe-write-surface.d.ts +11 -11
  35. package/dist/access-observe-write-surface.js +41 -41
  36. package/dist/access-offline-manifest.d.ts +9 -9
  37. package/dist/access-offline-manifest.js +5 -5
  38. package/dist/access-operations-batch.js +42 -42
  39. package/dist/access-operations.d.ts +11 -11
  40. package/dist/access-operations.js +47 -47
  41. package/dist/access-recall-concurrency.d.ts +11 -11
  42. package/dist/access-recall-concurrency.js +41 -41
  43. package/dist/access-recall-response.d.ts +11 -11
  44. package/dist/access-recall-response.js +41 -41
  45. package/dist/access-recall-surface.d.ts +11 -11
  46. package/dist/access-recall-surface.js +41 -41
  47. package/dist/{access-service-Dz6I9AZ-.d.ts → access-service-DcfM0Vf0.d.ts} +7 -7
  48. package/dist/access-service-helpers.d.ts +11 -11
  49. package/dist/access-service.d.ts +11 -11
  50. package/dist/access-service.js +41 -41
  51. package/dist/access-surface-catalog.d.ts +11 -11
  52. package/dist/access-surface-catalog.js +43 -43
  53. package/dist/access-wearables-meetings-surface.d.ts +3 -3
  54. package/dist/action-confidence.d.ts +1 -1
  55. package/dist/active-memory-bridge.d.ts +1 -1
  56. package/dist/active-recall.d.ts +1 -1
  57. package/dist/active-recall.js +3 -3
  58. package/dist/ambient-provenance.d.ts +1 -1
  59. package/dist/artifact-search.d.ts +1 -1
  60. package/dist/behavior-learner.d.ts +1 -1
  61. package/dist/behavior-signals.d.ts +1 -1
  62. package/dist/bootstrap.d.ts +9 -9
  63. package/dist/briefing-window.d.ts +2 -2
  64. package/dist/briefing.d.ts +2 -2
  65. package/dist/briefing.js +16 -16
  66. package/dist/buffer-surprise-report.d.ts +1 -1
  67. package/dist/buffer-turn-helpers.d.ts +1 -1
  68. package/dist/buffer.d.ts +2 -2
  69. package/dist/buffer.js +5 -5
  70. package/dist/bulk-import/index.d.ts +3 -3
  71. package/dist/calibration.d.ts +1 -1
  72. package/dist/capabilities.d.ts +1 -1
  73. package/dist/{catalog-C2jA-gLm.d.ts → catalog-BmBXTtOs.d.ts} +1 -1
  74. package/dist/causal-behavior.d.ts +1 -1
  75. package/dist/causal-consolidation.d.ts +1 -1
  76. package/dist/causal-consolidation.js +17 -17
  77. package/dist/causal-trajectory-graph.d.ts +1 -1
  78. package/dist/{chunk-52DBRDP5.js → chunk-23F7HGBV.js} +1 -1
  79. package/dist/{chunk-TNXNECAN.js → chunk-2OXIPF3A.js} +4 -4
  80. package/dist/{chunk-MSXUEYH6.js → chunk-3HHLOKKU.js} +2 -2
  81. package/dist/{chunk-OMGQAXUK.js → chunk-47BX23NA.js} +2 -2
  82. package/dist/{chunk-GO657WPH.js → chunk-52I6AHO6.js} +2 -2
  83. package/dist/{chunk-QD55QEEY.js → chunk-5CSKIWEB.js} +5 -5
  84. package/dist/{chunk-NMFPYAJ6.js → chunk-5GZ6UWY5.js} +8 -8
  85. package/dist/{chunk-KSZKQTZS.js → chunk-5KVMT25I.js} +2 -2
  86. package/dist/{chunk-D35XLYQ7.js → chunk-5NZIRM4Q.js} +7 -7
  87. package/dist/{chunk-DB2MKBQ7.js → chunk-7JPKRZD5.js} +2 -2
  88. package/dist/{chunk-Z3YEGSR4.js → chunk-A7GQBJP5.js} +9 -4
  89. package/dist/chunk-A7GQBJP5.js.map +1 -0
  90. package/dist/{chunk-PMNN247H.js → chunk-AAJK3PZ6.js} +2 -2
  91. package/dist/{chunk-6FUMA6AA.js → chunk-B3TZLAO4.js} +2 -2
  92. package/dist/{chunk-C24UZSFW.js → chunk-CEH2AFXG.js} +6 -6
  93. package/dist/{chunk-42GDJAU7.js → chunk-CIWOW2FH.js} +2 -2
  94. package/dist/{chunk-GNWLTCKC.js → chunk-CNZVEU4X.js} +2 -2
  95. package/dist/{chunk-CWPTYKCF.js → chunk-DGKVUPBM.js} +3 -3
  96. package/dist/{chunk-XJE6NHLT.js → chunk-FNYVWAIK.js} +55 -55
  97. package/dist/{chunk-THZ5UEQZ.js → chunk-FUPIAP6Q.js} +3 -3
  98. package/dist/{chunk-POSD62F5.js → chunk-G3TUQJFU.js} +2 -2
  99. package/dist/{chunk-Y3QQZOZ4.js → chunk-G775FE2E.js} +21 -21
  100. package/dist/{chunk-BEUB5ABO.js → chunk-GB4R6B5M.js} +2 -2
  101. package/dist/{chunk-XZBXINXZ.js → chunk-GIC6BASP.js} +4 -4
  102. package/dist/{chunk-6TMIW4HE.js → chunk-HWWGPS2N.js} +2 -2
  103. package/dist/{chunk-PPAKBRI7.js → chunk-IBHUZEKL.js} +2 -2
  104. package/dist/{chunk-6LMRUFBH.js → chunk-J67E4JNT.js} +2 -2
  105. package/dist/{chunk-FKBRP3J2.js → chunk-JHU543UU.js} +2 -2
  106. package/dist/{chunk-OCYRMVPT.js → chunk-JVGBDNXA.js} +2 -2
  107. package/dist/{chunk-IGOINKTD.js → chunk-K4E3Y3ZX.js} +2 -2
  108. package/dist/chunk-K4E3Y3ZX.js.map +1 -0
  109. package/dist/{chunk-GUG4LW4I.js → chunk-KIJCXLW7.js} +2 -2
  110. package/dist/{chunk-IN6D6BJG.js → chunk-KVXMN33W.js} +15 -15
  111. package/dist/chunk-LD72P4YS.js +29 -0
  112. package/dist/chunk-LD72P4YS.js.map +1 -0
  113. package/dist/chunk-LTDN5WYF.js +202 -0
  114. package/dist/chunk-LTDN5WYF.js.map +1 -0
  115. package/dist/{chunk-2C34EKRJ.js → chunk-MBDUNO7J.js} +2 -2
  116. package/dist/{chunk-V6LJENGW.js → chunk-MFI4QPW5.js} +2 -2
  117. package/dist/{chunk-4NKIGSJM.js → chunk-MK7EJLB4.js} +4 -4
  118. package/dist/{chunk-RACZB5HT.js → chunk-N37X5RU7.js} +4 -4
  119. package/dist/{chunk-PORKQEAW.js → chunk-NABJLNLU.js} +139 -107
  120. package/dist/chunk-NABJLNLU.js.map +1 -0
  121. package/dist/{chunk-AG46P24C.js → chunk-NNBZS3DY.js} +4 -4
  122. package/dist/{chunk-J2GY4UCR.js → chunk-NSP3HFJZ.js} +2 -2
  123. package/dist/{chunk-CEK6AHIG.js → chunk-OJSCH7QT.js} +8 -8
  124. package/dist/{chunk-MAWHEUAA.js → chunk-OT7WQ2I3.js} +2 -2
  125. package/dist/{chunk-ZW4SVXEY.js → chunk-Q3UMNZRK.js} +6 -6
  126. package/dist/{chunk-HQI2OQB5.js → chunk-Q5YKVBIV.js} +5 -5
  127. package/dist/{chunk-FHY6HIAY.js → chunk-QU2V4IO3.js} +2 -2
  128. package/dist/{chunk-2SW3N5HX.js → chunk-RF3LMSQW.js} +2 -2
  129. package/dist/{chunk-O7ERGZDA.js → chunk-RJ57OOCD.js} +2 -2
  130. package/dist/{chunk-KDYU3KZT.js → chunk-RLEJULGN.js} +5 -5
  131. package/dist/{chunk-7O24F2VS.js → chunk-SJ5L4ZZX.js} +2 -2
  132. package/dist/{chunk-BWZVFWMX.js → chunk-SOQLXIQX.js} +2 -2
  133. package/dist/{chunk-ZKE227GO.js → chunk-SRILZVR4.js} +2 -2
  134. package/dist/chunk-SRT6SHVZ.js +34 -0
  135. package/dist/chunk-SRT6SHVZ.js.map +1 -0
  136. package/dist/{chunk-2W4MTU4P.js → chunk-TEJKBBWS.js} +32 -26
  137. package/dist/chunk-TEJKBBWS.js.map +1 -0
  138. package/dist/{chunk-YV4ST46A.js → chunk-TKSBOV7N.js} +5 -5
  139. package/dist/{chunk-67U6UK5Q.js → chunk-TWMGWLHD.js} +2 -2
  140. package/dist/{chunk-726CXBJO.js → chunk-UAWSKMWQ.js} +2 -2
  141. package/dist/{chunk-MGVOBLUK.js → chunk-VCYY7XEL.js} +2 -2
  142. package/dist/{chunk-46XR5FNZ.js → chunk-VSWRJQQW.js} +31 -5
  143. package/dist/chunk-VSWRJQQW.js.map +1 -0
  144. package/dist/{chunk-ABPLUXVY.js → chunk-VX5YHEGJ.js} +3 -3
  145. package/dist/{chunk-SFJPCNBI.js → chunk-XVNDP3RO.js} +2 -2
  146. package/dist/{chunk-QVEKPVCG.js → chunk-ZC5L6ME2.js} +3 -3
  147. package/dist/{chunk-VVWOEKOZ.js → chunk-ZJGHOPEO.js} +43 -43
  148. package/dist/{chunk-4COPICMD.js → chunk-ZVUGRXSY.js} +6 -6
  149. package/dist/{cli-BOuEb4Ia.d.ts → cli-CFpMhqz5.d.ts} +5 -5
  150. package/dist/cli.d.ts +13 -13
  151. package/dist/cli.js +77 -76
  152. package/dist/coding/export-okf-codegraph.d.ts +1 -1
  153. package/dist/coding/export-okf-codegraph.js +16 -16
  154. package/dist/coding/pre-action-gate.d.ts +1 -1
  155. package/dist/compounding/engine.d.ts +2 -2
  156. package/dist/compounding/engine.js +16 -16
  157. package/dist/compounding/preference-consolidator.d.ts +1 -1
  158. package/dist/compression-optimizer.d.ts +1 -1
  159. package/dist/config.d.ts +1 -1
  160. package/dist/config.js +3 -3
  161. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  162. package/dist/connectors/codex-materialize-runner.js +16 -16
  163. package/dist/connectors/codex-materialize.d.ts +1 -1
  164. package/dist/connectors/index.d.ts +1 -1
  165. package/dist/connectors/index.js +17 -17
  166. package/dist/consolidation-provenance-check.d.ts +2 -2
  167. package/dist/consolidation-undo.d.ts +2 -2
  168. package/dist/contradiction/index.d.ts +3 -3
  169. package/dist/converge-config.d.ts +1 -1
  170. package/dist/convergence-refresh.d.ts +2 -2
  171. package/dist/convergence-refresh.js +20 -20
  172. package/dist/conversation-index/backend.d.ts +1 -1
  173. package/dist/conversation-index/chunker.d.ts +1 -1
  174. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  175. package/dist/conversation-index/indexer.d.ts +1 -1
  176. package/dist/conversation-index/search.d.ts +1 -1
  177. package/dist/corpus-watermark.d.ts +1 -1
  178. package/dist/corpus-watermark.js +19 -19
  179. package/dist/cross-lingual-recall.d.ts +1 -1
  180. package/dist/day-summary.d.ts +1 -1
  181. package/dist/delinearize.d.ts +1 -1
  182. package/dist/dependency-propagation-config.d.ts +1 -1
  183. package/dist/{dependency-propagation-delivery-D4WMbOwA.d.ts → dependency-propagation-delivery-BC3bCEet.d.ts} +1 -1
  184. package/dist/direct-answer-wiring.d.ts +1 -1
  185. package/dist/direct-answer.d.ts +1 -1
  186. package/dist/embedding-fallback.d.ts +1 -1
  187. package/dist/enrichment/index.d.ts +1 -1
  188. package/dist/entity-origin-fields.d.ts +1 -1
  189. package/dist/entity-retrieval.d.ts +2 -2
  190. package/dist/entity-retrieval.js +16 -16
  191. package/dist/entity-schema.d.ts +1 -1
  192. package/dist/episodic-context.d.ts +1 -1
  193. package/dist/eval-trajectory-contracts.d.ts +1 -1
  194. package/dist/eval-trajectory-store.d.ts +1 -1
  195. package/dist/eval-trajectory.d.ts +1 -1
  196. package/dist/explicit-capture.d.ts +9 -9
  197. package/dist/explicit-capture.js +1 -1
  198. package/dist/external-wiki-access.d.ts +11 -11
  199. package/dist/external-wiki-access.js +42 -42
  200. package/dist/external-wiki-collection-registration.d.ts +1 -1
  201. package/dist/external-wiki-collection.d.ts +1 -1
  202. package/dist/external-wiki-mcp-tools.d.ts +11 -11
  203. package/dist/extraction-error-classification.d.ts +1 -1
  204. package/dist/extraction-faithfulness.d.ts +1 -1
  205. package/dist/extraction-judge-telemetry.d.ts +1 -1
  206. package/dist/extraction-judge-training.d.ts +1 -1
  207. package/dist/extraction-judge.d.ts +1 -1
  208. package/dist/extraction-liveness.d.ts +1 -1
  209. package/dist/extraction-normalization.d.ts +1 -1
  210. package/dist/extraction-prompt.d.ts +1 -1
  211. package/dist/extraction-source-grounding-rules.d.ts +1 -1
  212. package/dist/extraction-source-grounding.d.ts +1 -1
  213. package/dist/extraction.d.ts +1 -1
  214. package/dist/extraction.js +29 -29
  215. package/dist/fallback-llm.d.ts +1 -1
  216. package/dist/{first-start-migration-KHIMCBIC.js → first-start-migration-UG32BSG2.js} +4 -4
  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-reinforcement.d.ts +1 -1
  221. package/dist/graph-path-reconstruction.d.ts +1 -1
  222. package/dist/graph-path-scoring.d.ts +1 -1
  223. package/dist/graph-snapshot.d.ts +1 -1
  224. package/dist/graph.d.ts +1 -1
  225. package/dist/harmonic-retrieval.js +1 -1
  226. package/dist/importance.d.ts +1 -1
  227. package/dist/importers/index.d.ts +1 -1
  228. package/dist/in-flight-reads.d.ts +1 -1
  229. package/dist/{index-DuJnzwHv.d.ts → index-D4hS9uxK.d.ts} +2 -2
  230. package/dist/index.d.ts +43 -24
  231. package/dist/index.js +162 -158
  232. package/dist/intent.d.ts +1 -1
  233. package/dist/lcm/engine.d.ts +1 -1
  234. package/dist/lcm/engine.js +3 -2
  235. package/dist/lcm/index.d.ts +1 -1
  236. package/dist/lcm/index.js +8 -7
  237. package/dist/lcm/tools.d.ts +1 -1
  238. package/dist/lifecycle.d.ts +1 -1
  239. package/dist/live-connectors-runner.d.ts +1 -1
  240. package/dist/local-llm.d.ts +1 -1
  241. package/dist/local-model-endpoint.d.ts +1 -1
  242. package/dist/location/index.d.ts +3 -3
  243. package/dist/location/index.js +47 -47
  244. package/dist/maintenance/memory-governance.d.ts +1 -1
  245. package/dist/maintenance/memory-governance.js +17 -17
  246. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  247. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +17 -17
  248. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  249. package/dist/maintenance/rebuild-memory-projection.js +19 -19
  250. package/dist/{maintenance-BBeaeYRR.d.ts → maintenance-BRcc3Hx8.d.ts} +3 -3
  251. package/dist/mcp-memory-inspector-app.d.ts +11 -11
  252. package/dist/memory-action-policy.d.ts +1 -1
  253. package/dist/memory-cache.d.ts +1 -1
  254. package/dist/memory-controller.d.ts +1 -1
  255. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  256. package/dist/memory-projection-store.d.ts +1 -1
  257. package/dist/memory-provenance.d.ts +1 -1
  258. package/dist/memory-snapshot.d.ts +1 -1
  259. package/dist/memory-subject-cli.d.ts +11 -11
  260. package/dist/memory-subject.d.ts +11 -11
  261. package/dist/memory-worth-outcomes.d.ts +2 -2
  262. package/dist/models-json.d.ts +1 -1
  263. package/dist/namespaces/migrate.d.ts +3 -3
  264. package/dist/namespaces/migrate.js +17 -17
  265. package/dist/namespaces/principal.d.ts +1 -1
  266. package/dist/namespaces/search.d.ts +1 -1
  267. package/dist/namespaces/search.js +9 -9
  268. package/dist/namespaces/storage.d.ts +3 -3
  269. package/dist/namespaces/storage.js +16 -16
  270. package/dist/native-binding-hint.d.ts +24 -0
  271. package/dist/native-binding-hint.js +10 -0
  272. package/dist/native-binding-hint.js.map +1 -0
  273. package/dist/native-knowledge.d.ts +1 -1
  274. package/dist/offline-sync-impression-drain.d.ts +1 -1
  275. package/dist/offline-sync-impression-drain.js +4 -4
  276. package/dist/operator-doctor-corpus.d.ts +1 -1
  277. package/dist/operator-doctor-corpus.js +20 -20
  278. package/dist/operator-doctor-replica.d.ts +1 -1
  279. package/dist/operator-toolkit.d.ts +3 -3
  280. package/dist/operator-toolkit.js +30 -30
  281. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  282. package/dist/orchestration/maintenance.d.ts +4 -4
  283. package/dist/orchestration/maintenance.js +31 -31
  284. package/dist/{orchestrator-CaqnwNwM.d.ts → orchestrator-Btq9lzAN.d.ts} +8 -8
  285. package/dist/orchestrator.d.ts +9 -9
  286. package/dist/orchestrator.js +124 -122
  287. package/dist/patterns-cli.d.ts +1 -1
  288. package/dist/{pipeline-CrxVjlJr.d.ts → pipeline-CZoNdFb5.d.ts} +1 -1
  289. package/dist/policy-runtime.d.ts +1 -1
  290. package/dist/proactive-contention.d.ts +1 -1
  291. package/dist/provenance.d.ts +1 -1
  292. package/dist/{public-http-CmQRjQCD.d.ts → public-http-C9-CHc40.d.ts} +1 -1
  293. package/dist/{qmd-BZgbJm0g.d.ts → qmd-VIjSCKIE.d.ts} +1 -1
  294. package/dist/qmd-preflight.d.ts +2 -2
  295. package/dist/qmd-recall-cache.d.ts +1 -1
  296. package/dist/qmd.d.ts +2 -2
  297. package/dist/qmd.js +4 -4
  298. package/dist/recall-concurrency-config.d.ts +1 -1
  299. package/dist/recall-disclosure-escalation.d.ts +1 -1
  300. package/dist/recall-explain-renderer.d.ts +1 -1
  301. package/dist/recall-memory-map.d.ts +1 -1
  302. package/dist/recall-navigate-access.d.ts +1 -1
  303. package/dist/recall-navigate.d.ts +1 -1
  304. package/dist/recall-planner-llm.d.ts +1 -1
  305. package/dist/recall-state.d.ts +1 -1
  306. package/dist/recall-tag-filter.d.ts +1 -1
  307. package/dist/recall-timings.d.ts +1 -1
  308. package/dist/recall-xray-cli.d.ts +1 -1
  309. package/dist/recall-xray-renderer.d.ts +1 -1
  310. package/dist/recall-xray.d.ts +1 -1
  311. package/dist/reconcile/cursor.d.ts +1 -1
  312. package/dist/reconcile/manifest.d.ts +1 -1
  313. package/dist/reconcile/plan.d.ts +1 -1
  314. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  315. package/dist/replay/normalizers/claude.d.ts +1 -1
  316. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  317. package/dist/replay/normalizers/shared.d.ts +1 -1
  318. package/dist/replay/runner.d.ts +1 -1
  319. package/dist/replay/types.d.ts +1 -1
  320. package/dist/replica-divergence.d.ts +1 -1
  321. package/dist/replica-peers-config.d.ts +1 -1
  322. package/dist/resolve-auth-token.d.ts +1 -1
  323. package/dist/resume-bundles.js +4 -4
  324. package/dist/retrieval-agents.d.ts +2 -2
  325. package/dist/retrieval-tiers.d.ts +1 -1
  326. package/dist/routing/engine.d.ts +1 -1
  327. package/dist/routing/store.d.ts +1 -1
  328. package/dist/salvage-envelope.d.ts +1 -1
  329. package/dist/schemas.d.ts +24 -24
  330. package/dist/{scope-profiles-DFaojvoP.d.ts → scope-profiles-DqbxQXIS.d.ts} +1 -1
  331. package/dist/search/embed-helper.d.ts +1 -1
  332. package/dist/search/factory.d.ts +1 -1
  333. package/dist/search/factory.js +8 -8
  334. package/dist/search/index.d.ts +1 -1
  335. package/dist/search/index.js +12 -12
  336. package/dist/search/lancedb-backend.d.ts +1 -1
  337. package/dist/search/lancedb-backend.js +2 -2
  338. package/dist/search/meilisearch-backend.d.ts +1 -1
  339. package/dist/search/meilisearch-backend.js +2 -2
  340. package/dist/search/noop-backend.d.ts +1 -1
  341. package/dist/search/orama-backend.d.ts +1 -1
  342. package/dist/search/orama-backend.js +2 -2
  343. package/dist/search/port.d.ts +1 -1
  344. package/dist/search/remote-backend.d.ts +1 -1
  345. package/dist/{semantic-consolidation-BiX68wZA.d.ts → semantic-consolidation-DW3rEUoW.d.ts} +1 -1
  346. package/dist/semantic-consolidation.d.ts +2 -2
  347. package/dist/semantic-consolidation.js +17 -17
  348. package/dist/semantic-rule-promotion.js +16 -16
  349. package/dist/semantic-rule-verifier.d.ts +1 -1
  350. package/dist/semantic-rule-verifier.js +16 -16
  351. package/dist/{service-D5h2zZ0M.d.ts → service-B2vJU_Bx.d.ts} +2 -2
  352. package/dist/session-observer-bands.d.ts +1 -1
  353. package/dist/session-observer-state.d.ts +1 -1
  354. package/dist/shared-context/manager.d.ts +1 -1
  355. package/dist/signal.d.ts +1 -1
  356. package/dist/source-agent-qualifier.d.ts +1 -1
  357. package/dist/source-agent-qualifier.js +27 -27
  358. package/dist/standup/build.d.ts +9 -3
  359. package/dist/standup/build.js +99 -7
  360. package/dist/{storage-CtsaojWD.d.ts → storage-6fn7BPmb.d.ts} +1 -1
  361. package/dist/storage.d.ts +2 -2
  362. package/dist/storage.js +15 -15
  363. package/dist/subject-config.d.ts +1 -1
  364. package/dist/summarizer.d.ts +1 -1
  365. package/dist/summary-snapshot.d.ts +1 -1
  366. package/dist/support-passport/index.d.ts +14 -14
  367. package/dist/support-passport/index.js +44 -44
  368. package/dist/temporal-supersession.d.ts +2 -2
  369. package/dist/temporal-timeline-recall.d.ts +1 -1
  370. package/dist/temporal-validity.d.ts +1 -1
  371. package/dist/threading.d.ts +1 -1
  372. package/dist/tier-migration.d.ts +2 -2
  373. package/dist/tier-routing.d.ts +1 -1
  374. package/dist/topics.d.ts +1 -1
  375. package/dist/transcript.d.ts +1 -1
  376. package/dist/transfer/export-okf.d.ts +1 -1
  377. package/dist/transfer/export-okf.js +17 -17
  378. package/dist/trust-score-stage.d.ts +1 -1
  379. package/dist/trust-score.d.ts +1 -1
  380. package/dist/{types-CIpfYz1I.d.ts → types-eM7QIcX2.d.ts} +4 -0
  381. package/dist/types.d.ts +1 -1
  382. package/dist/utility-runtime.d.ts +1 -1
  383. package/dist/verified-recall.js +16 -16
  384. package/dist/who-knows-cli.d.ts +11 -11
  385. package/dist/who-knows-cli.js +17 -17
  386. package/dist/who-knows.d.ts +11 -11
  387. package/dist/who-knows.js +16 -16
  388. package/dist/write-envelope.d.ts +1 -1
  389. package/package.json +2 -2
  390. package/scripts/ensure-better-sqlite3.mjs +10 -0
  391. package/src/access-http.test.ts +41 -17
  392. package/src/access-http.ts +10 -10
  393. package/src/access-mcp-output-schemas.ts +1 -1
  394. package/src/access-mcp-sse.ts +50 -0
  395. package/src/activity/config.test.ts +1 -1
  396. package/src/activity/config.ts +20 -4
  397. package/src/activity/journal.test.ts +40 -0
  398. package/src/activity/timeline/index.ts +1 -0
  399. package/src/activity/timeline/recap-window.test.ts +129 -0
  400. package/src/activity/timeline/recap-window.ts +55 -0
  401. package/src/activity/types.ts +4 -0
  402. package/src/config.test.ts +1 -1
  403. package/src/dedup/index.ts +7 -0
  404. package/src/dedup/merge-decision.test.ts +157 -0
  405. package/src/dedup/merge-decision.ts +78 -0
  406. package/src/lcm/engine.ts +4 -1
  407. package/src/native-binding-hint.test.ts +38 -0
  408. package/src/native-binding-hint.ts +51 -0
  409. package/src/standup/build.test.ts +138 -12
  410. package/src/standup/build.ts +172 -23
  411. package/src/standup/http-glue.ts +1 -1
  412. package/dist/chunk-2W4MTU4P.js.map +0 -1
  413. package/dist/chunk-46XR5FNZ.js.map +0 -1
  414. package/dist/chunk-IGOINKTD.js.map +0 -1
  415. package/dist/chunk-PORKQEAW.js.map +0 -1
  416. package/dist/chunk-VOSWUO3K.js +0 -100
  417. package/dist/chunk-VOSWUO3K.js.map +0 -1
  418. package/dist/chunk-Z3YEGSR4.js.map +0 -1
  419. /package/dist/{chunk-52DBRDP5.js.map → chunk-23F7HGBV.js.map} +0 -0
  420. /package/dist/{chunk-TNXNECAN.js.map → chunk-2OXIPF3A.js.map} +0 -0
  421. /package/dist/{chunk-MSXUEYH6.js.map → chunk-3HHLOKKU.js.map} +0 -0
  422. /package/dist/{chunk-OMGQAXUK.js.map → chunk-47BX23NA.js.map} +0 -0
  423. /package/dist/{chunk-GO657WPH.js.map → chunk-52I6AHO6.js.map} +0 -0
  424. /package/dist/{chunk-QD55QEEY.js.map → chunk-5CSKIWEB.js.map} +0 -0
  425. /package/dist/{chunk-NMFPYAJ6.js.map → chunk-5GZ6UWY5.js.map} +0 -0
  426. /package/dist/{chunk-KSZKQTZS.js.map → chunk-5KVMT25I.js.map} +0 -0
  427. /package/dist/{chunk-D35XLYQ7.js.map → chunk-5NZIRM4Q.js.map} +0 -0
  428. /package/dist/{chunk-DB2MKBQ7.js.map → chunk-7JPKRZD5.js.map} +0 -0
  429. /package/dist/{chunk-PMNN247H.js.map → chunk-AAJK3PZ6.js.map} +0 -0
  430. /package/dist/{chunk-6FUMA6AA.js.map → chunk-B3TZLAO4.js.map} +0 -0
  431. /package/dist/{chunk-C24UZSFW.js.map → chunk-CEH2AFXG.js.map} +0 -0
  432. /package/dist/{chunk-42GDJAU7.js.map → chunk-CIWOW2FH.js.map} +0 -0
  433. /package/dist/{chunk-GNWLTCKC.js.map → chunk-CNZVEU4X.js.map} +0 -0
  434. /package/dist/{chunk-CWPTYKCF.js.map → chunk-DGKVUPBM.js.map} +0 -0
  435. /package/dist/{chunk-XJE6NHLT.js.map → chunk-FNYVWAIK.js.map} +0 -0
  436. /package/dist/{chunk-THZ5UEQZ.js.map → chunk-FUPIAP6Q.js.map} +0 -0
  437. /package/dist/{chunk-POSD62F5.js.map → chunk-G3TUQJFU.js.map} +0 -0
  438. /package/dist/{chunk-Y3QQZOZ4.js.map → chunk-G775FE2E.js.map} +0 -0
  439. /package/dist/{chunk-BEUB5ABO.js.map → chunk-GB4R6B5M.js.map} +0 -0
  440. /package/dist/{chunk-XZBXINXZ.js.map → chunk-GIC6BASP.js.map} +0 -0
  441. /package/dist/{chunk-6TMIW4HE.js.map → chunk-HWWGPS2N.js.map} +0 -0
  442. /package/dist/{chunk-PPAKBRI7.js.map → chunk-IBHUZEKL.js.map} +0 -0
  443. /package/dist/{chunk-6LMRUFBH.js.map → chunk-J67E4JNT.js.map} +0 -0
  444. /package/dist/{chunk-FKBRP3J2.js.map → chunk-JHU543UU.js.map} +0 -0
  445. /package/dist/{chunk-OCYRMVPT.js.map → chunk-JVGBDNXA.js.map} +0 -0
  446. /package/dist/{chunk-GUG4LW4I.js.map → chunk-KIJCXLW7.js.map} +0 -0
  447. /package/dist/{chunk-IN6D6BJG.js.map → chunk-KVXMN33W.js.map} +0 -0
  448. /package/dist/{chunk-2C34EKRJ.js.map → chunk-MBDUNO7J.js.map} +0 -0
  449. /package/dist/{chunk-V6LJENGW.js.map → chunk-MFI4QPW5.js.map} +0 -0
  450. /package/dist/{chunk-4NKIGSJM.js.map → chunk-MK7EJLB4.js.map} +0 -0
  451. /package/dist/{chunk-RACZB5HT.js.map → chunk-N37X5RU7.js.map} +0 -0
  452. /package/dist/{chunk-AG46P24C.js.map → chunk-NNBZS3DY.js.map} +0 -0
  453. /package/dist/{chunk-J2GY4UCR.js.map → chunk-NSP3HFJZ.js.map} +0 -0
  454. /package/dist/{chunk-CEK6AHIG.js.map → chunk-OJSCH7QT.js.map} +0 -0
  455. /package/dist/{chunk-MAWHEUAA.js.map → chunk-OT7WQ2I3.js.map} +0 -0
  456. /package/dist/{chunk-ZW4SVXEY.js.map → chunk-Q3UMNZRK.js.map} +0 -0
  457. /package/dist/{chunk-HQI2OQB5.js.map → chunk-Q5YKVBIV.js.map} +0 -0
  458. /package/dist/{chunk-FHY6HIAY.js.map → chunk-QU2V4IO3.js.map} +0 -0
  459. /package/dist/{chunk-2SW3N5HX.js.map → chunk-RF3LMSQW.js.map} +0 -0
  460. /package/dist/{chunk-O7ERGZDA.js.map → chunk-RJ57OOCD.js.map} +0 -0
  461. /package/dist/{chunk-KDYU3KZT.js.map → chunk-RLEJULGN.js.map} +0 -0
  462. /package/dist/{chunk-7O24F2VS.js.map → chunk-SJ5L4ZZX.js.map} +0 -0
  463. /package/dist/{chunk-BWZVFWMX.js.map → chunk-SOQLXIQX.js.map} +0 -0
  464. /package/dist/{chunk-ZKE227GO.js.map → chunk-SRILZVR4.js.map} +0 -0
  465. /package/dist/{chunk-YV4ST46A.js.map → chunk-TKSBOV7N.js.map} +0 -0
  466. /package/dist/{chunk-67U6UK5Q.js.map → chunk-TWMGWLHD.js.map} +0 -0
  467. /package/dist/{chunk-726CXBJO.js.map → chunk-UAWSKMWQ.js.map} +0 -0
  468. /package/dist/{chunk-MGVOBLUK.js.map → chunk-VCYY7XEL.js.map} +0 -0
  469. /package/dist/{chunk-ABPLUXVY.js.map → chunk-VX5YHEGJ.js.map} +0 -0
  470. /package/dist/{chunk-SFJPCNBI.js.map → chunk-XVNDP3RO.js.map} +0 -0
  471. /package/dist/{chunk-QVEKPVCG.js.map → chunk-ZC5L6ME2.js.map} +0 -0
  472. /package/dist/{chunk-VVWOEKOZ.js.map → chunk-ZJGHOPEO.js.map} +0 -0
  473. /package/dist/{chunk-4COPICMD.js.map → chunk-ZVUGRXSY.js.map} +0 -0
  474. /package/dist/{first-start-migration-KHIMCBIC.js.map → first-start-migration-UG32BSG2.js.map} +0 -0
@@ -1,5 +1,6 @@
1
1
  import { coerceBooleanLike, coerceNumber } from "../connectors/coerce.js";
2
2
  import { assertValidTimezone } from "./digest.js";
3
+ import { resolveJournalSource } from "./journal-source.js";
3
4
  import type { ImportanceLevel } from "../types.js";
4
5
  import type {
5
6
  ActivityConfig,
@@ -29,7 +30,7 @@ export function defaultActivityConfig(): ActivityConfig {
29
30
  minConfidence: 0.7,
30
31
  minImportance: "normal",
31
32
  maxMemoriesPerDay: 0,
32
- timeline: { enabled: false, journal: { enabled: false }, qa: { enabled: false, maxRangeDays: 31 } },
33
+ timeline: { enabled: false, journal: { enabled: false, source: "file" }, qa: { enabled: false, maxRangeDays: 31 } },
33
34
  };
34
35
  }
35
36
 
@@ -200,7 +201,7 @@ export function parseActivityConfig(raw: unknown): ActivityConfig {
200
201
  * is malformed and must fail rather than silently disabling the layer.
201
202
  */
202
203
  function parseTimelineConfig(raw: unknown): ActivityTimelineConfig {
203
- if (raw === undefined) return { enabled: false, journal: { enabled: false }, qa: parseTimelineQaConfig(undefined) };
204
+ if (raw === undefined) return { enabled: false, journal: { enabled: false, source: "file" }, qa: parseTimelineQaConfig(undefined) };
204
205
  if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
205
206
  throw new TypeError("activity.timeline must be an object");
206
207
  }
@@ -217,7 +218,7 @@ function parseTimelineConfig(raw: unknown): ActivityTimelineConfig {
217
218
  }
218
219
 
219
220
  function parseTimelineJournalConfig(raw: unknown): ActivityTimelineJournalConfig {
220
- if (raw === undefined) return { enabled: false };
221
+ if (raw === undefined) return { enabled: false, source: "file" };
221
222
  if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
222
223
  throw new TypeError("activity.timeline.journal must be an object");
223
224
  }
@@ -226,7 +227,22 @@ function parseTimelineJournalConfig(raw: unknown): ActivityTimelineJournalConfig
226
227
  if (journal.enabled !== undefined && enabledValue === undefined) {
227
228
  throw new TypeError("activity.timeline.journal.enabled must be a boolean");
228
229
  }
229
- return { enabled: enabledValue ?? false };
230
+ const heading = journal.heading;
231
+ if (heading !== undefined && typeof heading !== "string") {
232
+ throw new TypeError("activity.timeline.journal.heading must be a string");
233
+ }
234
+ const source = journal.source === undefined ? "file" : typeof journal.source === "string" ? journal.source : "";
235
+ const resolved = resolveJournalSource({ source, heading: heading ?? "" });
236
+ if (!resolved.ok) {
237
+ if (resolved.error === "unknown_source") {
238
+ throw new RangeError('activity.timeline.journal.source must be one of "file", "vault"');
239
+ }
240
+ throw new RangeError('activity.timeline.journal.heading must be a non-empty string when source is "vault"');
241
+ }
242
+ if (resolved.mode === "vault") {
243
+ return { enabled: enabledValue ?? false, source: "vault", heading: resolved.heading };
244
+ }
245
+ return { enabled: enabledValue ?? false, source: "file" };
230
246
  }
231
247
 
232
248
  function parseTimelineQaConfig(raw: unknown): ActivityTimelineQaConfig {
@@ -32,6 +32,46 @@ test("activity.timeline.journal.enabled defaults off", () => {
32
32
  );
33
33
  });
34
34
 
35
+ test("activity.timeline.journal source defaults to file with no heading", () => {
36
+ const journal = parseActivityConfig(undefined).timeline.journal;
37
+ assert.equal(journal.source, "file");
38
+ assert.equal(journal.heading, undefined);
39
+ });
40
+
41
+ test("activity.timeline.journal vault mode trims and stores the heading", () => {
42
+ const journal = parseActivityConfig({ timeline: { journal: { enabled: true, source: "vault", heading: " Journal " } } }).timeline.journal;
43
+ assert.deepEqual(journal, { enabled: true, source: "vault", heading: "Journal" });
44
+ });
45
+
46
+ test("activity.timeline.journal vault mode requires a non-empty heading", () => {
47
+ for (const heading of [undefined, "", " "]) {
48
+ assert.throws(
49
+ () => parseActivityConfig({ timeline: { journal: { source: "vault", heading } } }),
50
+ RangeError,
51
+ );
52
+ }
53
+ });
54
+
55
+ test("activity.timeline.journal rejects an unknown source", () => {
56
+ assert.throws(
57
+ () => parseActivityConfig({ timeline: { journal: { source: "memoryDir" } } }),
58
+ /activity\.timeline\.journal\.source must be one of "file", "vault"/,
59
+ );
60
+ });
61
+
62
+ test("activity.timeline.journal rejects a non-string heading", () => {
63
+ assert.throws(
64
+ () => parseActivityConfig({ timeline: { journal: { heading: 5 } } }),
65
+ /activity\.timeline\.journal\.heading must be a string/,
66
+ );
67
+ });
68
+
69
+ test("activity.timeline.journal file mode ignores a provided heading", () => {
70
+ const journal = parseActivityConfig({ timeline: { journal: { source: "file", heading: "Ignored" } } }).timeline.journal;
71
+ assert.deepEqual(journal, { enabled: false, source: "file" });
72
+ assert.equal("heading" in journal, false);
73
+ });
74
+
35
75
  test("seed is a hard no-op without force", () => {
36
76
  withMemoryDir((memoryDir) => {
37
77
  const first = seedJournal({
@@ -19,3 +19,4 @@ export * from "./analysis-evidence.js";
19
19
  export * from "./analysis-prompt.js";
20
20
  export * from "./analysis-claim.js";
21
21
  export * from "./analysis-order.js";
22
+ export * from "./recap-window.js";
@@ -0,0 +1,129 @@
1
+ import assert from "node:assert/strict";
2
+ import { describe, it } from "node:test";
3
+
4
+ import {
5
+ clipCardsToRecapWindow,
6
+ type RecapWindowCard,
7
+ } from "./recap-window.js";
8
+
9
+ const MINUTE = 60_000;
10
+ const DAY_START = Date.UTC(2026, 0, 15); // 2026-01-15T00:00:00Z
11
+ const DAY_END = DAY_START + 24 * 60 * 60_000;
12
+
13
+ const iso = (ms: number): string => new Date(ms).toISOString();
14
+
15
+ const card = (id: string, startMs: number, endMs: number): RecapWindowCard => ({
16
+ id,
17
+ startUtc: iso(startMs),
18
+ endUtc: iso(endMs),
19
+ });
20
+
21
+ describe("clipCardsToRecapWindow", () => {
22
+ it("returns [] for empty input", () => {
23
+ assert.deepEqual(clipCardsToRecapWindow([], DAY_START, DAY_END), []);
24
+ });
25
+
26
+ it("excludes a card ending exactly at windowStart and one starting exactly at windowEnd", () => {
27
+ const before = card("before", DAY_START - 2 * MINUTE, DAY_START);
28
+ const after = card("after", DAY_END, DAY_END + 2 * MINUTE);
29
+ const inside = card("inside", DAY_START, DAY_END);
30
+
31
+ const result = clipCardsToRecapWindow([before, after, inside], DAY_START, DAY_END);
32
+
33
+ assert.deepEqual(
34
+ result.map((c) => c.id),
35
+ ["inside"],
36
+ );
37
+ assert.equal(result[0]?.startMs, DAY_START);
38
+ assert.equal(result[0]?.endMs, DAY_END);
39
+ assert.equal(result[0]?.durationMs, DAY_END - DAY_START);
40
+
41
+ // Each midnight-touching card lands in exactly one adjacent window.
42
+ const windowMs = DAY_END - DAY_START;
43
+ const prevDay = clipCardsToRecapWindow([before], DAY_START - windowMs, DAY_START);
44
+ const nextDay = clipCardsToRecapWindow([after], DAY_END, DAY_END + windowMs);
45
+ assert.equal(prevDay[0]?.id, "before");
46
+ assert.equal(nextDay[0]?.id, "after");
47
+ });
48
+
49
+ it("clips a card straddling the window start", () => {
50
+ const straddle = card("straddle", DAY_START - 30 * MINUTE, DAY_START + 90 * MINUTE);
51
+
52
+ const result = clipCardsToRecapWindow([straddle], DAY_START, DAY_END);
53
+
54
+ assert.equal(result.length, 1);
55
+ assert.equal(result[0]?.startMs, DAY_START);
56
+ assert.equal(result[0]?.endMs, DAY_START + 90 * MINUTE);
57
+ assert.equal(result[0]?.durationMs, 90 * MINUTE);
58
+ });
59
+
60
+ it("clips a card straddling the window end", () => {
61
+ const straddle = card("tail", DAY_END - 5 * MINUTE, DAY_END + 45 * MINUTE);
62
+
63
+ const result = clipCardsToRecapWindow([straddle], DAY_START, DAY_END);
64
+
65
+ assert.equal(result.length, 1);
66
+ assert.equal(result[0]?.endMs, DAY_END);
67
+ assert.equal(result[0]?.durationMs, 5 * MINUTE);
68
+ });
69
+
70
+ it("skips cards with unparseable timestamps without throwing", () => {
71
+ const good = card("good", DAY_START + MINUTE, DAY_START + 10 * MINUTE);
72
+ const bad: RecapWindowCard[] = [
73
+ { id: "bad-start", startUtc: "not-a-date", endUtc: iso(DAY_START + 5 * MINUTE) },
74
+ { id: "bad-end", startUtc: iso(DAY_START), endUtc: "" },
75
+ good,
76
+ ];
77
+
78
+ const result = clipCardsToRecapWindow(bad, DAY_START, DAY_END);
79
+
80
+ assert.deepEqual(
81
+ result.map((c) => c.id),
82
+ ["good"],
83
+ );
84
+ assert.equal(result[0]?.durationMs, 9 * MINUTE);
85
+ });
86
+
87
+ it("throws RangeError on inverted or empty window", () => {
88
+ assert.throws(
89
+ () => clipCardsToRecapWindow([], DAY_END, DAY_START),
90
+ RangeError,
91
+ );
92
+ assert.throws(
93
+ () => clipCardsToRecapWindow([], DAY_START, DAY_START),
94
+ RangeError,
95
+ );
96
+ });
97
+
98
+ it("throws RangeError on non-finite window bounds", () => {
99
+ // NaN and Infinity pass `end <= start`, so without an explicit finite
100
+ // check they would produce NaN timestamps instead of an error.
101
+ for (const [start, end] of [
102
+ [Number.NaN, DAY_END],
103
+ [DAY_START, Number.NaN],
104
+ [Number.POSITIVE_INFINITY, DAY_END],
105
+ [DAY_START, Number.POSITIVE_INFINITY],
106
+ ] as const) {
107
+ assert.throws(() => clipCardsToRecapWindow([], start, end), /finite/);
108
+ }
109
+ });
110
+
111
+ it("sorts by startMs then id, byte-identical across calls", () => {
112
+ const same = DAY_START + 60 * MINUTE;
113
+ const cards: RecapWindowCard[] = [
114
+ card("z-late", DAY_START + 120 * MINUTE, DAY_START + 130 * MINUTE),
115
+ card("b-tie", same, same + 10 * MINUTE),
116
+ card("a-tie", same, same + 10 * MINUTE),
117
+ card("early", DAY_START + 5 * MINUTE, DAY_START + 6 * MINUTE),
118
+ ];
119
+
120
+ const first = clipCardsToRecapWindow(cards, DAY_START, DAY_END);
121
+ const second = clipCardsToRecapWindow(cards, DAY_START, DAY_END);
122
+
123
+ assert.deepEqual(
124
+ first.map((c) => c.id),
125
+ ["early", "a-tie", "b-tie", "z-late"],
126
+ );
127
+ assert.deepEqual(first, second);
128
+ });
129
+ });
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Deterministic half-open recap window clip (issue #2051).
3
+ *
4
+ * Clips cards to [windowStartMs, windowEndMs) so recap renderers share one
5
+ * day-boundary derivation instead of re-deriving it per renderer.
6
+ */
7
+ export interface RecapWindowCard {
8
+ id: string;
9
+ startUtc: string;
10
+ endUtc: string;
11
+ }
12
+
13
+ export interface ClippedRecapCard {
14
+ id: string;
15
+ startMs: number;
16
+ endMs: number;
17
+ durationMs: number;
18
+ }
19
+
20
+ export function clipCardsToRecapWindow(
21
+ cards: readonly RecapWindowCard[],
22
+ windowStartMs: number,
23
+ windowEndMs: number,
24
+ ): ClippedRecapCard[] {
25
+ // NaN fails every comparison, so an unchecked non-finite bound slips past the
26
+ // ordering guard and emits NaN timestamps and durations — `durationMs <= 0`
27
+ // is also false for NaN, so the card is not even dropped.
28
+ if (!Number.isFinite(windowStartMs) || !Number.isFinite(windowEndMs)) {
29
+ throw new RangeError(
30
+ `recap window bounds must be finite; got start ${windowStartMs} and end ${windowEndMs}`,
31
+ );
32
+ }
33
+ if (windowEndMs <= windowStartMs) {
34
+ throw new RangeError(
35
+ `recap window end ${windowEndMs} must be greater than start ${windowStartMs}`,
36
+ );
37
+ }
38
+ const out: ClippedRecapCard[] = [];
39
+ for (const card of cards) {
40
+ const startMs = Date.parse(card.startUtc);
41
+ const endMs = Date.parse(card.endUtc);
42
+ if (!Number.isFinite(startMs) || !Number.isFinite(endMs)) {
43
+ continue;
44
+ }
45
+ const clippedStart = Math.max(startMs, windowStartMs);
46
+ const clippedEnd = Math.min(endMs, windowEndMs);
47
+ const durationMs = clippedEnd - clippedStart;
48
+ if (durationMs <= 0) {
49
+ continue;
50
+ }
51
+ out.push({ id: card.id, startMs: clippedStart, endMs: clippedEnd, durationMs });
52
+ }
53
+ out.sort((a, b) => a.startMs - b.startMs || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
54
+ return out;
55
+ }
@@ -99,6 +99,10 @@ export interface ActivitySourceConfig {
99
99
  /** Opt-in daily journal settings (issue #1984). Default off. */
100
100
  export interface ActivityTimelineJournalConfig {
101
101
  enabled: boolean;
102
+ /** Where the journal text is read from (issue #1987). */
103
+ source: "file" | "vault";
104
+ /** Vault section heading, trimmed. Required when `source` is `"vault"`; not stored in `"file"` mode. */
105
+ heading?: string;
102
106
  }
103
107
 
104
108
  /** Opt-in timeline Q&A range/search settings (issue #1983 PR1). Default off. */
@@ -2569,7 +2569,7 @@ test("parseConfig forwards activity source settings", () => {
2569
2569
  minConfidence: 0.7,
2570
2570
  minImportance: "normal",
2571
2571
  maxMemoriesPerDay: 0,
2572
- timeline: { enabled: false, journal: { enabled: false }, qa: { enabled: false, maxRangeDays: 31 } },
2572
+ timeline: { enabled: false, journal: { enabled: false, source: "file" }, qa: { enabled: false, maxRangeDays: 31 } },
2573
2573
  });
2574
2574
  });
2575
2575
 
@@ -460,3 +460,10 @@ function walkMdFiles(
460
460
  }
461
461
  }
462
462
  }
463
+
464
+ export {
465
+ decideMergeOnWrite,
466
+ type MergeCandidate,
467
+ type MergeDecision,
468
+ type MergeDecisionOptions,
469
+ } from "./merge-decision.js";
@@ -0,0 +1,157 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+
4
+ import {
5
+ decideMergeOnWrite,
6
+ type MergeCandidate,
7
+ type MergeDecisionOptions,
8
+ } from "./merge-decision.js";
9
+
10
+ const OPTS: MergeDecisionOptions = { updateThreshold: 0.8, duplicateThreshold: 0.92 };
11
+
12
+ function candidate(overrides: Partial<MergeCandidate> = {}): MergeCandidate {
13
+ return {
14
+ id: "fact-1",
15
+ similarity: 0.85,
16
+ updatedAt: "2026-01-02T00:00:00.000Z",
17
+ ...overrides,
18
+ };
19
+ }
20
+
21
+ test("no candidates creates", () => {
22
+ assert.deepEqual(decideMergeOnWrite([], OPTS), { action: "create" });
23
+ });
24
+
25
+ test("best similarity at or above duplicateThreshold skips as duplicate", () => {
26
+ assert.deepEqual(
27
+ decideMergeOnWrite(
28
+ [candidate({ id: "low", similarity: 0.5 }), candidate({ id: "dup", similarity: 0.92 })],
29
+ OPTS,
30
+ ),
31
+ { action: "skip", reason: "duplicate" },
32
+ );
33
+ });
34
+
35
+ test("best similarity between thresholds updates the best candidate", () => {
36
+ assert.deepEqual(
37
+ decideMergeOnWrite(
38
+ [candidate({ id: "best", similarity: 0.9 }), candidate({ id: "worst", similarity: 0.81 })],
39
+ OPTS,
40
+ ),
41
+ { action: "update", targetId: "best" },
42
+ );
43
+ });
44
+
45
+ test("best similarity below updateThreshold creates", () => {
46
+ assert.deepEqual(
47
+ decideMergeOnWrite([candidate({ similarity: 0.79 })], OPTS),
48
+ { action: "create" },
49
+ );
50
+ });
51
+
52
+ test("invalid thresholds throw RangeError", () => {
53
+ const bad: MergeDecisionOptions[] = [
54
+ { updateThreshold: Number.NaN, duplicateThreshold: 0.9 },
55
+ { updateThreshold: 0.8, duplicateThreshold: Number.POSITIVE_INFINITY },
56
+ { updateThreshold: -0.1, duplicateThreshold: 0.9 },
57
+ { updateThreshold: 0.8, duplicateThreshold: 1.1 },
58
+ { updateThreshold: 0.92, duplicateThreshold: 0.8 }, // duplicate < update
59
+ ];
60
+ for (const options of bad) {
61
+ assert.throws(() => decideMergeOnWrite([], options), RangeError);
62
+ }
63
+ });
64
+
65
+ test("updateThreshold 0 is honored, never coerced up", () => {
66
+ const zero = { updateThreshold: 0, duplicateThreshold: 0.92 };
67
+ // similarity 0 is >= 0 -> update, not create and not default-band behavior
68
+ assert.deepEqual(
69
+ decideMergeOnWrite([candidate({ similarity: 0 })], zero),
70
+ { action: "update", targetId: "fact-1" },
71
+ );
72
+ // no candidates still creates
73
+ assert.deepEqual(decideMergeOnWrite([], zero), { action: "create" });
74
+ });
75
+
76
+ test("malformed candidates are ignored, never thrown on", () => {
77
+ assert.deepEqual(
78
+ decideMergeOnWrite(
79
+ [
80
+ { id: "", similarity: 0.99, updatedAt: "2026-01-01T00:00:00.000Z" },
81
+ { id: " ", similarity: 0.99, updatedAt: "2026-01-01T00:00:00.000Z" },
82
+ { id: "nan", similarity: Number.NaN, updatedAt: "2026-01-01T00:00:00.000Z" },
83
+ { id: "inf", similarity: Number.POSITIVE_INFINITY, updatedAt: "2026-01-01T00:00:00.000Z" },
84
+ { id: "high", similarity: 1.5, updatedAt: "2026-01-01T00:00:00.000Z" },
85
+ { id: "neg", similarity: -0.2, updatedAt: "2026-01-01T00:00:00.000Z" },
86
+ { id: "good", similarity: 0.85, updatedAt: "2026-01-02T00:00:00.000Z" },
87
+ ],
88
+ OPTS,
89
+ ),
90
+ { action: "update", targetId: "good" },
91
+ );
92
+ // all-malformed behaves like no candidates
93
+ assert.deepEqual(
94
+ decideMergeOnWrite([{ id: "nan", similarity: Number.NaN, updatedAt: "x" }], OPTS),
95
+ { action: "create" },
96
+ );
97
+ });
98
+
99
+ test("identical similarity and updatedAt tie-breaks on id ascending, deterministically", () => {
100
+ const candidates = [
101
+ candidate({ id: "b", similarity: 0.9, updatedAt: "2026-03-01T00:00:00.000Z" }),
102
+ candidate({ id: "a", similarity: 0.9, updatedAt: "2026-03-01T00:00:00.000Z" }),
103
+ candidate({ id: "c", similarity: 0.9, updatedAt: "2026-03-01T00:00:00.000Z" }),
104
+ ];
105
+ const first = decideMergeOnWrite(candidates, OPTS);
106
+ const second = decideMergeOnWrite([...candidates].reverse(), OPTS);
107
+ assert.deepEqual(first, second);
108
+ assert.deepEqual(first, { action: "update", targetId: "a" });
109
+ });
110
+
111
+ test("unparseable updatedAt sorts last", () => {
112
+ const candidates = [
113
+ candidate({ id: "bad-date", similarity: 0.9, updatedAt: "not-a-timestamp" }),
114
+ candidate({ id: "good-date", similarity: 0.9, updatedAt: "2026-03-01T00:00:00.000Z" }),
115
+ ];
116
+ assert.deepEqual(decideMergeOnWrite(candidates, OPTS), { action: "update", targetId: "good-date" });
117
+ // newer timestamp wins when both parse
118
+ assert.deepEqual(
119
+ decideMergeOnWrite(
120
+ [
121
+ candidate({ id: "older", updatedAt: "2026-01-01T00:00:00.000Z" }),
122
+ candidate({ id: "newer", updatedAt: "2026-06-01T00:00:00.000Z" }),
123
+ ],
124
+ OPTS,
125
+ ),
126
+ { action: "update", targetId: "newer" },
127
+ );
128
+ });
129
+
130
+ // Two unparseable timestamps must not make the comparator asymmetric: testing
131
+ // each side against NaN independently returned 1 for both orderings, so the
132
+ // winner depended on array order.
133
+ test("two unparseable updatedAt values break the tie by id, whatever the order", () => {
134
+ const options = { updateThreshold: 0.5, duplicateThreshold: 0.95 };
135
+ const alpha = { id: "alpha", similarity: 0.7, updatedAt: "not-a-date" };
136
+ const beta = { id: "beta", similarity: 0.7, updatedAt: "also-not-a-date" };
137
+
138
+ for (const candidates of [[alpha, beta], [beta, alpha]]) {
139
+ assert.deepEqual(decideMergeOnWrite(candidates, options), {
140
+ action: "update",
141
+ targetId: "alpha",
142
+ });
143
+ }
144
+ });
145
+
146
+ test("a parseable updatedAt still outranks an unparseable one in both orders", () => {
147
+ const options = { updateThreshold: 0.5, duplicateThreshold: 0.95 };
148
+ const dated = { id: "zeta", similarity: 0.7, updatedAt: "2026-08-19T00:00:00.000Z" };
149
+ const undated = { id: "alpha", similarity: 0.7, updatedAt: "nope" };
150
+
151
+ for (const candidates of [[dated, undated], [undated, dated]]) {
152
+ assert.deepEqual(decideMergeOnWrite(candidates, options), {
153
+ action: "update",
154
+ targetId: "zeta",
155
+ });
156
+ }
157
+ });
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Pure create/update/skip decision for merge-on-write (issue #2330 slice).
3
+ *
4
+ * No I/O, no LLM. Invalid thresholds throw RangeError; bad candidates are
5
+ * ignored, never thrown on. `below_threshold` is reserved for a later slice.
6
+ */
7
+
8
+ export type MergeDecision =
9
+ | { action: "create" }
10
+ | { action: "update"; targetId: string }
11
+ | { action: "skip"; reason: "duplicate" | "below_threshold" };
12
+
13
+ export interface MergeCandidate {
14
+ id: string;
15
+ similarity: number; // 0..1
16
+ updatedAt: string; // ISO
17
+ }
18
+
19
+ export interface MergeDecisionOptions {
20
+ updateThreshold: number; // >= this similarity -> update
21
+ duplicateThreshold: number; // >= this similarity -> skip as duplicate
22
+ }
23
+
24
+ function assertThreshold(value: number, name: string): void {
25
+ if (!Number.isFinite(value) || value < 0 || value > 1) {
26
+ throw new RangeError(`invalid ${name}: ${value}`);
27
+ }
28
+ }
29
+
30
+ /** Total order: similarity desc, then updatedAt desc, then id asc. NaN times sort last. */
31
+ function compareCandidates(a: MergeCandidate, b: MergeCandidate): number {
32
+ if (a.similarity !== b.similarity) return b.similarity - a.similarity;
33
+ // Date.parse never throws; unparseable timestamps yield NaN and sort last.
34
+ // NaN !== NaN, so the two sides must be classified as a pair: testing each
35
+ // independently returned 1 for BOTH orderings when both were unparseable,
36
+ // which breaks antisymmetry and made the winner depend on array order.
37
+ const aTime = Date.parse(a.updatedAt);
38
+ const bTime = Date.parse(b.updatedAt);
39
+ const aUnparseable = Number.isNaN(aTime);
40
+ const bUnparseable = Number.isNaN(bTime);
41
+ if (aUnparseable !== bUnparseable) return aUnparseable ? 1 : -1;
42
+ if (!aUnparseable && aTime !== bTime) return bTime - aTime;
43
+ return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
44
+ }
45
+
46
+ export function decideMergeOnWrite(
47
+ candidates: readonly MergeCandidate[],
48
+ options: MergeDecisionOptions,
49
+ ): MergeDecision {
50
+ assertThreshold(options.updateThreshold, "updateThreshold");
51
+ assertThreshold(options.duplicateThreshold, "duplicateThreshold");
52
+ if (options.duplicateThreshold < options.updateThreshold) {
53
+ throw new RangeError(
54
+ `duplicateThreshold ${options.duplicateThreshold} < updateThreshold ${options.updateThreshold}`,
55
+ );
56
+ }
57
+
58
+ const valid = candidates.filter(
59
+ (c) =>
60
+ typeof c.id === "string" &&
61
+ c.id.trim() !== "" &&
62
+ typeof c.similarity === "number" &&
63
+ Number.isFinite(c.similarity) &&
64
+ c.similarity >= 0 &&
65
+ c.similarity <= 1,
66
+ );
67
+ if (valid.length === 0) return { action: "create" };
68
+
69
+ const best = valid.reduce((acc, c) => (compareCandidates(c, acc) < 0 ? c : acc));
70
+
71
+ if (best.similarity >= options.duplicateThreshold) {
72
+ return { action: "skip", reason: "duplicate" };
73
+ }
74
+ if (best.similarity >= options.updateThreshold) {
75
+ return { action: "update", targetId: best.id };
76
+ }
77
+ return { action: "create" };
78
+ }
package/src/lcm/engine.ts CHANGED
@@ -12,6 +12,7 @@ import { LcmWorkQueue, type LcmObserveMessage } from "./queue.js";
12
12
  import type { PluginConfig } from "../types.js";
13
13
  import { estimateTokenCount } from "../token-estimate.js";
14
14
  import { log } from "../logger.js";
15
+ import { nativeBindingRecoveryHint } from "../native-binding-hint.js";
15
16
  export interface LcmEngineConfig {
16
17
  enabled: boolean;
17
18
  leafBatchSize: number;
@@ -225,7 +226,9 @@ export class LcmEngine {
225
226
  })
226
227
  .catch((err) => {
227
228
  if (this.closed) return;
228
- log.error(`LCM observe enqueue initialization error: ${err}`);
229
+ log.error(
230
+ `LCM observe enqueue initialization error: ${err}${nativeBindingRecoveryHint(err)}`,
231
+ );
229
232
  })
230
233
  .finally(() => {
231
234
  this.releasePendingObserveInit(normalizedSessionId);
@@ -0,0 +1,38 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+
4
+ import { isNativeBindingError, nativeBindingRecoveryHint } from "./native-binding-hint.js";
5
+
6
+ test("recognizes the bindings-resolution failure operators actually see", () => {
7
+ const error = new Error(
8
+ "Could not locate the bindings file. Tried:\n → .../better-sqlite3/build/Release/better_sqlite3.node",
9
+ );
10
+ assert.equal(isNativeBindingError(error), true);
11
+ const hint = nativeBindingRecoveryHint(error);
12
+ assert.match(hint, /npm rebuild better-sqlite3 --build-from-source/);
13
+ assert.match(hint, new RegExp(`ABI ${process.versions.modules}\\b`));
14
+ assert.match(hint, new RegExp(`Node ${process.versions.node.split(".")[0]}\\b`));
15
+ });
16
+
17
+ test("recognizes an ABI mismatch reported as NODE_MODULE_VERSION", () => {
18
+ const error = new Error(
19
+ "The module was compiled against a different Node.js version using NODE_MODULE_VERSION 127. " +
20
+ "This version of Node.js requires NODE_MODULE_VERSION 141.",
21
+ );
22
+ assert.equal(isNativeBindingError(error), true);
23
+ assert.match(nativeBindingRecoveryHint(error), /--build-from-source/);
24
+ });
25
+
26
+ test("an unrelated error yields no hint so its message reads unchanged", () => {
27
+ const error = new Error("SQLITE_BUSY: database is locked");
28
+ assert.equal(isNativeBindingError(error), false);
29
+ assert.equal(nativeBindingRecoveryHint(error), "");
30
+ });
31
+
32
+ test("non-Error inputs are handled without throwing", () => {
33
+ assert.equal(isNativeBindingError(undefined), false);
34
+ assert.equal(isNativeBindingError(null), false);
35
+ assert.equal(nativeBindingRecoveryHint({}), "");
36
+ assert.equal(isNativeBindingError("could not locate the bindings file"), true);
37
+ assert.match(nativeBindingRecoveryHint("invalid ELF header"), /--build-from-source/);
38
+ });
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Actionable recovery hint for a missing or ABI-mismatched better-sqlite3
3
+ * native binding (issue #2719).
4
+ *
5
+ * `better-sqlite3` publishes prebuilds for LTS Node only, so a newer runtime
6
+ * installs the package with no loadable binding and every SQLite-backed path
7
+ * fails with a bindings-resolution error. The raw error names neither the
8
+ * running ABI nor the command that fixes it, so operators saw only
9
+ * "Could not locate the bindings file" at first use.
10
+ *
11
+ * The repair itself lives in the `@remnic/core` postinstall script — an
12
+ * OpenClaw plugin package may not ship a child-process-spawning file, so the
13
+ * host-facing packages surface this hint instead of re-implementing a rebuild.
14
+ */
15
+
16
+ /** Substrings that identify a native-binding load failure, lowercased. */
17
+ const BINDING_ERROR_MARKERS = [
18
+ "could not locate the bindings file",
19
+ "was compiled against a different node.js version",
20
+ "node_module_version",
21
+ "invalid elf header",
22
+ "better_sqlite3.node",
23
+ ];
24
+
25
+ function messageOf(error: unknown): string {
26
+ if (error instanceof Error) return error.message;
27
+ if (typeof error === "string") return error;
28
+ return "";
29
+ }
30
+
31
+ /** True when the error is a better-sqlite3 native-binding load failure. */
32
+ export function isNativeBindingError(error: unknown): boolean {
33
+ const message = messageOf(error).toLowerCase();
34
+ if (message.length === 0) return false;
35
+ return BINDING_ERROR_MARKERS.some((marker) => message.includes(marker));
36
+ }
37
+
38
+ /**
39
+ * Suffix naming the running Node ABI and the exact rebuild command, or an
40
+ * empty string when the error is unrelated. Callers append it to their own
41
+ * message so an unrelated failure reads exactly as before.
42
+ */
43
+ export function nativeBindingRecoveryHint(error: unknown): string {
44
+ if (!isNativeBindingError(error)) return "";
45
+ const major = process.versions.node.split(".")[0] ?? process.versions.node;
46
+ return (
47
+ ` — better-sqlite3 has no loadable native binding for Node ${major}` +
48
+ ` (ABI ${process.versions.modules}); rebuild it with` +
49
+ " `npm rebuild better-sqlite3 --build-from-source`"
50
+ );
51
+ }