nlm-memory 0.21.0 → 0.21.13

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 (413) hide show
  1. package/README.md +67 -12
  2. package/assets/replay-eval-dark.svg +26 -0
  3. package/assets/replay-eval-light.svg +26 -0
  4. package/dist/cli/digest.js +34 -7
  5. package/dist/cli/digest.js.map +1 -1
  6. package/dist/cli/nlm.d.ts +14 -0
  7. package/dist/cli/nlm.js +450 -65
  8. package/dist/cli/nlm.js.map +1 -1
  9. package/dist/cli/reprocess-job-adapters.d.ts +35 -0
  10. package/dist/cli/reprocess-job-adapters.js +80 -0
  11. package/dist/cli/reprocess-job-adapters.js.map +1 -0
  12. package/dist/cli/scope-coverage.js +4 -1
  13. package/dist/cli/scope-coverage.js.map +1 -1
  14. package/dist/cli/supersede.js +8 -7
  15. package/dist/cli/supersede.js.map +1 -1
  16. package/dist/core/actions/actions-log.d.ts +65 -8
  17. package/dist/core/actions/actions-log.js +134 -17
  18. package/dist/core/actions/actions-log.js.map +1 -1
  19. package/dist/core/actions/overlay.d.ts +11 -2
  20. package/dist/core/actions/overlay.js +18 -6
  21. package/dist/core/actions/overlay.js.map +1 -1
  22. package/dist/core/adapters/from-source.js +11 -3
  23. package/dist/core/adapters/from-source.js.map +1 -1
  24. package/dist/core/adapters/fs-wiki-writer.d.ts +44 -0
  25. package/dist/core/adapters/fs-wiki-writer.js +132 -0
  26. package/dist/core/adapters/fs-wiki-writer.js.map +1 -0
  27. package/dist/core/adapters/hermes-agent.d.ts +15 -2
  28. package/dist/core/adapters/hermes-agent.js +57 -11
  29. package/dist/core/adapters/hermes-agent.js.map +1 -1
  30. package/dist/core/adapters/memory-wiki-writer.d.ts +8 -0
  31. package/dist/core/adapters/memory-wiki-writer.js +16 -0
  32. package/dist/core/adapters/memory-wiki-writer.js.map +1 -0
  33. package/dist/core/adapters/muse.d.ts +51 -0
  34. package/dist/core/adapters/muse.js +271 -0
  35. package/dist/core/adapters/muse.js.map +1 -0
  36. package/dist/core/adapters/opencode.d.ts +11 -4
  37. package/dist/core/adapters/opencode.js +41 -7
  38. package/dist/core/adapters/opencode.js.map +1 -1
  39. package/dist/core/alerts/alert-state.d.ts +17 -0
  40. package/dist/core/alerts/alert-state.js +45 -0
  41. package/dist/core/alerts/alert-state.js.map +1 -0
  42. package/dist/core/alerts/check-and-alert.d.ts +28 -0
  43. package/dist/core/alerts/check-and-alert.js +53 -0
  44. package/dist/core/alerts/check-and-alert.js.map +1 -0
  45. package/dist/core/alerts/drift-transition.d.ts +27 -0
  46. package/dist/core/alerts/drift-transition.js +56 -0
  47. package/dist/core/alerts/drift-transition.js.map +1 -0
  48. package/dist/core/alerts/embedder-transition.d.ts +23 -0
  49. package/dist/core/alerts/embedder-transition.js +40 -0
  50. package/dist/core/alerts/embedder-transition.js.map +1 -0
  51. package/dist/core/alerts/fire-alert.d.ts +24 -0
  52. package/dist/core/alerts/fire-alert.js +72 -0
  53. package/dist/core/alerts/fire-alert.js.map +1 -0
  54. package/dist/core/alerts/job-alert.d.ts +12 -0
  55. package/dist/core/alerts/job-alert.js +37 -0
  56. package/dist/core/alerts/job-alert.js.map +1 -0
  57. package/dist/core/alerts/types.d.ts +104 -0
  58. package/dist/core/alerts/types.js +11 -0
  59. package/dist/core/alerts/types.js.map +1 -0
  60. package/dist/core/alerts/wiki-alert.d.ts +15 -0
  61. package/dist/core/alerts/wiki-alert.js +31 -0
  62. package/dist/core/alerts/wiki-alert.js.map +1 -0
  63. package/dist/core/classifier/prompt.d.ts +13 -0
  64. package/dist/core/classifier/prompt.js +52 -2
  65. package/dist/core/classifier/prompt.js.map +1 -1
  66. package/dist/core/dataset/build-dataset.d.ts +16 -1
  67. package/dist/core/dataset/build-dataset.js +105 -45
  68. package/dist/core/dataset/build-dataset.js.map +1 -1
  69. package/dist/core/digest/compose.d.ts +8 -0
  70. package/dist/core/digest/compose.js +54 -0
  71. package/dist/core/digest/compose.js.map +1 -1
  72. package/dist/core/digest/hook-injection.d.ts +1 -1
  73. package/dist/core/digest/hook-injection.js +9 -1
  74. package/dist/core/digest/hook-injection.js.map +1 -1
  75. package/dist/core/digest/hook-version-parity.d.ts +31 -0
  76. package/dist/core/digest/hook-version-parity.js +56 -0
  77. package/dist/core/digest/hook-version-parity.js.map +1 -0
  78. package/dist/core/embedding/pg-embed-backfill.js +1 -1
  79. package/dist/core/embedding/pg-embed-backfill.js.map +1 -1
  80. package/dist/core/exemplars/capture-from-session.d.ts +1 -1
  81. package/dist/core/exemplars/capture-from-session.js +3 -3
  82. package/dist/core/exemplars/capture-from-session.js.map +1 -1
  83. package/dist/core/exemplars/embed-backfill.d.ts +9 -0
  84. package/dist/core/exemplars/embed-backfill.js +9 -1
  85. package/dist/core/exemplars/embed-backfill.js.map +1 -1
  86. package/dist/core/exemplars/recall-code.d.ts +1 -1
  87. package/dist/core/exemplars/recall-code.js +2 -2
  88. package/dist/core/exemplars/recall-code.js.map +1 -1
  89. package/dist/core/facts/backfill-facts.d.ts +1 -1
  90. package/dist/core/facts/backfill-facts.js +4 -4
  91. package/dist/core/facts/backfill-facts.js.map +1 -1
  92. package/dist/core/facts/embed-backfill.d.ts +54 -0
  93. package/dist/core/facts/embed-backfill.js +109 -0
  94. package/dist/core/facts/embed-backfill.js.map +1 -0
  95. package/dist/core/facts/reconcile-facts.d.ts +42 -0
  96. package/dist/core/facts/reconcile-facts.js +133 -0
  97. package/dist/core/facts/reconcile-facts.js.map +1 -0
  98. package/dist/core/health/embed-failure-state.d.ts +4 -0
  99. package/dist/core/health/embed-failure-state.js +12 -0
  100. package/dist/core/health/embed-failure-state.js.map +1 -0
  101. package/dist/core/health/warmup-retry.d.ts +27 -0
  102. package/dist/core/health/warmup-retry.js +53 -0
  103. package/dist/core/health/warmup-retry.js.map +1 -0
  104. package/dist/core/health/warmup-state.d.ts +15 -0
  105. package/dist/core/health/warmup-state.js +15 -1
  106. package/dist/core/health/warmup-state.js.map +1 -1
  107. package/dist/core/hook/cite-memo.d.ts +11 -7
  108. package/dist/core/hook/cite-memo.js +25 -17
  109. package/dist/core/hook/cite-memo.js.map +1 -1
  110. package/dist/core/hook/hook-log.d.ts +13 -2
  111. package/dist/core/hook/hook-log.js +16 -8
  112. package/dist/core/hook/hook-log.js.map +1 -1
  113. package/dist/core/hook/memo.d.ts +10 -6
  114. package/dist/core/hook/memo.js +25 -17
  115. package/dist/core/hook/memo.js.map +1 -1
  116. package/dist/core/hook/pointer-block.d.ts +8 -1
  117. package/dist/core/hook/pointer-block.js +17 -4
  118. package/dist/core/hook/pointer-block.js.map +1 -1
  119. package/dist/core/hook/resolve-conversation-by-query.d.ts +6 -5
  120. package/dist/core/hook/resolve-conversation-by-query.js +24 -12
  121. package/dist/core/hook/resolve-conversation-by-query.js.map +1 -1
  122. package/dist/core/ingest/ingest-session.d.ts +1 -1
  123. package/dist/core/ingest/ingest-session.js +3 -3
  124. package/dist/core/ingest/ingest-session.js.map +1 -1
  125. package/dist/core/ingest/reclassify-oversized.d.ts +1 -1
  126. package/dist/core/ingest/reclassify-oversized.js +2 -2
  127. package/dist/core/ingest/reclassify-oversized.js.map +1 -1
  128. package/dist/core/ingest/reprocess.d.ts +1 -1
  129. package/dist/core/ingest/reprocess.js +2 -2
  130. package/dist/core/ingest/reprocess.js.map +1 -1
  131. package/dist/core/jobs/job-supervisor.d.ts +168 -0
  132. package/dist/core/jobs/job-supervisor.js +335 -0
  133. package/dist/core/jobs/job-supervisor.js.map +1 -0
  134. package/dist/core/learner/model.d.ts +63 -0
  135. package/dist/core/learner/model.js +30 -0
  136. package/dist/core/learner/model.js.map +1 -0
  137. package/dist/core/learner/service.d.ts +42 -0
  138. package/dist/core/learner/service.js +74 -0
  139. package/dist/core/learner/service.js.map +1 -0
  140. package/dist/core/learner/summary.d.ts +28 -0
  141. package/dist/core/learner/summary.js +70 -0
  142. package/dist/core/learner/summary.js.map +1 -0
  143. package/dist/core/learner/validate.d.ts +18 -0
  144. package/dist/core/learner/validate.js +95 -0
  145. package/dist/core/learner/validate.js.map +1 -0
  146. package/dist/core/metrics/re-derivation.d.ts +31 -2
  147. package/dist/core/metrics/re-derivation.js +36 -4
  148. package/dist/core/metrics/re-derivation.js.map +1 -1
  149. package/dist/core/outcome/coverage.d.ts +1 -1
  150. package/dist/core/outcome/coverage.js +2 -2
  151. package/dist/core/outcome/coverage.js.map +1 -1
  152. package/dist/core/outcome/rollup.d.ts +1 -1
  153. package/dist/core/outcome/rollup.js +4 -4
  154. package/dist/core/outcome/rollup.js.map +1 -1
  155. package/dist/core/providers/provider-registry.d.ts +40 -23
  156. package/dist/core/providers/provider-registry.js +99 -81
  157. package/dist/core/providers/provider-registry.js.map +1 -1
  158. package/dist/core/recall/citation-log.d.ts +10 -5
  159. package/dist/core/recall/citation-log.js +21 -10
  160. package/dist/core/recall/citation-log.js.map +1 -1
  161. package/dist/core/recall/hook-recall-log.d.ts +5 -2
  162. package/dist/core/recall/hook-recall-log.js +12 -6
  163. package/dist/core/recall/hook-recall-log.js.map +1 -1
  164. package/dist/core/recall/miss-log.d.ts +7 -4
  165. package/dist/core/recall/miss-log.js +18 -11
  166. package/dist/core/recall/miss-log.js.map +1 -1
  167. package/dist/core/recall/query-log.d.ts +8 -5
  168. package/dist/core/recall/query-log.js +16 -9
  169. package/dist/core/recall/query-log.js.map +1 -1
  170. package/dist/core/recall/recall-service.d.ts +10 -1
  171. package/dist/core/recall/recall-service.js +31 -12
  172. package/dist/core/recall/recall-service.js.map +1 -1
  173. package/dist/core/recall/recent-log.d.ts +6 -1
  174. package/dist/core/recall/recent-log.js +13 -5
  175. package/dist/core/recall/recent-log.js.map +1 -1
  176. package/dist/core/recall/related-concepts.d.ts +29 -0
  177. package/dist/core/recall/related-concepts.js +67 -0
  178. package/dist/core/recall/related-concepts.js.map +1 -0
  179. package/dist/core/recall/related-exemplars.d.ts +1 -1
  180. package/dist/core/recall/related-exemplars.js +2 -2
  181. package/dist/core/recall/related-exemplars.js.map +1 -1
  182. package/dist/core/recall/related-facts.d.ts +1 -1
  183. package/dist/core/recall/related-facts.js +3 -3
  184. package/dist/core/recall/related-facts.js.map +1 -1
  185. package/dist/core/recall-facts/fact-query-log.d.ts +8 -4
  186. package/dist/core/recall-facts/fact-query-log.js +16 -8
  187. package/dist/core/recall-facts/fact-query-log.js.map +1 -1
  188. package/dist/core/recall-facts/fact-recall-service.d.ts +2 -2
  189. package/dist/core/recall-facts/fact-recall-service.js +12 -12
  190. package/dist/core/recall-facts/fact-recall-service.js.map +1 -1
  191. package/dist/core/scheduler/scan-once.js +15 -14
  192. package/dist/core/scheduler/scan-once.js.map +1 -1
  193. package/dist/core/scheduler/scheduler.d.ts +3 -0
  194. package/dist/core/scheduler/scheduler.js +15 -11
  195. package/dist/core/scheduler/scheduler.js.map +1 -1
  196. package/dist/core/signals/failure-mode-recall.d.ts +1 -1
  197. package/dist/core/signals/failure-mode-recall.js +2 -2
  198. package/dist/core/signals/failure-mode-recall.js.map +1 -1
  199. package/dist/core/signals/stamp-scope.d.ts +2 -2
  200. package/dist/core/signals/stamp-scope.js +2 -2
  201. package/dist/core/signals/stamp-scope.js.map +1 -1
  202. package/dist/core/sources/source-registry.d.ts +49 -28
  203. package/dist/core/sources/source-registry.js +113 -70
  204. package/dist/core/sources/source-registry.js.map +1 -1
  205. package/dist/core/storage/pg-code-exemplar-store.d.ts +19 -10
  206. package/dist/core/storage/pg-code-exemplar-store.js +58 -27
  207. package/dist/core/storage/pg-code-exemplar-store.js.map +1 -1
  208. package/dist/core/storage/pg-entity-store.d.ts +6 -1
  209. package/dist/core/storage/pg-entity-store.js +33 -18
  210. package/dist/core/storage/pg-entity-store.js.map +1 -1
  211. package/dist/core/storage/pg-fact-ingest.d.ts +1 -1
  212. package/dist/core/storage/pg-fact-ingest.js +10 -7
  213. package/dist/core/storage/pg-fact-ingest.js.map +1 -1
  214. package/dist/core/storage/pg-fact-store.d.ts +29 -17
  215. package/dist/core/storage/pg-fact-store.js +99 -46
  216. package/dist/core/storage/pg-fact-store.js.map +1 -1
  217. package/dist/core/storage/pg-learner-store.d.ts +27 -0
  218. package/dist/core/storage/pg-learner-store.js +174 -0
  219. package/dist/core/storage/pg-learner-store.js.map +1 -0
  220. package/dist/core/storage/pg-session-store.d.ts +24 -20
  221. package/dist/core/storage/pg-session-store.js +162 -90
  222. package/dist/core/storage/pg-session-store.js.map +1 -1
  223. package/dist/core/storage/pg-signal-store.d.ts +10 -5
  224. package/dist/core/storage/pg-signal-store.js +24 -12
  225. package/dist/core/storage/pg-signal-store.js.map +1 -1
  226. package/dist/core/storage/pg-storage.d.ts +4 -0
  227. package/dist/core/storage/pg-storage.js +6 -0
  228. package/dist/core/storage/pg-storage.js.map +1 -1
  229. package/dist/core/storage/pg-workstream-store.d.ts +16 -11
  230. package/dist/core/storage/pg-workstream-store.js +46 -29
  231. package/dist/core/storage/pg-workstream-store.js.map +1 -1
  232. package/dist/core/storage/sqlite-code-exemplar-store.d.ts +24 -10
  233. package/dist/core/storage/sqlite-code-exemplar-store.js +84 -40
  234. package/dist/core/storage/sqlite-code-exemplar-store.js.map +1 -1
  235. package/dist/core/storage/sqlite-entity-store.d.ts +8 -1
  236. package/dist/core/storage/sqlite-entity-store.js +46 -27
  237. package/dist/core/storage/sqlite-entity-store.js.map +1 -1
  238. package/dist/core/storage/sqlite-fact-store.d.ts +45 -19
  239. package/dist/core/storage/sqlite-fact-store.js +172 -64
  240. package/dist/core/storage/sqlite-fact-store.js.map +1 -1
  241. package/dist/core/storage/sqlite-learner-store.d.ts +33 -0
  242. package/dist/core/storage/sqlite-learner-store.js +178 -0
  243. package/dist/core/storage/sqlite-learner-store.js.map +1 -0
  244. package/dist/core/storage/sqlite-outcome-store.d.ts +37 -22
  245. package/dist/core/storage/sqlite-outcome-store.js +90 -37
  246. package/dist/core/storage/sqlite-outcome-store.js.map +1 -1
  247. package/dist/core/storage/sqlite-session-store.d.ts +29 -20
  248. package/dist/core/storage/sqlite-session-store.js +207 -121
  249. package/dist/core/storage/sqlite-session-store.js.map +1 -1
  250. package/dist/core/storage/sqlite-signal-store.d.ts +12 -5
  251. package/dist/core/storage/sqlite-signal-store.js +27 -15
  252. package/dist/core/storage/sqlite-signal-store.js.map +1 -1
  253. package/dist/core/storage/sqlite-storage.d.ts +4 -0
  254. package/dist/core/storage/sqlite-storage.js +10 -2
  255. package/dist/core/storage/sqlite-storage.js.map +1 -1
  256. package/dist/core/storage/sqlite-workstream-store.d.ts +16 -11
  257. package/dist/core/storage/sqlite-workstream-store.js +52 -31
  258. package/dist/core/storage/sqlite-workstream-store.js.map +1 -1
  259. package/dist/core/storage/supersedence-log.d.ts +10 -7
  260. package/dist/core/storage/supersedence-log.js +19 -14
  261. package/dist/core/storage/supersedence-log.js.map +1 -1
  262. package/dist/core/tenancy/default-team.d.ts +6 -0
  263. package/dist/core/tenancy/default-team.js +7 -0
  264. package/dist/core/tenancy/default-team.js.map +1 -0
  265. package/dist/core/tenancy/hosted-mode.d.ts +9 -0
  266. package/dist/core/tenancy/hosted-mode.js +12 -0
  267. package/dist/core/tenancy/hosted-mode.js.map +1 -0
  268. package/dist/core/tenancy/team-auth.d.ts +16 -0
  269. package/dist/core/tenancy/team-auth.js +22 -0
  270. package/dist/core/tenancy/team-auth.js.map +1 -0
  271. package/dist/core/tenancy/team-token-store.d.ts +45 -0
  272. package/dist/core/tenancy/team-token-store.js +52 -0
  273. package/dist/core/tenancy/team-token-store.js.map +1 -0
  274. package/dist/core/tenancy/tenant-clause.d.ts +37 -0
  275. package/dist/core/tenancy/tenant-clause.js +11 -0
  276. package/dist/core/tenancy/tenant-clause.js.map +1 -0
  277. package/dist/core/tenancy/tenant-state-path.d.ts +28 -0
  278. package/dist/core/tenancy/tenant-state-path.js +49 -0
  279. package/dist/core/tenancy/tenant-state-path.js.map +1 -0
  280. package/dist/core/wiki/project.d.ts +17 -0
  281. package/dist/core/wiki/project.js +37 -0
  282. package/dist/core/wiki/project.js.map +1 -0
  283. package/dist/core/wiki/reconcile.d.ts +15 -0
  284. package/dist/core/wiki/reconcile.js +14 -0
  285. package/dist/core/wiki/reconcile.js.map +1 -0
  286. package/dist/core/wiki/render.d.ts +5 -0
  287. package/dist/core/wiki/render.js +84 -0
  288. package/dist/core/wiki/render.js.map +1 -0
  289. package/dist/core/wiki/rollup.d.ts +28 -0
  290. package/dist/core/wiki/rollup.js +91 -0
  291. package/dist/core/wiki/rollup.js.map +1 -0
  292. package/dist/core/wiki/select.d.ts +8 -0
  293. package/dist/core/wiki/select.js +7 -0
  294. package/dist/core/wiki/select.js.map +1 -0
  295. package/dist/core/wiki/slug.d.ts +36 -0
  296. package/dist/core/wiki/slug.js +71 -0
  297. package/dist/core/wiki/slug.js.map +1 -0
  298. package/dist/core/wiki/types.d.ts +37 -0
  299. package/dist/core/wiki/types.js +2 -0
  300. package/dist/core/wiki/types.js.map +1 -0
  301. package/dist/core/work-digest/build-work-digest.d.ts +1 -1
  302. package/dist/core/work-digest/build-work-digest.js +3 -3
  303. package/dist/core/work-digest/build-work-digest.js.map +1 -1
  304. package/dist/core/workstream/bind.d.ts +1 -1
  305. package/dist/core/workstream/bind.js +10 -10
  306. package/dist/core/workstream/bind.js.map +1 -1
  307. package/dist/core/workstream/rollup.d.ts +1 -1
  308. package/dist/core/workstream/rollup.js +6 -6
  309. package/dist/core/workstream/rollup.js.map +1 -1
  310. package/dist/hook/hook-helpers.d.ts +14 -0
  311. package/dist/hook/hook-helpers.js +29 -2
  312. package/dist/hook/hook-helpers.js.map +1 -1
  313. package/dist/hook/pre-compact-hook.js +6 -4
  314. package/dist/hook/pre-compact-hook.js.map +1 -1
  315. package/dist/hook/prompt-recall-hook.d.ts +5 -2
  316. package/dist/hook/prompt-recall-hook.js +28 -17
  317. package/dist/hook/prompt-recall-hook.js.map +1 -1
  318. package/dist/hook/recall-over-http.d.ts +27 -3
  319. package/dist/hook/recall-over-http.js +44 -11
  320. package/dist/hook/recall-over-http.js.map +1 -1
  321. package/dist/hook/session-end-hook.js +7 -5
  322. package/dist/hook/session-end-hook.js.map +1 -1
  323. package/dist/hook/session-start-hook.d.ts +14 -1
  324. package/dist/hook/session-start-hook.js +55 -15
  325. package/dist/hook/session-start-hook.js.map +1 -1
  326. package/dist/hook/stop-hook.js +9 -7
  327. package/dist/hook/stop-hook.js.map +1 -1
  328. package/dist/http/app.d.ts +41 -3
  329. package/dist/http/app.js +355 -96
  330. package/dist/http/app.js.map +1 -1
  331. package/dist/install/claude-code.d.ts +17 -0
  332. package/dist/install/claude-code.js +44 -5
  333. package/dist/install/claude-code.js.map +1 -1
  334. package/dist/install/codex.d.ts +23 -2
  335. package/dist/install/codex.js +111 -14
  336. package/dist/install/codex.js.map +1 -1
  337. package/dist/install/cursor.d.ts +2 -2
  338. package/dist/install/cursor.js +7 -7
  339. package/dist/install/cursor.js.map +1 -1
  340. package/dist/install/hermes.d.ts +8 -0
  341. package/dist/install/hermes.js +28 -5
  342. package/dist/install/hermes.js.map +1 -1
  343. package/dist/install/local-source.d.ts +20 -0
  344. package/dist/install/local-source.js +28 -0
  345. package/dist/install/local-source.js.map +1 -0
  346. package/dist/install/mcp-block.d.ts +77 -0
  347. package/dist/install/mcp-block.js +99 -0
  348. package/dist/install/mcp-block.js.map +1 -0
  349. package/dist/install/pi.d.ts +26 -0
  350. package/dist/install/pi.js +43 -0
  351. package/dist/install/pi.js.map +1 -1
  352. package/dist/install/setup.js +6 -0
  353. package/dist/install/setup.js.map +1 -1
  354. package/dist/install/windsurf.d.ts +2 -2
  355. package/dist/install/windsurf.js +7 -7
  356. package/dist/install/windsurf.js.map +1 -1
  357. package/dist/llm/classifier-box.d.ts +5 -0
  358. package/dist/llm/classifier-box.js +5 -0
  359. package/dist/llm/classifier-box.js.map +1 -1
  360. package/dist/mcp/server.d.ts +73 -16
  361. package/dist/mcp/server.js +306 -83
  362. package/dist/mcp/server.js.map +1 -1
  363. package/dist/ports/clock.d.ts +12 -0
  364. package/dist/ports/clock.js +10 -0
  365. package/dist/ports/clock.js.map +1 -0
  366. package/dist/ports/code-exemplar-store.d.ts +13 -13
  367. package/dist/ports/entity-store.d.ts +5 -1
  368. package/dist/ports/fact-store.d.ts +0 -0
  369. package/dist/ports/fact-store.js +0 -0
  370. package/dist/ports/fact-store.js.map +1 -1
  371. package/dist/ports/learner-store.d.ts +80 -0
  372. package/dist/ports/learner-store.js +19 -0
  373. package/dist/ports/learner-store.js.map +1 -0
  374. package/dist/ports/outcome.d.ts +3 -3
  375. package/dist/ports/session-store.d.ts +20 -14
  376. package/dist/ports/session-store.js +5 -0
  377. package/dist/ports/session-store.js.map +1 -1
  378. package/dist/ports/signal-store.d.ts +12 -8
  379. package/dist/ports/spawn-child.d.ts +14 -0
  380. package/dist/ports/spawn-child.js +10 -0
  381. package/dist/ports/spawn-child.js.map +1 -0
  382. package/dist/ports/storage.d.ts +6 -0
  383. package/dist/ports/transcript-adapter.d.ts +11 -0
  384. package/dist/ports/wiki-writer.d.ts +19 -0
  385. package/dist/ports/wiki-writer.js +12 -0
  386. package/dist/ports/wiki-writer.js.map +1 -0
  387. package/dist/ports/workstream-store.d.ts +19 -12
  388. package/dist/shared/types.d.ts +22 -0
  389. package/dist/shared/types.js.map +1 -1
  390. package/dist/shared/version.d.ts +9 -0
  391. package/dist/shared/version.js +11 -0
  392. package/dist/shared/version.js.map +1 -0
  393. package/dist/ui/assets/index-D6F3xAis.js +11 -0
  394. package/dist/ui/index.html +1 -1
  395. package/migrations/033_actions_kind_check.sql +58 -0
  396. package/migrations/034_tenancy_teams_and_stamps.sql +40 -0
  397. package/migrations/035_tenancy_entity_rekey.sql +75 -0
  398. package/migrations/036_tenant_name_uniqueness.sql +59 -0
  399. package/migrations/037_sessions_covering_index.sql +25 -0
  400. package/migrations/038_sources_muse.sql +33 -0
  401. package/migrations/039_learner_evidence.sql +51 -0
  402. package/migrations/pg/033_actions_kind_check.sql +17 -0
  403. package/migrations/pg/034_tenancy.sql +77 -0
  404. package/migrations/pg/035_tenant_name_uniqueness.sql +15 -0
  405. package/migrations/pg/036_sources_muse.sql +12 -0
  406. package/migrations/pg/037_learner_evidence.sql +55 -0
  407. package/nlm/index.js +246 -55
  408. package/package.json +10 -5
  409. package/plugin/.codex-plugin/plugin.json +2 -2
  410. package/plugin/scripts/prompt-recall-hook.mjs +244 -55
  411. package/plugin/scripts/session-start-hook.mjs +273 -53
  412. package/plugin/scripts/stop-hook.mjs +195 -37
  413. package/dist/ui/assets/index-CSaBtgXD.js +0 -11
@@ -4,10 +4,13 @@
4
4
  * supersedence at ingest time is not logged here — that lineage is already
5
5
  * implicit in the session_edges row's predecessor reference.
6
6
  *
7
- * Path defaults to ~/.nlm/supersedence-log.jsonl, overridable via
8
- * NLM_SUPERSEDENCE_LOG. Telemetry path — never raises, but on failure it
9
- * emits one warning line to stderr so a silent disk-full or permission
10
- * issue doesn't leave the operator believing their audit trail is intact.
7
+ * Path is tenant-derived (core/tenancy/tenant-state-path.ts): the default
8
+ * team's log is ~/.nlm/supersedence-log.jsonl, overridable via
9
+ * NLM_SUPERSEDENCE_LOG; every other tenant is isolated under
10
+ * ~/.nlm/tenants/<tenantId>/supersedence-log.jsonl and ignores the env
11
+ * override. Telemetry path — never raises, but on failure it emits one
12
+ * warning line to stderr so a silent disk-full or permission issue doesn't
13
+ * leave the operator believing their audit trail is intact.
11
14
  */
12
15
  export interface SupersedenceEntry {
13
16
  readonly predecessorId: string;
@@ -16,7 +19,7 @@ export interface SupersedenceEntry {
16
19
  readonly source?: string;
17
20
  }
18
21
  /** Read all supersedence log entries. Never raises — returns [] on missing file. */
19
- export declare function readSupersedenceLog(): Promise<ReadonlyArray<SupersedenceEntry & {
22
+ export declare function readSupersedenceLog(tenantId: string, logPath?: string): Promise<ReadonlyArray<SupersedenceEntry & {
20
23
  ts: string;
21
24
  source?: string;
22
25
  }>>;
@@ -27,5 +30,5 @@ export interface FactSupersedenceEntry {
27
30
  }
28
31
  /** Append a fact-level supersedence event to the shared audit JSONL.
29
32
  * Entries carry `kind: "fact"` so the session-scoped reader skips them. */
30
- export declare function appendFactSupersedence(entry: FactSupersedenceEntry, logPath?: string): Promise<void>;
31
- export declare function appendSupersedence(entry: SupersedenceEntry, logPath?: string): Promise<void>;
33
+ export declare function appendFactSupersedence(tenantId: string, entry: FactSupersedenceEntry, logPath?: string): Promise<void>;
34
+ export declare function appendSupersedence(tenantId: string, entry: SupersedenceEntry, logPath?: string): Promise<void>;
@@ -4,24 +4,29 @@
4
4
  * supersedence at ingest time is not logged here — that lineage is already
5
5
  * implicit in the session_edges row's predecessor reference.
6
6
  *
7
- * Path defaults to ~/.nlm/supersedence-log.jsonl, overridable via
8
- * NLM_SUPERSEDENCE_LOG. Telemetry path — never raises, but on failure it
9
- * emits one warning line to stderr so a silent disk-full or permission
10
- * issue doesn't leave the operator believing their audit trail is intact.
7
+ * Path is tenant-derived (core/tenancy/tenant-state-path.ts): the default
8
+ * team's log is ~/.nlm/supersedence-log.jsonl, overridable via
9
+ * NLM_SUPERSEDENCE_LOG; every other tenant is isolated under
10
+ * ~/.nlm/tenants/<tenantId>/supersedence-log.jsonl and ignores the env
11
+ * override. Telemetry path — never raises, but on failure it emits one
12
+ * warning line to stderr so a silent disk-full or permission issue doesn't
13
+ * leave the operator believing their audit trail is intact.
11
14
  */
12
15
  import { appendFile, mkdir, readFile } from "node:fs/promises";
13
- import { dirname, join } from "node:path";
14
- import { homedir } from "node:os";
15
- function defaultLogPath() {
16
- return (process.env["NLM_SUPERSEDENCE_LOG"] ??
17
- join(homedir(), ".nlm", "supersedence-log.jsonl"));
16
+ import { dirname } from "node:path";
17
+ import { tenantStatePath } from "../tenancy/tenant-state-path.js";
18
+ import { DEFAULT_TEAM_ID } from "../tenancy/default-team.js";
19
+ function defaultLogPath(tenantId) {
20
+ if (tenantId === DEFAULT_TEAM_ID) {
21
+ return process.env["NLM_SUPERSEDENCE_LOG"] ?? tenantStatePath(tenantId, "supersedence-log.jsonl");
22
+ }
23
+ return tenantStatePath(tenantId, "supersedence-log.jsonl");
18
24
  }
19
25
  /** Read all supersedence log entries. Never raises — returns [] on missing file. */
20
- export async function readSupersedenceLog() {
21
- const path = defaultLogPath();
26
+ export async function readSupersedenceLog(tenantId, logPath = defaultLogPath(tenantId)) {
22
27
  let raw;
23
28
  try {
24
- raw = await readFile(path, "utf8");
29
+ raw = await readFile(logPath, "utf8");
25
30
  }
26
31
  catch {
27
32
  // Log file missing or unreadable - no supersedence history recovered.
@@ -53,7 +58,7 @@ export async function readSupersedenceLog() {
53
58
  }
54
59
  /** Append a fact-level supersedence event to the shared audit JSONL.
55
60
  * Entries carry `kind: "fact"` so the session-scoped reader skips them. */
56
- export async function appendFactSupersedence(entry, logPath = defaultLogPath()) {
61
+ export async function appendFactSupersedence(tenantId, entry, logPath = defaultLogPath(tenantId)) {
57
62
  try {
58
63
  await mkdir(dirname(logPath), { recursive: true });
59
64
  const payload = {
@@ -70,7 +75,7 @@ export async function appendFactSupersedence(entry, logPath = defaultLogPath())
70
75
  process.stderr.write(`nlm-memory: failed to append fact-supersedence-log entry at ${logPath}: ${msg}\n`);
71
76
  }
72
77
  }
73
- export async function appendSupersedence(entry, logPath = defaultLogPath()) {
78
+ export async function appendSupersedence(tenantId, entry, logPath = defaultLogPath(tenantId)) {
74
79
  try {
75
80
  await mkdir(dirname(logPath), { recursive: true });
76
81
  const payload = {
@@ -1 +1 @@
1
- {"version":3,"file":"supersedence-log.js","sourceRoot":"","sources":["../../../src/core/storage/supersedence-log.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"supersedence-log.js","sourceRoot":"","sources":["../../../src/core/storage/supersedence-log.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The fixed id of the single-tenant local deployment's team, seeded by
3
+ * migrations 034 (both lanes). A literal — never generated — so it can appear
4
+ * in sqlite column DEFAULTs (tenancy design doc, kept privately in .superpowers/).
5
+ */
6
+ export declare const DEFAULT_TEAM_ID = "team_local";
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The fixed id of the single-tenant local deployment's team, seeded by
3
+ * migrations 034 (both lanes). A literal — never generated — so it can appear
4
+ * in sqlite column DEFAULTs (tenancy design doc, kept privately in .superpowers/).
5
+ */
6
+ export const DEFAULT_TEAM_ID = "team_local";
7
+ //# sourceMappingURL=default-team.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"default-team.js","sourceRoot":"","sources":["../../../src/core/tenancy/default-team.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,YAAY,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * NLM_HOSTED=1 switches the daemon to hosted posture. Under hosted mode,
3
+ * LOCAL-dispositioned routes (whole-DB dataset/backup/restore/stats,
4
+ * process-global classifier swap) and M6-FILTER routes (citation events,
5
+ * recall/facts stats+recent, hook-memo trio — file-state surfaces not yet
6
+ * tenant-attributed) return 403 before touching any handler (program spec
7
+ * §4.6). Local mode (the default, no env set) is unaffected.
8
+ */
9
+ export declare function isHostedMode(): boolean;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * NLM_HOSTED=1 switches the daemon to hosted posture. Under hosted mode,
3
+ * LOCAL-dispositioned routes (whole-DB dataset/backup/restore/stats,
4
+ * process-global classifier swap) and M6-FILTER routes (citation events,
5
+ * recall/facts stats+recent, hook-memo trio — file-state surfaces not yet
6
+ * tenant-attributed) return 403 before touching any handler (program spec
7
+ * §4.6). Local mode (the default, no env set) is unaffected.
8
+ */
9
+ export function isHostedMode() {
10
+ return process.env["NLM_HOSTED"] === "1";
11
+ }
12
+ //# sourceMappingURL=hosted-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hosted-mode.js","sourceRoot":"","sources":["../../../src/core/tenancy/hosted-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,GAAG,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * resolveTeamByToken — the one auth-only tenant-resolution function every
3
+ * gated network transport routes through (program spec §3: "The tenant is
4
+ * resolved from the authenticated credential and from nothing else").
5
+ *
6
+ * Mechanism: sha256-hex the presented bearer token, look up
7
+ * `team_tokens WHERE token_hash = $hash AND revoked_at IS NULL`, return the
8
+ * team_id. No ambient derivation, no request parameter, no fallback chain —
9
+ * a token that doesn't resolve returns null and the caller denies.
10
+ */
11
+ import type { TeamTokenStorePort } from "./team-token-store.js";
12
+ export interface ResolvedTeam {
13
+ readonly teamId: string;
14
+ }
15
+ export declare function hashTeamToken(token: string): string;
16
+ export declare function resolveTeamByToken(store: TeamTokenStorePort, presentedToken: string | undefined | null): Promise<ResolvedTeam | null>;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * resolveTeamByToken — the one auth-only tenant-resolution function every
3
+ * gated network transport routes through (program spec §3: "The tenant is
4
+ * resolved from the authenticated credential and from nothing else").
5
+ *
6
+ * Mechanism: sha256-hex the presented bearer token, look up
7
+ * `team_tokens WHERE token_hash = $hash AND revoked_at IS NULL`, return the
8
+ * team_id. No ambient derivation, no request parameter, no fallback chain —
9
+ * a token that doesn't resolve returns null and the caller denies.
10
+ */
11
+ import { createHash } from "node:crypto";
12
+ export function hashTeamToken(token) {
13
+ return createHash("sha256").update(token, "utf8").digest("hex");
14
+ }
15
+ export async function resolveTeamByToken(store, presentedToken) {
16
+ if (!presentedToken)
17
+ return null;
18
+ const hash = hashTeamToken(presentedToken);
19
+ const row = await store.findActiveByHash(hash);
20
+ return row ? { teamId: row.teamId } : null;
21
+ }
22
+ //# sourceMappingURL=team-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team-auth.js","sourceRoot":"","sources":["../../../src/core/tenancy/team-auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAOzC,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,KAAyB,EACzB,cAAyC;IAEzC,IAAI,CAAC,cAAc;QAAE,OAAO,IAAI,CAAC;IACjC,MAAM,IAAI,GAAG,aAAa,CAAC,cAAc,CAAC,CAAC;IAC3C,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAC/C,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7C,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * TeamTokenStore / PgTeamTokenStore — CRUD over the `team_tokens` table
3
+ * (program spec §2 M1, §3 M3). This IS the tenancy registry, not corpus
4
+ * data: methods take no `tenantId` param by design, same pinned exception as
5
+ * SourceRegistry.findByToken (src/core/sources/source-registry.ts) — the
6
+ * whole point of this store is to RESOLVE a tenant from a presented token,
7
+ * not to be scoped by one. team_tokens is TENANT-NEUTRAL and exempt from the
8
+ * tenantClause guard (tests/integration/tenant-guard.test.ts) for the same
9
+ * reason findByToken is exempt.
10
+ */
11
+ import type Database from "better-sqlite3";
12
+ import type { Pool } from "pg";
13
+ export interface ResolvedTeamToken {
14
+ readonly teamId: string;
15
+ }
16
+ export interface TeamTokenStorePort {
17
+ /** AUTH lookup: resolves an active (non-revoked) token hash to its team. */
18
+ findActiveByHash(hash: string): Promise<ResolvedTeamToken | null>;
19
+ insert(hash: string, teamId: string): Promise<void>;
20
+ revoke(hash: string): Promise<void>;
21
+ /**
22
+ * Idempotent insert-if-absent. Used for local-mode boot continuity (M3
23
+ * §3): an existing NLM_MCP_TOKEN's hash is seeded once for the default
24
+ * team so it keeps authenticating through the same resolveTeamByToken
25
+ * path as any future per-team token. A no-op if the hash already has a
26
+ * row (active OR revoked) — never resurrects a deliberately revoked token.
27
+ */
28
+ ensureActive(hash: string, teamId: string): Promise<void>;
29
+ }
30
+ export declare class TeamTokenStore implements TeamTokenStorePort {
31
+ private readonly db;
32
+ constructor(db: Database.Database);
33
+ findActiveByHash(hash: string): Promise<ResolvedTeamToken | null>;
34
+ insert(hash: string, teamId: string): Promise<void>;
35
+ revoke(hash: string): Promise<void>;
36
+ ensureActive(hash: string, teamId: string): Promise<void>;
37
+ }
38
+ export declare class PgTeamTokenStore implements TeamTokenStorePort {
39
+ private readonly pool;
40
+ constructor(pool: Pool);
41
+ findActiveByHash(hash: string): Promise<ResolvedTeamToken | null>;
42
+ insert(hash: string, teamId: string): Promise<void>;
43
+ revoke(hash: string): Promise<void>;
44
+ ensureActive(hash: string, teamId: string): Promise<void>;
45
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * TeamTokenStore / PgTeamTokenStore — CRUD over the `team_tokens` table
3
+ * (program spec §2 M1, §3 M3). This IS the tenancy registry, not corpus
4
+ * data: methods take no `tenantId` param by design, same pinned exception as
5
+ * SourceRegistry.findByToken (src/core/sources/source-registry.ts) — the
6
+ * whole point of this store is to RESOLVE a tenant from a presented token,
7
+ * not to be scoped by one. team_tokens is TENANT-NEUTRAL and exempt from the
8
+ * tenantClause guard (tests/integration/tenant-guard.test.ts) for the same
9
+ * reason findByToken is exempt.
10
+ */
11
+ export class TeamTokenStore {
12
+ db;
13
+ constructor(db) {
14
+ this.db = db;
15
+ }
16
+ async findActiveByHash(hash) {
17
+ const row = this.db.prepare("SELECT team_id FROM team_tokens WHERE token_hash = ? AND revoked_at IS NULL").get(hash);
18
+ return row ? { teamId: row.team_id } : null;
19
+ }
20
+ async insert(hash, teamId) {
21
+ this.db.prepare("INSERT INTO team_tokens (token_hash, team_id) VALUES (?, ?)").run(hash, teamId);
22
+ }
23
+ async revoke(hash) {
24
+ this.db.prepare("UPDATE team_tokens SET revoked_at = datetime('now') WHERE token_hash = ?").run(hash);
25
+ }
26
+ async ensureActive(hash, teamId) {
27
+ const existing = this.db.prepare("SELECT token_hash FROM team_tokens WHERE token_hash = ?").get(hash);
28
+ if (existing)
29
+ return;
30
+ await this.insert(hash, teamId);
31
+ }
32
+ }
33
+ export class PgTeamTokenStore {
34
+ pool;
35
+ constructor(pool) {
36
+ this.pool = pool;
37
+ }
38
+ async findActiveByHash(hash) {
39
+ const result = await this.pool.query("SELECT team_id FROM team_tokens WHERE token_hash = $1 AND revoked_at IS NULL", [hash]);
40
+ return result.rows[0] ? { teamId: result.rows[0].team_id } : null;
41
+ }
42
+ async insert(hash, teamId) {
43
+ await this.pool.query("INSERT INTO team_tokens (token_hash, team_id) VALUES ($1, $2)", [hash, teamId]);
44
+ }
45
+ async revoke(hash) {
46
+ await this.pool.query("UPDATE team_tokens SET revoked_at = NOW() WHERE token_hash = $1", [hash]);
47
+ }
48
+ async ensureActive(hash, teamId) {
49
+ await this.pool.query("INSERT INTO team_tokens (token_hash, team_id) VALUES ($1, $2) ON CONFLICT (token_hash) DO NOTHING", [hash, teamId]);
50
+ }
51
+ }
52
+ //# sourceMappingURL=team-token-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team-token-store.js","sourceRoot":"","sources":["../../../src/core/tenancy/team-token-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA4BH,MAAM,OAAO,cAAc;IACI;IAA7B,YAA6B,EAAqB;QAArB,OAAE,GAAF,EAAE,CAAmB;IAAG,CAAC;IAEtD,KAAK,CAAC,gBAAgB,CAAC,IAAY;QACjC,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CACzB,6EAA6E,CAC9E,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACZ,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAY,EAAE,MAAc;QACvC,IAAI,CAAC,EAAE,CAAC,OAAO,CACb,6DAA6D,CAC9D,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAY;QACvB,IAAI,CAAC,EAAE,CAAC,OAAO,CACb,0EAA0E,CAC3E,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACd,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,IAAY,EAAE,MAAc;QAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAC9B,yDAAyD,CAC1D,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACZ,IAAI,QAAQ;YAAE,OAAO;QACrB,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAClC,CAAC;CACF;AAED,MAAM,OAAO,gBAAgB;IACE;IAA7B,YAA6B,IAAU;QAAV,SAAI,GAAJ,IAAI,CAAM;IAAG,CAAC;IAE3C,KAAK,CAAC,gBAAgB,CAAC,IAAY;QACjC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAClC,8EAA8E,EAC9E,CAAC,IAAI,CAAC,CACP,CAAC;QACF,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACpE,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAY,EAAE,MAAc;QACvC,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CACnB,+DAA+D,EAC/D,CAAC,IAAI,EAAE,MAAM,CAAC,CACf,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAY;QACvB,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CACnB,iEAAiE,EACjE,CAAC,IAAI,CAAC,CACP,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,IAAY,EAAE,MAAc;QAC7C,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CACnB,mGAAmG,EACnG,CAAC,IAAI,EAAE,MAAM,CAAC,CACf,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * tenantClause / tenantClausePg — the single WHERE-fragment builder every
3
+ * corpus SQL string routes through (program spec §4.2). Wave C's guard test
4
+ * (tests/integration/tenant-guard.test.ts) scans src/core/storage/*.ts,
5
+ * actions-log.ts, build-dataset.ts, and http/app.ts for the literal text
6
+ * `tenant_id =`; the invariant this file exists to hold is that the literal
7
+ * appears ONLY here (migrations excepted).
8
+ *
9
+ * Two entry points because the two backends bind params differently, and
10
+ * both existing store idioms build a WHERE clause the same way — a
11
+ * `where: string[]` of fragments joined with " AND ", pushed alongside a
12
+ * parallel `params: unknown[]` array (see SqliteFactStore.list / .listBySessions,
13
+ * PgFactStore.list) — so a helper that returns one `{sql, param}` pair slots
14
+ * directly into that pattern for both:
15
+ *
16
+ * sqlite (better-sqlite3, positional `?`):
17
+ * const c = tenantClause(tenantId);
18
+ * where.push(c.sql); params.push(c.param);
19
+ *
20
+ * pg (node-postgres, numbered `$n`, tracked via a running `idx`):
21
+ * const c = tenantClausePg(tenantId, idx++);
22
+ * where.push(c.sql); params.push(c.param);
23
+ *
24
+ * For single-fragment templates (SqliteSessionStore.getById et al., built as
25
+ * a fixed template literal rather than a where[]/params[] pair), the fragment
26
+ * still composes: interpolate `c.sql` at the right spot in the template and
27
+ * append `c.param` to the positional argument list in the matching order.
28
+ *
29
+ * `column` defaults to the bare column name but accepts an alias-qualified
30
+ * form (e.g. "s.tenant_id") for joined queries.
31
+ */
32
+ export interface TenantClause {
33
+ readonly sql: string;
34
+ readonly param: string;
35
+ }
36
+ export declare function tenantClause(tenantId: string, column?: string): TenantClause;
37
+ export declare function tenantClausePg(tenantId: string, paramIndex: number, column?: string): TenantClause;
@@ -0,0 +1,11 @@
1
+ export function tenantClause(tenantId, column = "tenant_id") {
2
+ if (!tenantId)
3
+ throw new Error("tenantClause: tenantId is required");
4
+ return { sql: `${column} = ?`, param: tenantId };
5
+ }
6
+ export function tenantClausePg(tenantId, paramIndex, column = "tenant_id") {
7
+ if (!tenantId)
8
+ throw new Error("tenantClausePg: tenantId is required");
9
+ return { sql: `${column} = $${paramIndex}`, param: tenantId };
10
+ }
11
+ //# sourceMappingURL=tenant-clause.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant-clause.js","sourceRoot":"","sources":["../../../src/core/tenancy/tenant-clause.ts"],"names":[],"mappings":"AAoCA,MAAM,UAAU,YAAY,CAAC,QAAgB,EAAE,MAAM,GAAG,WAAW;IACjE,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACrE,OAAO,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,UAAkB,EAAE,MAAM,GAAG,WAAW;IACvF,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IACvE,OAAO,EAAE,GAAG,EAAE,GAAG,MAAM,OAAO,UAAU,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AAChE,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Path derivation for the shared file-state modules (hook memo, hook log,
3
+ * query/citation/miss logs — the JSONL/JSON telemetry that predates
4
+ * per-tenant SQLite rows). The default team's paths are byte-identical to
5
+ * the pre-M6 layout (~/.nlm/<segments>); every other tenant is isolated
6
+ * under ~/.nlm/tenants/<sanitized-tenantId>/<same segments>, so file state
7
+ * stops leaking across tenants the way a shared ~/.nlm/query_log.jsonl did.
8
+ *
9
+ * Sanitization mirrors the conversation-id rule in core/hook/memo.ts
10
+ * ([^A-Za-z0-9_-] -> "_", with "unknown" as the fallback for an id that
11
+ * sanitizes to nothing) but is not injective on its own — "acme.co" and
12
+ * "acme_co" both sanitize to "acme_co", which would collide the two
13
+ * tenants' directories. An id already safe (matches [A-Za-z0-9_-]+) is used
14
+ * as-is; any other id gets the sanitized form plus an 8-hex-char sha256
15
+ * digest of the *raw* (pre-sanitization) id appended, so two ids that
16
+ * collide after sanitization always land in distinct directories.
17
+ *
18
+ * NLM_STATE_ROOT overrides the ~/.nlm base directory for every tenant,
19
+ * default team included (the two branches below share the same `base`).
20
+ * This is a root move, not a per-tenant redirect: it does not reintroduce
21
+ * the leak the per-file overrides (NLM_QUERY_LOG et al., which apply to the
22
+ * default team's file only) were scoped away from — every tenant's
23
+ * directory keeps moving together under the new root, so isolation between
24
+ * tenants is unaffected. Test-only; production leaves it unset.
25
+ */
26
+ export declare const TENANTS_DIRNAME = "tenants";
27
+ /** ~/.nlm/<segments> for the default team; ~/.nlm/tenants/<t>/<segments> otherwise. */
28
+ export declare function tenantStatePath(tenantId: string, ...segments: string[]): string;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Path derivation for the shared file-state modules (hook memo, hook log,
3
+ * query/citation/miss logs — the JSONL/JSON telemetry that predates
4
+ * per-tenant SQLite rows). The default team's paths are byte-identical to
5
+ * the pre-M6 layout (~/.nlm/<segments>); every other tenant is isolated
6
+ * under ~/.nlm/tenants/<sanitized-tenantId>/<same segments>, so file state
7
+ * stops leaking across tenants the way a shared ~/.nlm/query_log.jsonl did.
8
+ *
9
+ * Sanitization mirrors the conversation-id rule in core/hook/memo.ts
10
+ * ([^A-Za-z0-9_-] -> "_", with "unknown" as the fallback for an id that
11
+ * sanitizes to nothing) but is not injective on its own — "acme.co" and
12
+ * "acme_co" both sanitize to "acme_co", which would collide the two
13
+ * tenants' directories. An id already safe (matches [A-Za-z0-9_-]+) is used
14
+ * as-is; any other id gets the sanitized form plus an 8-hex-char sha256
15
+ * digest of the *raw* (pre-sanitization) id appended, so two ids that
16
+ * collide after sanitization always land in distinct directories.
17
+ *
18
+ * NLM_STATE_ROOT overrides the ~/.nlm base directory for every tenant,
19
+ * default team included (the two branches below share the same `base`).
20
+ * This is a root move, not a per-tenant redirect: it does not reintroduce
21
+ * the leak the per-file overrides (NLM_QUERY_LOG et al., which apply to the
22
+ * default team's file only) were scoped away from — every tenant's
23
+ * directory keeps moving together under the new root, so isolation between
24
+ * tenants is unaffected. Test-only; production leaves it unset.
25
+ */
26
+ import { createHash } from "node:crypto";
27
+ import { homedir } from "node:os";
28
+ import { join } from "node:path";
29
+ import { DEFAULT_TEAM_ID } from "./default-team.js";
30
+ export const TENANTS_DIRNAME = "tenants";
31
+ const SAFE_TENANT_ID = /^[A-Za-z0-9_-]+$/;
32
+ function sanitizeTenantId(tenantId) {
33
+ if (SAFE_TENANT_ID.test(tenantId))
34
+ return tenantId;
35
+ const sanitized = tenantId.replace(/[^A-Za-z0-9_-]/g, "_") || "unknown";
36
+ const hash = createHash("sha256").update(tenantId).digest("hex").slice(0, 8);
37
+ return `${sanitized}_${hash}`;
38
+ }
39
+ function stateRoot() {
40
+ return process.env["NLM_STATE_ROOT"] || join(homedir(), ".nlm");
41
+ }
42
+ /** ~/.nlm/<segments> for the default team; ~/.nlm/tenants/<t>/<segments> otherwise. */
43
+ export function tenantStatePath(tenantId, ...segments) {
44
+ const base = stateRoot();
45
+ if (tenantId === DEFAULT_TEAM_ID)
46
+ return join(base, ...segments);
47
+ return join(base, TENANTS_DIRNAME, sanitizeTenantId(tenantId), ...segments);
48
+ }
49
+ //# sourceMappingURL=tenant-state-path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant-state-path.js","sourceRoot":"","sources":["../../../src/core/tenancy/tenant-state-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,CAAC,MAAM,eAAe,GAAG,SAAS,CAAC;AAEzC,MAAM,cAAc,GAAG,kBAAkB,CAAC;AAE1C,SAAS,gBAAgB,CAAC,QAAgB;IACxC,IAAI,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAC;IACnD,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,IAAI,SAAS,CAAC;IACxE,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7E,OAAO,GAAG,SAAS,IAAI,IAAI,EAAE,CAAC;AAChC,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC,CAAC;AAClE,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,GAAG,QAAkB;IACrE,MAAM,IAAI,GAAG,SAAS,EAAE,CAAC;IACzB,IAAI,QAAQ,KAAK,eAAe;QAAE,OAAO,IAAI,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,CAAC;IACjE,OAAO,IAAI,CAAC,IAAI,EAAE,eAAe,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EAAE,GAAG,QAAQ,CAAC,CAAC;AAC9E,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * The projection: select, roll up, render, reconcile.
3
+ *
4
+ * Reads current content through the writer so reconcile can skip unchanged
5
+ * files. Colliding spellings of one subject merge into a single page rather
6
+ * than throwing (see slug.ts); only a slug that collides with a reserved
7
+ * generated filename still propagates, because the alternative there is one
8
+ * page silently overwriting the index or log.
9
+ */
10
+ import type { FactStore } from "../../ports/fact-store.js";
11
+ import type { WikiWriter } from "../../ports/wiki-writer.js";
12
+ import type { ProjectionResult, WikiConfig } from "./types.js";
13
+ export interface ProjectDeps {
14
+ readonly facts: Pick<FactStore, "listSubjectStats" | "listBySubjects">;
15
+ readonly writer: WikiWriter;
16
+ }
17
+ export declare function projectWiki(deps: ProjectDeps, tenantId: string, config: WikiConfig, today: string): Promise<ProjectionResult>;
@@ -0,0 +1,37 @@
1
+ import { buildSlugGroups } from "./slug.js";
2
+ import { selectSubjects } from "./select.js";
3
+ import { rollupPages } from "./rollup.js";
4
+ import { renderAll } from "./render.js";
5
+ import { planReconcile } from "./reconcile.js";
6
+ export async function projectWiki(deps, tenantId, config, today) {
7
+ const stats = await deps.facts.listSubjectStats(tenantId);
8
+ const selected = selectSubjects(stats, config);
9
+ const groups = buildSlugGroups(selected.map((s) => s.subject));
10
+ const pages = await rollupPages(deps, tenantId, selected, groups);
11
+ const rendered = renderAll(pages, config, today);
12
+ const existing = await deps.writer.list();
13
+ const rendering = new Set(rendered.map((r) => r.relPath));
14
+ const current = new Map();
15
+ for (const relPath of existing) {
16
+ if (!rendering.has(relPath))
17
+ continue;
18
+ const content = await deps.writer.read(relPath);
19
+ if (content !== null)
20
+ current.set(relPath, content);
21
+ }
22
+ const plan = planReconcile(rendered, existing, current);
23
+ for (const file of plan.toWrite)
24
+ await deps.writer.write(file.relPath, file.content);
25
+ for (const relPath of plan.toRemove)
26
+ await deps.writer.remove(relPath);
27
+ const onDisk = (await deps.writer.list()).filter((p) => p !== "index.md" && p !== "log.md").length;
28
+ return {
29
+ written: plan.toWrite.length,
30
+ unchanged: plan.unchanged,
31
+ removed: plan.toRemove.length,
32
+ qualifying: pages.length,
33
+ onDisk,
34
+ coverageDrift: pages.length - onDisk,
35
+ };
36
+ }
37
+ //# sourceMappingURL=project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.js","sourceRoot":"","sources":["../../../src/core/wiki/project.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAO/C,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAAiB,EACjB,QAAgB,EAChB,MAAkB,EAClB,KAAa;IAEb,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC1D,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,eAAe,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IAClE,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IAEjD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IAC1C,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAC1D,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,SAAS;QACtC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAChD,IAAI,OAAO,KAAK,IAAI;YAAE,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,IAAI,GAAG,aAAa,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IACxD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACrF,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAEvE,MAAM,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,UAAU,IAAI,CAAC,KAAK,QAAQ,CAAC,CAAC,MAAM,CAAC;IACnG,OAAO;QACL,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM;QAC5B,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM;QAC7B,UAAU,EAAE,KAAK,CAAC,MAAM;QACxB,MAAM;QACN,aAAa,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM;KACrC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Diff the rendered set against what is on disk.
3
+ *
4
+ * Skipping byte-identical files is what makes a 6-hourly job free: a run with
5
+ * no corpus change writes nothing and Obsidian never re-indexes. Removing
6
+ * files with no rendered counterpart is what keeps the tree a projection
7
+ * rather than an append-only pile.
8
+ */
9
+ import type { RenderedPage } from "./types.js";
10
+ export interface ReconcilePlan {
11
+ readonly toWrite: ReadonlyArray<RenderedPage>;
12
+ readonly toRemove: ReadonlyArray<string>;
13
+ readonly unchanged: number;
14
+ }
15
+ export declare function planReconcile(rendered: ReadonlyArray<RenderedPage>, existing: ReadonlyArray<string>, current: ReadonlyMap<string, string>): ReconcilePlan;
@@ -0,0 +1,14 @@
1
+ export function planReconcile(rendered, existing, current) {
2
+ const toWrite = [];
3
+ let unchanged = 0;
4
+ for (const file of rendered) {
5
+ if (current.get(file.relPath) === file.content)
6
+ unchanged += 1;
7
+ else
8
+ toWrite.push(file);
9
+ }
10
+ const keep = new Set(rendered.map((f) => f.relPath));
11
+ const toRemove = existing.filter((p) => !keep.has(p));
12
+ return { toWrite, toRemove, unchanged };
13
+ }
14
+ //# sourceMappingURL=reconcile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reconcile.js","sourceRoot":"","sources":["../../../src/core/wiki/reconcile.ts"],"names":[],"mappings":"AAgBA,MAAM,UAAU,aAAa,CAC3B,QAAqC,EACrC,QAA+B,EAC/B,OAAoC;IAEpC,MAAM,OAAO,GAAmB,EAAE,CAAC;IACnC,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,OAAO;YAAE,SAAS,IAAI,CAAC,CAAC;;YAC1D,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { PageRollup, RenderedPage, WikiConfig } from "./types.js";
2
+ export declare function renderPage(page: PageRollup, config: WikiConfig): RenderedPage;
3
+ export declare function renderIndex(pages: ReadonlyArray<PageRollup>, today: string): RenderedPage;
4
+ export declare function renderLog(pages: ReadonlyArray<PageRollup>, today: string): RenderedPage;
5
+ export declare function renderAll(pages: ReadonlyArray<PageRollup>, config: WikiConfig, today: string): ReadonlyArray<RenderedPage>;