@remnic/core 9.66.8 → 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 (451) hide show
  1. package/dist/access-admin-ops-surface.d.ts +11 -11
  2. package/dist/access-admin-ops-surface.js +20 -20
  3. package/dist/access-authorization-probe.d.ts +11 -11
  4. package/dist/access-authorization-probe.js +21 -21
  5. package/dist/access-boundary.d.ts +11 -11
  6. package/dist/access-boundary.js +20 -20
  7. package/dist/access-cli.js +68 -67
  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 +20 -20
  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 +22 -22
  18. package/dist/access-http.d.ts +12 -12
  19. package/dist/access-http.js +34 -34
  20. package/dist/access-identity-continuity-surface.d.ts +9 -9
  21. package/dist/access-identity-continuity-surface.js +20 -20
  22. package/dist/access-lcm-surface.d.ts +11 -11
  23. package/dist/access-lcm-surface.js +20 -20
  24. package/dist/access-mcp-output-schemas.js +1 -1
  25. package/dist/access-mcp.d.ts +11 -11
  26. package/dist/access-mcp.js +28 -28
  27. package/dist/access-memory-search-fanout.d.ts +2 -2
  28. package/dist/{access-namespace-preflight-50VIkPhB.d.ts → access-namespace-preflight-S8fhQcCo.d.ts} +1 -1
  29. package/dist/access-namespace-preflight.d.ts +3 -3
  30. package/dist/access-namespace-preflight.js +20 -20
  31. package/dist/access-observe-write-surface.d.ts +11 -11
  32. package/dist/access-observe-write-surface.js +20 -20
  33. package/dist/access-offline-manifest.d.ts +9 -9
  34. package/dist/access-operations-batch.js +21 -21
  35. package/dist/access-operations.d.ts +16 -16
  36. package/dist/access-operations.js +26 -26
  37. package/dist/access-recall-concurrency.d.ts +11 -11
  38. package/dist/access-recall-concurrency.js +20 -20
  39. package/dist/access-recall-response.d.ts +11 -11
  40. package/dist/access-recall-response.js +20 -20
  41. package/dist/access-recall-surface.d.ts +11 -11
  42. package/dist/access-recall-surface.js +20 -20
  43. package/dist/access-schema.d.ts +89 -89
  44. package/dist/{access-service-C2tV2-uL.d.ts → access-service-DcfM0Vf0.d.ts} +71 -71
  45. package/dist/access-service-helpers.d.ts +11 -11
  46. package/dist/access-service.d.ts +11 -11
  47. package/dist/access-service.js +20 -20
  48. package/dist/access-surface-catalog.d.ts +11 -11
  49. package/dist/access-surface-catalog.js +22 -22
  50. package/dist/access-wearables-meetings-surface.d.ts +3 -3
  51. package/dist/action-confidence.d.ts +1 -1
  52. package/dist/active-memory-bridge.d.ts +1 -1
  53. package/dist/active-recall.d.ts +1 -1
  54. package/dist/active-recall.js +2 -2
  55. package/dist/ambient-provenance.d.ts +1 -1
  56. package/dist/artifact-search.d.ts +1 -1
  57. package/dist/behavior-learner.d.ts +1 -1
  58. package/dist/behavior-signals.d.ts +1 -1
  59. package/dist/bootstrap.d.ts +9 -9
  60. package/dist/briefing-window.d.ts +2 -2
  61. package/dist/briefing.d.ts +2 -2
  62. package/dist/briefing.js +9 -9
  63. package/dist/buffer-surprise-report.d.ts +1 -1
  64. package/dist/buffer-turn-helpers.d.ts +1 -1
  65. package/dist/buffer.d.ts +2 -2
  66. package/dist/buffer.js +4 -4
  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-C2jA-gLm.d.ts → catalog-BmBXTtOs.d.ts} +1 -1
  71. package/dist/causal-behavior.d.ts +1 -1
  72. package/dist/causal-consolidation.d.ts +1 -1
  73. package/dist/causal-consolidation.js +10 -10
  74. package/dist/causal-trajectory-graph.d.ts +1 -1
  75. package/dist/{chunk-LWI43S46.js → chunk-23F7HGBV.js} +1 -1
  76. package/dist/{chunk-BDGWA5GK.js → chunk-3HHLOKKU.js} +2 -2
  77. package/dist/{chunk-FNK4KIYR.js → chunk-47BX23NA.js} +2 -2
  78. package/dist/{chunk-GO657WPH.js → chunk-52I6AHO6.js} +2 -2
  79. package/dist/{chunk-KKGWB2LG.js → chunk-5CSKIWEB.js} +3 -3
  80. package/dist/{chunk-EKUABFXQ.js → chunk-5GZ6UWY5.js} +6 -6
  81. package/dist/{chunk-MWLBRFLY.js → chunk-5KVMT25I.js} +2 -2
  82. package/dist/{chunk-6BYJQ3L2.js → chunk-5NZIRM4Q.js} +5 -5
  83. package/dist/{chunk-UMSTKKMV.js → chunk-7JPKRZD5.js} +2 -2
  84. package/dist/{chunk-UMZUKOJU.js → chunk-A7GQBJP5.js} +7 -2
  85. package/dist/chunk-A7GQBJP5.js.map +1 -0
  86. package/dist/{chunk-VYIPVLRX.js → chunk-AAJK3PZ6.js} +2 -2
  87. package/dist/{chunk-OERZXNSK.js → chunk-B3TZLAO4.js} +2 -2
  88. package/dist/{chunk-C24UZSFW.js → chunk-CEH2AFXG.js} +6 -6
  89. package/dist/{chunk-S63O62DN.js → chunk-CIWOW2FH.js} +2 -2
  90. package/dist/{chunk-IE7N2YK6.js → chunk-CNZVEU4X.js} +2 -2
  91. package/dist/{chunk-5UP5R37C.js → chunk-DGKVUPBM.js} +3 -3
  92. package/dist/{chunk-2YDU4VR7.js → chunk-FNYVWAIK.js} +18 -18
  93. package/dist/{chunk-XSPVSEAN.js → chunk-FUPIAP6Q.js} +3 -3
  94. package/dist/{chunk-5IYJWCLC.js → chunk-G3TUQJFU.js} +2 -2
  95. package/dist/{chunk-K7NUAY36.js → chunk-G775FE2E.js} +8 -8
  96. package/dist/{chunk-NEWY74GS.js → chunk-GB4R6B5M.js} +2 -2
  97. package/dist/{chunk-RI4CMRTZ.js → chunk-HWWGPS2N.js} +2 -2
  98. package/dist/{chunk-I2TIUGLC.js → chunk-IBHUZEKL.js} +2 -2
  99. package/dist/{chunk-NEDBOZ7G.js → chunk-J67E4JNT.js} +2 -2
  100. package/dist/{chunk-XUKS57W7.js → chunk-JHU543UU.js} +2 -2
  101. package/dist/{chunk-XDUQR5R7.js → chunk-JVGBDNXA.js} +2 -2
  102. package/dist/{chunk-IGOINKTD.js → chunk-K4E3Y3ZX.js} +2 -2
  103. package/dist/chunk-K4E3Y3ZX.js.map +1 -0
  104. package/dist/{chunk-GUG4LW4I.js → chunk-KIJCXLW7.js} +2 -2
  105. package/dist/{chunk-AVYNKPFS.js → chunk-KVXMN33W.js} +4 -4
  106. package/dist/chunk-LD72P4YS.js +29 -0
  107. package/dist/chunk-LD72P4YS.js.map +1 -0
  108. package/dist/chunk-LTDN5WYF.js +202 -0
  109. package/dist/chunk-LTDN5WYF.js.map +1 -0
  110. package/dist/{chunk-FI6FT6YX.js → chunk-MBDUNO7J.js} +2 -2
  111. package/dist/{chunk-MBXTGOFR.js → chunk-MFI4QPW5.js} +2 -2
  112. package/dist/{chunk-UJICQ77Y.js → chunk-MK7EJLB4.js} +2 -2
  113. package/dist/{chunk-UOQZOV2J.js → chunk-NABJLNLU.js} +64 -32
  114. package/dist/chunk-NABJLNLU.js.map +1 -0
  115. package/dist/{chunk-X32ALJQB.js → chunk-NSP3HFJZ.js} +2 -2
  116. package/dist/{chunk-6ULLVM2V.js → chunk-OJSCH7QT.js} +8 -8
  117. package/dist/{chunk-MFIFCXS3.js → chunk-OT7WQ2I3.js} +2 -2
  118. package/dist/{chunk-XVCYV7WQ.js → chunk-Q3UMNZRK.js} +3 -3
  119. package/dist/{chunk-O2RJZR6J.js → chunk-Q5YKVBIV.js} +2 -2
  120. package/dist/{chunk-KMPEBHH5.js → chunk-QU2V4IO3.js} +2 -2
  121. package/dist/{chunk-SVATDJNY.js → chunk-RF3LMSQW.js} +2 -2
  122. package/dist/{chunk-OMA2B7GY.js → chunk-RLEJULGN.js} +2 -2
  123. package/dist/{chunk-KH2LZMD5.js → chunk-SJ5L4ZZX.js} +2 -2
  124. package/dist/{chunk-2MYBDWUY.js → chunk-SOQLXIQX.js} +2 -2
  125. package/dist/{chunk-2V4YPDIX.js → chunk-SRILZVR4.js} +2 -2
  126. package/dist/{chunk-5S6TQ36T.js → chunk-TEJKBBWS.js} +10 -10
  127. package/dist/{chunk-5S6TQ36T.js.map → chunk-TEJKBBWS.js.map} +1 -1
  128. package/dist/{chunk-AZLSFKGU.js → chunk-TKSBOV7N.js} +5 -5
  129. package/dist/{chunk-YSYHSZWD.js → chunk-TWMGWLHD.js} +2 -2
  130. package/dist/{chunk-QK375NXZ.js → chunk-UAWSKMWQ.js} +2 -2
  131. package/dist/{chunk-FY62KW6Q.js → chunk-VCYY7XEL.js} +2 -2
  132. package/dist/{chunk-46XR5FNZ.js → chunk-VSWRJQQW.js} +31 -5
  133. package/dist/chunk-VSWRJQQW.js.map +1 -0
  134. package/dist/{chunk-6ZRLH4VS.js → chunk-VX5YHEGJ.js} +3 -3
  135. package/dist/{chunk-RPHCLGQ7.js → chunk-XVNDP3RO.js} +2 -2
  136. package/dist/{chunk-XORZMKVF.js → chunk-ZC5L6ME2.js} +3 -3
  137. package/dist/{chunk-7X63THIR.js → chunk-ZJGHOPEO.js} +28 -28
  138. package/dist/{chunk-ULTK4NZY.js → chunk-ZVUGRXSY.js} +2 -2
  139. package/dist/{cli-CsfFMe6n.d.ts → cli-CFpMhqz5.d.ts} +5 -5
  140. package/dist/cli.d.ts +13 -13
  141. package/dist/cli.js +51 -51
  142. package/dist/coding/export-okf-codegraph.d.ts +1 -1
  143. package/dist/coding/export-okf-codegraph.js +9 -9
  144. package/dist/coding/pre-action-gate.d.ts +1 -1
  145. package/dist/compounding/engine.d.ts +2 -2
  146. package/dist/compounding/engine.js +9 -9
  147. package/dist/compounding/preference-consolidator.d.ts +1 -1
  148. package/dist/compression-optimizer.d.ts +1 -1
  149. package/dist/config.d.ts +1 -1
  150. package/dist/config.js +2 -2
  151. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  152. package/dist/connectors/codex-materialize-runner.js +9 -9
  153. package/dist/connectors/codex-materialize.d.ts +1 -1
  154. package/dist/connectors/index.d.ts +1 -1
  155. package/dist/connectors/index.js +9 -9
  156. package/dist/consolidation-provenance-check.d.ts +2 -2
  157. package/dist/consolidation-undo.d.ts +2 -2
  158. package/dist/contradiction/index.d.ts +3 -3
  159. package/dist/converge-config.d.ts +1 -1
  160. package/dist/convergence-refresh.d.ts +2 -2
  161. package/dist/convergence-refresh.js +11 -11
  162. package/dist/conversation-index/backend.d.ts +1 -1
  163. package/dist/conversation-index/chunker.d.ts +1 -1
  164. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  165. package/dist/conversation-index/indexer.d.ts +1 -1
  166. package/dist/conversation-index/search.d.ts +1 -1
  167. package/dist/corpus-watermark.d.ts +1 -1
  168. package/dist/corpus-watermark.js +11 -11
  169. package/dist/cross-lingual-recall.d.ts +1 -1
  170. package/dist/day-summary.d.ts +1 -1
  171. package/dist/delinearize.d.ts +1 -1
  172. package/dist/dependency-propagation-config.d.ts +1 -1
  173. package/dist/{dependency-propagation-delivery-D4WMbOwA.d.ts → dependency-propagation-delivery-BC3bCEet.d.ts} +1 -1
  174. package/dist/direct-answer-wiring.d.ts +1 -1
  175. package/dist/direct-answer.d.ts +1 -1
  176. package/dist/embedding-fallback.d.ts +1 -1
  177. package/dist/enrichment/index.d.ts +1 -1
  178. package/dist/entity-origin-fields.d.ts +1 -1
  179. package/dist/entity-retrieval.d.ts +2 -2
  180. package/dist/entity-retrieval.js +9 -9
  181. package/dist/entity-schema.d.ts +1 -1
  182. package/dist/episodic-context.d.ts +1 -1
  183. package/dist/eval-trajectory-contracts.d.ts +1 -1
  184. package/dist/eval-trajectory-store.d.ts +1 -1
  185. package/dist/eval-trajectory.d.ts +1 -1
  186. package/dist/explicit-capture.d.ts +9 -9
  187. package/dist/external-wiki-access.d.ts +11 -11
  188. package/dist/external-wiki-access.js +21 -21
  189. package/dist/external-wiki-collection-registration.d.ts +1 -1
  190. package/dist/external-wiki-collection.d.ts +1 -1
  191. package/dist/external-wiki-mcp-tools.d.ts +11 -11
  192. package/dist/extraction-error-classification.d.ts +1 -1
  193. package/dist/extraction-faithfulness.d.ts +1 -1
  194. package/dist/extraction-judge-telemetry.d.ts +1 -1
  195. package/dist/extraction-judge-training.d.ts +1 -1
  196. package/dist/extraction-judge.d.ts +1 -1
  197. package/dist/extraction-liveness.d.ts +1 -1
  198. package/dist/extraction-normalization.d.ts +1 -1
  199. package/dist/extraction-prompt.d.ts +1 -1
  200. package/dist/extraction-source-grounding-rules.d.ts +1 -1
  201. package/dist/extraction-source-grounding.d.ts +1 -1
  202. package/dist/extraction.d.ts +1 -1
  203. package/dist/extraction.js +12 -12
  204. package/dist/fallback-llm.d.ts +1 -1
  205. package/dist/{first-start-migration-KHIMCBIC.js → first-start-migration-UG32BSG2.js} +4 -4
  206. package/dist/graph-dashboard-diff.d.ts +1 -1
  207. package/dist/graph-dashboard-key.d.ts +1 -1
  208. package/dist/graph-dashboard-parser.d.ts +1 -1
  209. package/dist/graph-edge-reinforcement.d.ts +1 -1
  210. package/dist/graph-path-reconstruction.d.ts +1 -1
  211. package/dist/graph-path-scoring.d.ts +1 -1
  212. package/dist/graph-snapshot.d.ts +1 -1
  213. package/dist/graph.d.ts +1 -1
  214. package/dist/harmonic-retrieval.js +1 -1
  215. package/dist/importance.d.ts +1 -1
  216. package/dist/importers/index.d.ts +1 -1
  217. package/dist/in-flight-reads.d.ts +1 -1
  218. package/dist/{index-DuJnzwHv.d.ts → index-D4hS9uxK.d.ts} +2 -2
  219. package/dist/index.d.ts +719 -700
  220. package/dist/index.js +79 -76
  221. package/dist/intent.d.ts +1 -1
  222. package/dist/lcm/engine.d.ts +1 -1
  223. package/dist/lcm/engine.js +2 -1
  224. package/dist/lcm/index.d.ts +1 -1
  225. package/dist/lcm/index.js +5 -4
  226. package/dist/lcm/tools.d.ts +1 -1
  227. package/dist/lifecycle.d.ts +1 -1
  228. package/dist/live-connectors-runner.d.ts +1 -1
  229. package/dist/local-llm.d.ts +1 -1
  230. package/dist/local-model-endpoint.d.ts +1 -1
  231. package/dist/location/index.d.ts +3 -3
  232. package/dist/location/index.js +11 -11
  233. package/dist/maintenance/memory-governance.d.ts +1 -1
  234. package/dist/maintenance/memory-governance.js +9 -9
  235. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  236. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +9 -9
  237. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  238. package/dist/maintenance/rebuild-memory-projection.js +10 -10
  239. package/dist/{maintenance-BBeaeYRR.d.ts → maintenance-BRcc3Hx8.d.ts} +3 -3
  240. package/dist/mcp-memory-inspector-app.d.ts +11 -11
  241. package/dist/memory-action-policy.d.ts +1 -1
  242. package/dist/memory-cache.d.ts +1 -1
  243. package/dist/memory-controller.d.ts +1 -1
  244. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  245. package/dist/memory-projection-store.d.ts +1 -1
  246. package/dist/memory-provenance.d.ts +1 -1
  247. package/dist/memory-snapshot.d.ts +1 -1
  248. package/dist/memory-subject-cli.d.ts +11 -11
  249. package/dist/memory-subject.d.ts +11 -11
  250. package/dist/memory-worth-outcomes.d.ts +2 -2
  251. package/dist/models-json.d.ts +1 -1
  252. package/dist/namespaces/migrate.d.ts +3 -3
  253. package/dist/namespaces/migrate.js +10 -10
  254. package/dist/namespaces/principal.d.ts +1 -1
  255. package/dist/namespaces/search.d.ts +1 -1
  256. package/dist/namespaces/search.js +6 -6
  257. package/dist/namespaces/storage.d.ts +3 -3
  258. package/dist/namespaces/storage.js +9 -9
  259. package/dist/native-binding-hint.d.ts +24 -0
  260. package/dist/native-binding-hint.js +10 -0
  261. package/dist/native-binding-hint.js.map +1 -0
  262. package/dist/native-knowledge.d.ts +1 -1
  263. package/dist/offline-sync-impression-drain.d.ts +1 -1
  264. package/dist/operator-doctor-corpus.d.ts +1 -1
  265. package/dist/operator-doctor-corpus.js +12 -12
  266. package/dist/operator-doctor-replica.d.ts +1 -1
  267. package/dist/operator-toolkit.d.ts +3 -3
  268. package/dist/operator-toolkit.js +19 -19
  269. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  270. package/dist/orchestration/maintenance.d.ts +4 -4
  271. package/dist/orchestration/maintenance.js +18 -18
  272. package/dist/{orchestrator-CaqnwNwM.d.ts → orchestrator-Btq9lzAN.d.ts} +8 -8
  273. package/dist/orchestrator.d.ts +9 -9
  274. package/dist/orchestrator.js +68 -67
  275. package/dist/patterns-cli.d.ts +1 -1
  276. package/dist/{pipeline-CrxVjlJr.d.ts → pipeline-CZoNdFb5.d.ts} +1 -1
  277. package/dist/policy-runtime.d.ts +1 -1
  278. package/dist/proactive-contention.d.ts +1 -1
  279. package/dist/provenance.d.ts +1 -1
  280. package/dist/{public-http-Cwvl4QZr.d.ts → public-http-C9-CHc40.d.ts} +1 -1
  281. package/dist/{qmd-BZgbJm0g.d.ts → qmd-VIjSCKIE.d.ts} +1 -1
  282. package/dist/qmd-preflight.d.ts +2 -2
  283. package/dist/qmd-recall-cache.d.ts +1 -1
  284. package/dist/qmd.d.ts +2 -2
  285. package/dist/qmd.js +4 -4
  286. package/dist/recall-concurrency-config.d.ts +1 -1
  287. package/dist/recall-disclosure-escalation.d.ts +1 -1
  288. package/dist/recall-explain-renderer.d.ts +1 -1
  289. package/dist/recall-memory-map.d.ts +1 -1
  290. package/dist/recall-navigate-access.d.ts +1 -1
  291. package/dist/recall-navigate.d.ts +1 -1
  292. package/dist/recall-planner-llm.d.ts +1 -1
  293. package/dist/recall-state.d.ts +1 -1
  294. package/dist/recall-tag-filter.d.ts +1 -1
  295. package/dist/recall-timings.d.ts +1 -1
  296. package/dist/recall-xray-cli.d.ts +1 -1
  297. package/dist/recall-xray-renderer.d.ts +1 -1
  298. package/dist/recall-xray.d.ts +1 -1
  299. package/dist/reconcile/cursor.d.ts +1 -1
  300. package/dist/reconcile/manifest.d.ts +1 -1
  301. package/dist/reconcile/plan.d.ts +1 -1
  302. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  303. package/dist/replay/normalizers/claude.d.ts +1 -1
  304. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  305. package/dist/replay/normalizers/shared.d.ts +1 -1
  306. package/dist/replay/runner.d.ts +1 -1
  307. package/dist/replay/types.d.ts +1 -1
  308. package/dist/replica-divergence.d.ts +1 -1
  309. package/dist/replica-peers-config.d.ts +1 -1
  310. package/dist/resolve-auth-token.d.ts +1 -1
  311. package/dist/resume-bundles.js +3 -3
  312. package/dist/retrieval-agents.d.ts +2 -2
  313. package/dist/retrieval-tiers.d.ts +1 -1
  314. package/dist/routing/engine.d.ts +1 -1
  315. package/dist/routing/store.d.ts +1 -1
  316. package/dist/salvage-envelope.d.ts +1 -1
  317. package/dist/schemas.d.ts +176 -176
  318. package/dist/{scope-profiles-DFaojvoP.d.ts → scope-profiles-DqbxQXIS.d.ts} +1 -1
  319. package/dist/search/embed-helper.d.ts +1 -1
  320. package/dist/search/factory.d.ts +1 -1
  321. package/dist/search/factory.js +5 -5
  322. package/dist/search/index.d.ts +1 -1
  323. package/dist/search/index.js +9 -9
  324. package/dist/search/lancedb-backend.d.ts +1 -1
  325. package/dist/search/meilisearch-backend.d.ts +1 -1
  326. package/dist/search/noop-backend.d.ts +1 -1
  327. package/dist/search/orama-backend.d.ts +1 -1
  328. package/dist/search/port.d.ts +1 -1
  329. package/dist/search/remote-backend.d.ts +1 -1
  330. package/dist/{semantic-consolidation-BiX68wZA.d.ts → semantic-consolidation-DW3rEUoW.d.ts} +1 -1
  331. package/dist/semantic-consolidation.d.ts +2 -2
  332. package/dist/semantic-consolidation.js +10 -10
  333. package/dist/semantic-rule-promotion.js +9 -9
  334. package/dist/semantic-rule-verifier.d.ts +1 -1
  335. package/dist/semantic-rule-verifier.js +9 -9
  336. package/dist/{service-D5h2zZ0M.d.ts → service-B2vJU_Bx.d.ts} +2 -2
  337. package/dist/session-observer-bands.d.ts +1 -1
  338. package/dist/session-observer-state.d.ts +1 -1
  339. package/dist/shared-context/manager.d.ts +7 -7
  340. package/dist/signal.d.ts +1 -1
  341. package/dist/source-agent-qualifier.d.ts +1 -1
  342. package/dist/source-agent-qualifier.js +11 -11
  343. package/dist/standup/build.d.ts +9 -3
  344. package/dist/standup/build.js +99 -7
  345. package/dist/{storage-CtsaojWD.d.ts → storage-6fn7BPmb.d.ts} +1 -1
  346. package/dist/storage.d.ts +2 -2
  347. package/dist/storage.js +8 -8
  348. package/dist/subject-config.d.ts +1 -1
  349. package/dist/summarizer.d.ts +1 -1
  350. package/dist/summary-snapshot.d.ts +1 -1
  351. package/dist/support-passport/index.d.ts +14 -14
  352. package/dist/support-passport/index.js +23 -23
  353. package/dist/temporal-supersession.d.ts +2 -2
  354. package/dist/temporal-timeline-recall.d.ts +1 -1
  355. package/dist/temporal-validity.d.ts +1 -1
  356. package/dist/threading.d.ts +1 -1
  357. package/dist/tier-migration.d.ts +2 -2
  358. package/dist/tier-routing.d.ts +1 -1
  359. package/dist/topics.d.ts +1 -1
  360. package/dist/transcript.d.ts +1 -1
  361. package/dist/transfer/export-okf.d.ts +1 -1
  362. package/dist/transfer/export-okf.js +10 -10
  363. package/dist/transfer/types.d.ts +78 -78
  364. package/dist/trust-score-stage.d.ts +1 -1
  365. package/dist/trust-score.d.ts +1 -1
  366. package/dist/{types-CIpfYz1I.d.ts → types-eM7QIcX2.d.ts} +4 -0
  367. package/dist/types.d.ts +1 -1
  368. package/dist/utility-runtime.d.ts +1 -1
  369. package/dist/verified-recall.js +9 -9
  370. package/dist/who-knows-cli.d.ts +11 -11
  371. package/dist/who-knows-cli.js +10 -10
  372. package/dist/who-knows.d.ts +11 -11
  373. package/dist/who-knows.js +9 -9
  374. package/dist/write-envelope.d.ts +1 -1
  375. package/package.json +2 -2
  376. package/scripts/ensure-better-sqlite3.mjs +10 -0
  377. package/src/access-mcp-output-schemas.ts +1 -1
  378. package/src/activity/config.test.ts +1 -1
  379. package/src/activity/config.ts +20 -4
  380. package/src/activity/journal.test.ts +40 -0
  381. package/src/activity/timeline/index.ts +1 -0
  382. package/src/activity/timeline/recap-window.test.ts +129 -0
  383. package/src/activity/timeline/recap-window.ts +55 -0
  384. package/src/activity/types.ts +4 -0
  385. package/src/config.test.ts +1 -1
  386. package/src/dedup/index.ts +7 -0
  387. package/src/dedup/merge-decision.test.ts +157 -0
  388. package/src/dedup/merge-decision.ts +78 -0
  389. package/src/lcm/engine.ts +4 -1
  390. package/src/native-binding-hint.test.ts +38 -0
  391. package/src/native-binding-hint.ts +51 -0
  392. package/src/standup/build.test.ts +138 -12
  393. package/src/standup/build.ts +172 -23
  394. package/src/standup/http-glue.ts +1 -1
  395. package/dist/chunk-46XR5FNZ.js.map +0 -1
  396. package/dist/chunk-IGOINKTD.js.map +0 -1
  397. package/dist/chunk-UMZUKOJU.js.map +0 -1
  398. package/dist/chunk-UOQZOV2J.js.map +0 -1
  399. package/dist/chunk-VOSWUO3K.js +0 -100
  400. package/dist/chunk-VOSWUO3K.js.map +0 -1
  401. /package/dist/{chunk-LWI43S46.js.map → chunk-23F7HGBV.js.map} +0 -0
  402. /package/dist/{chunk-BDGWA5GK.js.map → chunk-3HHLOKKU.js.map} +0 -0
  403. /package/dist/{chunk-FNK4KIYR.js.map → chunk-47BX23NA.js.map} +0 -0
  404. /package/dist/{chunk-GO657WPH.js.map → chunk-52I6AHO6.js.map} +0 -0
  405. /package/dist/{chunk-KKGWB2LG.js.map → chunk-5CSKIWEB.js.map} +0 -0
  406. /package/dist/{chunk-EKUABFXQ.js.map → chunk-5GZ6UWY5.js.map} +0 -0
  407. /package/dist/{chunk-MWLBRFLY.js.map → chunk-5KVMT25I.js.map} +0 -0
  408. /package/dist/{chunk-6BYJQ3L2.js.map → chunk-5NZIRM4Q.js.map} +0 -0
  409. /package/dist/{chunk-UMSTKKMV.js.map → chunk-7JPKRZD5.js.map} +0 -0
  410. /package/dist/{chunk-VYIPVLRX.js.map → chunk-AAJK3PZ6.js.map} +0 -0
  411. /package/dist/{chunk-OERZXNSK.js.map → chunk-B3TZLAO4.js.map} +0 -0
  412. /package/dist/{chunk-C24UZSFW.js.map → chunk-CEH2AFXG.js.map} +0 -0
  413. /package/dist/{chunk-S63O62DN.js.map → chunk-CIWOW2FH.js.map} +0 -0
  414. /package/dist/{chunk-IE7N2YK6.js.map → chunk-CNZVEU4X.js.map} +0 -0
  415. /package/dist/{chunk-5UP5R37C.js.map → chunk-DGKVUPBM.js.map} +0 -0
  416. /package/dist/{chunk-2YDU4VR7.js.map → chunk-FNYVWAIK.js.map} +0 -0
  417. /package/dist/{chunk-XSPVSEAN.js.map → chunk-FUPIAP6Q.js.map} +0 -0
  418. /package/dist/{chunk-5IYJWCLC.js.map → chunk-G3TUQJFU.js.map} +0 -0
  419. /package/dist/{chunk-K7NUAY36.js.map → chunk-G775FE2E.js.map} +0 -0
  420. /package/dist/{chunk-NEWY74GS.js.map → chunk-GB4R6B5M.js.map} +0 -0
  421. /package/dist/{chunk-RI4CMRTZ.js.map → chunk-HWWGPS2N.js.map} +0 -0
  422. /package/dist/{chunk-I2TIUGLC.js.map → chunk-IBHUZEKL.js.map} +0 -0
  423. /package/dist/{chunk-NEDBOZ7G.js.map → chunk-J67E4JNT.js.map} +0 -0
  424. /package/dist/{chunk-XUKS57W7.js.map → chunk-JHU543UU.js.map} +0 -0
  425. /package/dist/{chunk-XDUQR5R7.js.map → chunk-JVGBDNXA.js.map} +0 -0
  426. /package/dist/{chunk-GUG4LW4I.js.map → chunk-KIJCXLW7.js.map} +0 -0
  427. /package/dist/{chunk-AVYNKPFS.js.map → chunk-KVXMN33W.js.map} +0 -0
  428. /package/dist/{chunk-FI6FT6YX.js.map → chunk-MBDUNO7J.js.map} +0 -0
  429. /package/dist/{chunk-MBXTGOFR.js.map → chunk-MFI4QPW5.js.map} +0 -0
  430. /package/dist/{chunk-UJICQ77Y.js.map → chunk-MK7EJLB4.js.map} +0 -0
  431. /package/dist/{chunk-X32ALJQB.js.map → chunk-NSP3HFJZ.js.map} +0 -0
  432. /package/dist/{chunk-6ULLVM2V.js.map → chunk-OJSCH7QT.js.map} +0 -0
  433. /package/dist/{chunk-MFIFCXS3.js.map → chunk-OT7WQ2I3.js.map} +0 -0
  434. /package/dist/{chunk-XVCYV7WQ.js.map → chunk-Q3UMNZRK.js.map} +0 -0
  435. /package/dist/{chunk-O2RJZR6J.js.map → chunk-Q5YKVBIV.js.map} +0 -0
  436. /package/dist/{chunk-KMPEBHH5.js.map → chunk-QU2V4IO3.js.map} +0 -0
  437. /package/dist/{chunk-SVATDJNY.js.map → chunk-RF3LMSQW.js.map} +0 -0
  438. /package/dist/{chunk-OMA2B7GY.js.map → chunk-RLEJULGN.js.map} +0 -0
  439. /package/dist/{chunk-KH2LZMD5.js.map → chunk-SJ5L4ZZX.js.map} +0 -0
  440. /package/dist/{chunk-2MYBDWUY.js.map → chunk-SOQLXIQX.js.map} +0 -0
  441. /package/dist/{chunk-2V4YPDIX.js.map → chunk-SRILZVR4.js.map} +0 -0
  442. /package/dist/{chunk-AZLSFKGU.js.map → chunk-TKSBOV7N.js.map} +0 -0
  443. /package/dist/{chunk-YSYHSZWD.js.map → chunk-TWMGWLHD.js.map} +0 -0
  444. /package/dist/{chunk-QK375NXZ.js.map → chunk-UAWSKMWQ.js.map} +0 -0
  445. /package/dist/{chunk-FY62KW6Q.js.map → chunk-VCYY7XEL.js.map} +0 -0
  446. /package/dist/{chunk-6ZRLH4VS.js.map → chunk-VX5YHEGJ.js.map} +0 -0
  447. /package/dist/{chunk-RPHCLGQ7.js.map → chunk-XVNDP3RO.js.map} +0 -0
  448. /package/dist/{chunk-XORZMKVF.js.map → chunk-ZC5L6ME2.js.map} +0 -0
  449. /package/dist/{chunk-7X63THIR.js.map → chunk-ZJGHOPEO.js.map} +0 -0
  450. /package/dist/{chunk-ULTK4NZY.js.map → chunk-ZVUGRXSY.js.map} +0 -0
  451. /package/dist/{first-start-migration-KHIMCBIC.js.map → first-start-migration-UG32BSG2.js.map} +0 -0
@@ -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
+ }
@@ -4,30 +4,156 @@ import os from "node:os";
4
4
  import path from "node:path";
5
5
  import test from "node:test";
6
6
 
7
- import { buildStandup, parseStandupDate, previousDate } from "./build.js";
7
+ import { buildStandup, parseStandupDate, previousActiveDate } from "./build.js";
8
8
 
9
- test("parseStandupDate rejects garbage and defaults to UTC today", () => {
9
+ const FRONTMATTER = (date: string): string => `---\nid: digest-${date}\ncategory: fact\nstatus: active\n---\n`;
10
+
11
+ test("parseStandupDate defaults only on absence, rejects garbage and empty", () => {
10
12
  assert.equal(parseStandupDate(undefined, new Date("2026-08-18T12:00:00Z")), "2026-08-18");
13
+ assert.equal(parseStandupDate(null, new Date("2026-08-18T12:00:00Z")), "2026-08-18");
11
14
  assert.throws(() => parseStandupDate("nope"), /YYYY-MM-DD/);
12
- assert.equal(previousDate("2026-08-18"), "2026-08-17");
15
+ // An explicitly empty date is user input, not absence (§39: reject, never
16
+ // silently default).
17
+ assert.throws(() => parseStandupDate(""), /YYYY-MM-DD/);
18
+ });
19
+
20
+ test("previousActiveDate falls back to calendar-previous when no digests exist", async () => {
21
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-standup-"));
22
+ try {
23
+ assert.equal(previousActiveDate(memoryDir, "2026-08-18"), "2026-08-17");
24
+ } finally {
25
+ await rm(memoryDir, { recursive: true, force: true });
26
+ }
27
+ });
28
+
29
+ test("previousActiveDate skips idle weekend days (Monday resolves to Friday)", async () => {
30
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-standup-"));
31
+ try {
32
+ await mkdir(path.join(memoryDir, "activity"), { recursive: true });
33
+ // 2026-08-17 is a Monday; 2026-08-14 is the prior Friday (derived from
34
+ // `date -d`, not memory). Weekend has no digest files.
35
+ await writeFile(path.join(memoryDir, "activity", "2026-08-14.md"), "x\n", "utf8");
36
+ assert.equal(previousActiveDate(memoryDir, "2026-08-17"), "2026-08-14");
37
+ } finally {
38
+ await rm(memoryDir, { recursive: true, force: true });
39
+ }
40
+ });
41
+
42
+ test("previousActiveDate picks the most recent active day, not a fixed weekday", async () => {
43
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-standup-"));
44
+ try {
45
+ await mkdir(path.join(memoryDir, "activity"), { recursive: true });
46
+ // Sunday activity counts: prior day is the latest day WITH data.
47
+ await writeFile(path.join(memoryDir, "activity", "2026-08-16.md"), "x\n", "utf8");
48
+ assert.equal(previousActiveDate(memoryDir, "2026-08-17"), "2026-08-16");
49
+ } finally {
50
+ await rm(memoryDir, { recursive: true, force: true });
51
+ }
13
52
  });
14
53
 
15
- test("buildStandup is deterministic and marks missing days", async () => {
54
+ function digestBody(spans: string[]): string {
55
+ return ["## Timeline", "", ...spans].join("\n");
56
+ }
57
+
58
+ test("buildStandup derives every section from the prior active day and stays deterministic", async () => {
16
59
  const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-standup-"));
17
60
  try {
18
61
  await mkdir(path.join(memoryDir, "activity"), { recursive: true });
62
+ // Friday 2026-08-14 has the activity; Monday 2026-08-17 is the standup day.
19
63
  await writeFile(
20
- path.join(memoryDir, "activity", "2026-08-18.md"),
21
- "---\ndate: 2026-08-18\n---\n# Today\n- shipped standup\n- blocker: waiting on review\n",
64
+ path.join(memoryDir, "activity", "2026-08-14.md"),
65
+ FRONTMATTER("2026-08-14") +
66
+ digestBody([
67
+ "- [09:00] Editor — refactor",
68
+ "- [09:30] Editor — refactor",
69
+ "- [10:15] Terminal — build",
70
+ "- [11:40] Editor — review",
71
+ "- [14:05] Browser — docs",
72
+ "- [15:20] Editor — blocker: waiting on review",
73
+ ]),
22
74
  "utf8",
23
75
  );
24
- const a = buildStandup(memoryDir, "2026-08-18");
25
- const b = buildStandup(memoryDir, "2026-08-18");
76
+ const a = buildStandup(memoryDir, "2026-08-17");
77
+ const b = buildStandup(memoryDir, "2026-08-17");
26
78
  assert.equal(a.markdown, b.markdown);
27
- assert.equal(a.yesterday, "2026-08-17");
28
- assert.match(a.markdown, /blocker: waiting on review/);
29
- assert.match(a.activityGrid, /yesterday \| \./);
30
- assert.match(a.activityGrid, /today \| x/);
79
+
80
+ assert.equal(a.yesterday, "2026-08-14");
81
+ // Highlights come from the PRIOR day (issue #1981), and frontmatter
82
+ // fields never leak into rendered sections.
83
+ assert.ok(a.highlights.length > 0);
84
+ for (const line of a.highlights) {
85
+ assert.doesNotMatch(line, /^id: |^category: |^status: |^---$/);
86
+ }
87
+ assert.match(a.markdown, /## Highlights\n- \[09:00\] Editor — refactor/);
88
+ // Blockers strip list markers (no doubled bullets) and come from P.
89
+ assert.ok(a.blockers.some((line) => line === "[15:20] Editor — blocker: waiting on review"));
90
+ assert.doesNotMatch(a.markdown, /- - /);
91
+ // Grid: exactly hours 9, 10, 11, 14, 15 non-empty; Monday empty.
92
+ assert.match(a.activityGrid, /^prior day 2026-08-14 — 24 hour buckets/);
93
+ assert.match(a.activityGrid, /^non-empty hours: 9, 10, 11, 14, 15$/m);
94
+ assert.match(a.markdown, /## Today \(2026-08-17\)\n_No activity digest._/);
95
+ // Zero commitments → explicit empty-priorities message, never invented.
96
+ assert.match(a.markdown, /## Today's priorities\n- \(no tracked commitments — add priorities manually\)/);
97
+ } finally {
98
+ await rm(memoryDir, { recursive: true, force: true });
99
+ }
100
+ });
101
+
102
+ test("buildStandup renders an empty grid row when the prior day has no digest", async () => {
103
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-standup-"));
104
+ try {
105
+ const brief = buildStandup(memoryDir, "2026-08-18");
106
+ assert.match(brief.activityGrid, /^prior day 2026-08-17: no activity digest \(empty\)$/);
107
+ } finally {
108
+ await rm(memoryDir, { recursive: true, force: true });
109
+ }
110
+ });
111
+
112
+ test("buildStandup lists open commitments as priorities and overdue ones as blocker candidates", async () => {
113
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-standup-"));
114
+ try {
115
+ await mkdir(path.join(memoryDir, "facts", "2026-08-10"), { recursive: true });
116
+ const commitment = (id: string, extra: string): string =>
117
+ `---\nid: ${id}\ncategory: commitment\nstatus: active\ncreated: 2026-08-10T00:00:00Z\nupdated: 2026-08-10T00:00:00Z\nsource: test\nconfidence: 0.8\nconfidenceTier: reported\ntags: []\n${extra}---\n${id} says: ship the thing\n`;
118
+ await writeFile(path.join(memoryDir, "facts", "2026-08-10", "open.md"), commitment("open-1", ""), "utf8");
119
+ await writeFile(
120
+ path.join(memoryDir, "facts", "2026-08-10", "due-soon.md"),
121
+ commitment("due-soon", "expiresAt: 2026-08-19T00:00:00Z\n"),
122
+ "utf8",
123
+ );
124
+ await writeFile(
125
+ path.join(memoryDir, "facts", "2026-08-10", "overdue.md"),
126
+ commitment("overdue-1", "expiresAt: 2026-08-15T00:00:00Z\n"),
127
+ "utf8",
128
+ );
129
+ await writeFile(
130
+ path.join(memoryDir, "facts", "2026-08-10", "fulfilled.md"),
131
+ commitment("done-1", "tags: [fulfilled]\n"),
132
+ "utf8",
133
+ );
134
+ await writeFile(
135
+ path.join(memoryDir, "facts", "2026-08-10", "review.md"),
136
+ commitment("pending-1", "status: pending_review\n"),
137
+ "utf8",
138
+ );
139
+ await writeFile(
140
+ path.join(memoryDir, "facts", "2026-08-10", "plain-fact.md"),
141
+ `---\nid: fact-1\ncategory: fact\nstatus: active\ncreated: 2026-08-10T00:00:00Z\nupdated: 2026-08-10T00:00:00Z\nsource: test\nconfidence: 0.8\nconfidenceTier: reported\ntags: []\n---\nnot a commitment\n`,
142
+ "utf8",
143
+ );
144
+
145
+ const brief = buildStandup(memoryDir, "2026-08-17");
146
+ // Overdue commitment is a blocker candidate, not a priority.
147
+ assert.ok(brief.blockers.some((line) => line.startsWith("commitment past due: overdue-1 says: ship the thing")));
148
+ // Fulfiled, pending-review, and non-commitment facts never appear.
149
+ const priorities = brief.priorities.join("\n");
150
+ assert.ok(priorities.includes("due-soon says: ship the thing (due 2026-08-19)"));
151
+ assert.ok(priorities.includes("open-1 says: ship the thing"));
152
+ assert.ok(!priorities.includes("done-1"));
153
+ assert.ok(!priorities.includes("pending-1"));
154
+ assert.ok(!priorities.includes("not a commitment"));
155
+ // Due-first ordering: expiresAt before bare created.
156
+ assert.ok(priorities.indexOf("due-soon") < priorities.indexOf("open-1"));
31
157
  } finally {
32
158
  await rm(memoryDir, { recursive: true, force: true });
33
159
  }
@@ -1,41 +1,73 @@
1
- import { readFileSync } from "node:fs";
1
+ import { readdirSync, readFileSync } from "node:fs";
2
2
  import path from "node:path";
3
3
 
4
+ import { EngramAccessInputError } from "../access-errors.js";
4
5
  import { activityDigestPath, isValidActivityDate } from "../activity/digest.js";
6
+ import { parseFrontmatter } from "../storage.js";
5
7
 
6
8
  export interface StandupBrief {
7
9
  date: string;
8
10
  yesterday: string;
9
11
  today: string;
10
12
  highlights: string[];
13
+ priorities: string[];
11
14
  blockers: string[];
12
15
  activityGrid: string;
13
16
  markdown: string;
14
17
  }
15
18
 
16
19
  export function parseStandupDate(raw: unknown, now = new Date()): string {
17
- if (raw === undefined || raw === null || raw === "") {
20
+ if (raw === undefined || raw === null) {
18
21
  return now.toISOString().slice(0, 10);
19
22
  }
20
23
  const value = String(raw);
21
24
  if (!isValidActivityDate(value)) {
22
- throw new Error(`invalid --date ${value}; expected YYYY-MM-DD`);
25
+ // Typed so the HTTP surface maps it to 400 (EngramAccessInputError);
26
+ // subclasses Error, so the CLI still prints the message verbatim.
27
+ throw new EngramAccessInputError(`invalid --date ${value}; expected YYYY-MM-DD`);
23
28
  }
24
29
  return value;
25
30
  }
26
31
 
27
- export function previousDate(date: string): string {
32
+ /** Look back at most this many days for the prior active day (issue #1981). */
33
+ const STANDUP_PRIOR_DAY_LOOKBACK = 7;
34
+
35
+ function shiftDays(date: string, days: number): string {
28
36
  const ms = Date.parse(`${date}T00:00:00Z`);
29
- return new Date(ms - 86_400_000).toISOString().slice(0, 10);
37
+ return new Date(ms + days * 86_400_000).toISOString().slice(0, 10);
38
+ }
39
+
40
+ /**
41
+ * Prior active day: the most recent of the 7 days before `date` that has an
42
+ * activity digest (working-day lookback — Monday resolves to Friday, not
43
+ * Sunday, when the weekend has no digests). Calendar-previous day when no
44
+ * day in the window qualifies.
45
+ */
46
+ export function previousActiveDate(memoryDir: string, date: string): string {
47
+ for (let back = 1; back <= STANDUP_PRIOR_DAY_LOOKBACK; back += 1) {
48
+ const candidate = shiftDays(date, -back);
49
+ if (readOptional(activityDigestPath(memoryDir, candidate)) !== null) return candidate;
50
+ }
51
+ return shiftDays(date, -1);
30
52
  }
31
53
 
32
54
  export function buildStandup(memoryDir: string, date: string): StandupBrief {
33
- const yesterday = previousDate(date);
55
+ const yesterday = previousActiveDate(memoryDir, date);
34
56
  const todayBody = readOptional(activityDigestPath(memoryDir, date));
35
57
  const yesterdayBody = readOptional(activityDigestPath(memoryDir, yesterday));
36
- const highlights = extractHighlights(todayBody);
37
- const blockers = extractBlockers(todayBody);
38
- const activityGrid = renderGrid(yesterdayBody, todayBody);
58
+ const highlights = extractHighlights(yesterdayBody);
59
+ const commitments = sortCommitments(readOpenCommitments(memoryDir));
60
+ const dateMs = Date.parse(`${date}T00:00:00Z`);
61
+ const overdue = commitments.filter(
62
+ (c) => c.expiresAt !== undefined && Number.isFinite(Date.parse(c.expiresAt)) && Date.parse(c.expiresAt) < dateMs,
63
+ );
64
+ const open = commitments.filter((c) => !overdue.includes(c));
65
+ const priorities = open.map((c) => (c.expiresAt ? `${c.text} (due ${c.expiresAt.slice(0, 10)})` : c.text));
66
+ const blockers = [
67
+ ...extractBlockers(yesterdayBody),
68
+ ...overdue.map((c) => `commitment past due: ${c.text} (was due ${c.expiresAt?.slice(0, 10)})`),
69
+ ];
70
+ const activityGrid = renderGrid(yesterday, yesterdayBody);
39
71
  const markdown = [
40
72
  `# Standup ${date}`,
41
73
  "",
@@ -48,6 +80,9 @@ export function buildStandup(memoryDir: string, date: string): StandupBrief {
48
80
  "## Highlights",
49
81
  ...(highlights.length > 0 ? highlights.map((line) => `- ${line}`) : ["- _None._"]),
50
82
  "",
83
+ "## Today's priorities",
84
+ ...(priorities.length > 0 ? priorities.map((line) => `- ${line}`) : ["- (no tracked commitments — add priorities manually)"]),
85
+ "",
51
86
  "## Blockers",
52
87
  ...(blockers.length > 0 ? blockers.map((line) => `- ${line}`) : ["- _None._"]),
53
88
  "",
@@ -61,6 +96,7 @@ export function buildStandup(memoryDir: string, date: string): StandupBrief {
61
96
  yesterday,
62
97
  today: date,
63
98
  highlights,
99
+ priorities,
64
100
  blockers,
65
101
  activityGrid,
66
102
  markdown,
@@ -75,13 +111,28 @@ function readOptional(filePath: string): string | null {
75
111
  }
76
112
  }
77
113
 
114
+ /** Drop a leading `--- … ---` frontmatter block so its fields never render. */
115
+ function stripFrontmatter(body: string): string {
116
+ const lines = body.split("\n");
117
+ if (lines[0]?.trim() !== "---") return body;
118
+ const end = lines.indexOf("---", 1);
119
+ return end < 0 ? body : lines.slice(end + 1).join("\n");
120
+ }
121
+
78
122
  function firstLines(body: string, n: number): string {
79
- return body.split("\n").filter((line) => !line.startsWith("---")).slice(0, n).join("\n").trim() || "_Empty digest._";
123
+ return (
124
+ stripFrontmatter(body)
125
+ .split("\n")
126
+ .filter((line) => line.trim().length > 0 && !line.startsWith("#") && !line.startsWith("---"))
127
+ .slice(0, n)
128
+ .join("\n")
129
+ .trim() || "_Empty digest._"
130
+ );
80
131
  }
81
132
 
82
133
  function extractHighlights(body: string | null): string[] {
83
134
  if (!body) return [];
84
- return body
135
+ return stripFrontmatter(body)
85
136
  .split("\n")
86
137
  .map((line) => line.replace(/^[-*]\s+/, "").trim())
87
138
  .filter((line) => line.length > 0 && !line.startsWith("#") && !line.startsWith("---"))
@@ -90,26 +141,124 @@ function extractHighlights(body: string | null): string[] {
90
141
 
91
142
  function extractBlockers(body: string | null): string[] {
92
143
  if (!body) return [];
93
- return body
144
+ return stripFrontmatter(body)
94
145
  .split("\n")
95
- .map((line) => line.trim())
96
- .filter((line) => /blocker|blocked|stuck|waiting/i.test(line))
146
+ .map((line) => line.replace(/^[-*]\s+/, "").trim())
147
+ .filter((line) => line.length > 0 && /blocker|blocked|stuck|waiting/i.test(line))
97
148
  .slice(0, 5);
98
149
  }
99
150
 
100
- function renderGrid(yesterday: string | null, today: string | null): string {
101
- const y = yesterday ? "x" : ".";
102
- const t = today ? "x" : ".";
103
- return ["| day | digest |", "|---|---|", `| yesterday | ${y} |`, `| today | ${t} |`].join("\n");
151
+ // ── Activity grid (24 hour buckets, byte-stable) ────────────────────────────
152
+
153
+ const GRID_GLYPHS = ["░", "▁", "", "▃", "", "█"] as const;
154
+
155
+ /** Local hour of a digest timeline span line `- [HH:MM] app — window`, or null. */
156
+ function spanHour(line: string): number | null {
157
+ if (!line.startsWith("- [")) return null;
158
+ const close = line.indexOf("]", 3);
159
+ if (close < 0) return null;
160
+ const clock = line.slice(3, close);
161
+ const sep = clock.indexOf(":");
162
+ if (sep <= 0) return null;
163
+ const hour = Number.parseInt(clock.slice(0, sep), 10);
164
+ return Number.isInteger(hour) && hour >= 0 && hour <= 23 ? hour : null;
165
+ }
166
+
167
+ function renderGrid(yesterday: string, body: string | null): string {
168
+ if (!body) return `prior day ${yesterday}: no activity digest (empty)`;
169
+ const counts: number[] = new Array(24).fill(0);
170
+ for (const line of stripFrontmatter(body).split("\n")) {
171
+ const hour = spanHour(line);
172
+ if (hour !== null) counts[hour] = counts[hour]! + 1;
173
+ }
174
+ const max = Math.max(...counts);
175
+ if (max === 0) return `prior day ${yesterday}: digest present, no timeline activity`;
176
+ const glyphs = counts
177
+ .map((count) =>
178
+ count === 0 ? "·" : GRID_GLYPHS[Math.min(GRID_GLYPHS.length - 1, Math.ceil((count / max) * GRID_GLYPHS.length) - 1)],
179
+ )
180
+ .join("");
181
+ const nonEmpty = counts.map((count, hour) => (count > 0 ? `${hour}` : null)).filter((h): h is string => h !== null);
182
+ return [`prior day ${yesterday} — 24 hour buckets (· = idle):`, glyphs, `non-empty hours: ${nonEmpty.join(", ")}`].join(
183
+ "\n",
184
+ );
185
+ }
186
+
187
+ // ── Open commitments (deterministic facts scan) ─────────────────────────────
188
+
189
+ interface OpenCommitment {
190
+ id: string;
191
+ text: string;
192
+ created: string;
193
+ expiresAt?: string;
194
+ }
195
+
196
+ function readOpenCommitments(memoryDir: string): OpenCommitment[] {
197
+ const factsDir = path.join(memoryDir, "facts");
198
+ let dayDirs: string[];
199
+ try {
200
+ dayDirs = readdirSync(factsDir, { withFileTypes: true })
201
+ .filter((entry) => entry.isDirectory() && !entry.isSymbolicLink() && isValidActivityDate(entry.name))
202
+ .map((entry) => entry.name)
203
+ .sort();
204
+ } catch {
205
+ return [];
206
+ }
207
+ const out: OpenCommitment[] = [];
208
+ for (const day of dayDirs) {
209
+ let files: string[];
210
+ try {
211
+ files = readdirSync(path.join(factsDir, day), { withFileTypes: true })
212
+ .filter((entry) => entry.isFile() && !entry.isSymbolicLink() && entry.name.endsWith(".md"))
213
+ .map((entry) => entry.name)
214
+ .sort();
215
+ } catch {
216
+ continue;
217
+ }
218
+ for (const name of files) {
219
+ const parsed = parseFrontmatter(readOptional(path.join(factsDir, day, name)) ?? "");
220
+ if (!parsed) continue;
221
+ const fm = parsed.frontmatter;
222
+ if (fm.category !== "commitment") continue;
223
+ if ((fm.status ?? "active") !== "active") continue;
224
+ if (fm.tags.some((tag) => tag === "fulfilled" || tag === "expired")) continue;
225
+ const text = parsed.content
226
+ .split("\n")
227
+ .map((line) => line.trim())
228
+ .find((line) => line.length > 0);
229
+ if (!text) continue;
230
+ out.push({
231
+ id: fm.id,
232
+ text,
233
+ created: fm.created,
234
+ ...(fm.expiresAt !== undefined ? { expiresAt: fm.expiresAt } : {}),
235
+ });
236
+ }
237
+ }
238
+ return out;
239
+ }
240
+
241
+ function sortCommitments(list: OpenCommitment[]): OpenCommitment[] {
242
+ return [...list].sort((a, b) => {
243
+ // Due-ness first: a commitment with a concrete expiry outranks an
244
+ // undated one; earlier expiry is more due. Created, then id, as the
245
+ // stable tiebreak (§12).
246
+ const aDated = a.expiresAt !== undefined ? 0 : 1;
247
+ const bDated = b.expiresAt !== undefined ? 0 : 1;
248
+ if (aDated !== bDated) return aDated - bDated;
249
+ const ka = a.expiresAt ?? a.created;
250
+ const kb = b.expiresAt ?? b.created;
251
+ if (ka !== kb) return ka < kb ? -1 : 1;
252
+ if (a.id !== b.id) return a.id < b.id ? -1 : 1;
253
+ return 0;
254
+ });
104
255
  }
105
256
 
106
257
  export function standupHelp(): string {
107
258
  return `Usage: remnic standup [--date YYYY-MM-DD]
108
259
 
109
- Deterministic yesterday/today/blockers brief plus an activity grid.
260
+ Deterministic yesterday/today/blockers brief: prior-working-day highlights,
261
+ today's priorities from open commitments, blocker candidates, and a 24-hour
262
+ activity grid.
110
263
  `;
111
264
  }
112
-
113
- export function standupMemoryDirPlaceholder(memoryDir: string): string {
114
- return path.resolve(memoryDir);
115
- }
@@ -10,6 +10,6 @@ export async function respondStandup(
10
10
  ): Promise<void> {
11
11
  const op = getOperation("standup");
12
12
  if (!op) throw new Error("access-boundary: operation not registered: standup");
13
- const output = (await op.run({ ...(date ? { date } : {}) }, { service })) as { result: unknown };
13
+ const output = (await op.run({ ...(date === null ? {} : { date }) }, { service })) as { result: unknown };
14
14
  respondJson(res, 200, output.result);
15
15
  }