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
@@ -1,20 +1,163 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/hook/session-start-hook.ts
4
- import { pathToFileURL } from "node:url";
4
+ import { execFileSync } from "node:child_process";
5
5
 
6
6
  // src/core/hook/hook-log.ts
7
7
  import { appendFileSync, mkdirSync } from "node:fs";
8
+ import { dirname } from "node:path";
9
+
10
+ // src/core/tenancy/tenant-state-path.ts
11
+ import { createHash } from "node:crypto";
8
12
  import { homedir } from "node:os";
9
- import { dirname, join } from "node:path";
10
- function logPath() {
11
- return process.env["NLM_HOOK_LOG"] ?? join(homedir(), ".nlm", "hook-log.jsonl");
13
+ import { join } from "node:path";
14
+
15
+ // src/core/tenancy/default-team.ts
16
+ var DEFAULT_TEAM_ID = "team_local";
17
+
18
+ // src/core/tenancy/tenant-state-path.ts
19
+ var TENANTS_DIRNAME = "tenants";
20
+ var SAFE_TENANT_ID = /^[A-Za-z0-9_-]+$/;
21
+ function sanitizeTenantId(tenantId) {
22
+ if (SAFE_TENANT_ID.test(tenantId)) return tenantId;
23
+ const sanitized = tenantId.replace(/[^A-Za-z0-9_-]/g, "_") || "unknown";
24
+ const hash = createHash("sha256").update(tenantId).digest("hex").slice(0, 8);
25
+ return `${sanitized}_${hash}`;
26
+ }
27
+ function stateRoot() {
28
+ return process.env["NLM_STATE_ROOT"] || join(homedir(), ".nlm");
29
+ }
30
+ function tenantStatePath(tenantId, ...segments) {
31
+ const base = stateRoot();
32
+ if (tenantId === DEFAULT_TEAM_ID) return join(base, ...segments);
33
+ return join(base, TENANTS_DIRNAME, sanitizeTenantId(tenantId), ...segments);
34
+ }
35
+
36
+ // package.json
37
+ var package_default = {
38
+ name: "nlm-memory",
39
+ version: "0.21.13",
40
+ description: "Local-first non-linear memory operating system for AI operators.",
41
+ type: "module",
42
+ license: "Apache-2.0",
43
+ engines: {
44
+ node: ">=22.0.0"
45
+ },
46
+ repository: {
47
+ type: "git",
48
+ url: "git+https://github.com/pbmagnet4/nlm-memory.git"
49
+ },
50
+ homepage: "https://github.com/pbmagnet4/nlm-memory#readme",
51
+ bugs: {
52
+ url: "https://github.com/pbmagnet4/nlm-memory/issues"
53
+ },
54
+ keywords: [
55
+ "ai",
56
+ "memory",
57
+ "mcp",
58
+ "claude-code",
59
+ "codex",
60
+ "hermes",
61
+ "local-first",
62
+ "recall",
63
+ "session-memory"
64
+ ],
65
+ files: [
66
+ "dist",
67
+ "migrations",
68
+ "fixtures",
69
+ "templates",
70
+ "plugin",
71
+ "plugin-hermes-agent",
72
+ "nlm",
73
+ "assets",
74
+ "LICENSE",
75
+ "README.md"
76
+ ],
77
+ bin: {
78
+ nlm: "dist/cli/nlm.js"
79
+ },
80
+ scripts: {
81
+ dev: "tsx watch src/cli/nlm.ts start",
82
+ start: "node dist/cli/nlm.js start",
83
+ "build:server": "tsc -p tsconfig.json && tsc-alias -p tsconfig.json",
84
+ "build:ui": "vite build --config src/ui/vite.config.ts",
85
+ "build:codex-plugin": "node scripts/build-codex-plugin.mjs",
86
+ "verify:codex-release": "node scripts/verify-codex-release.mjs",
87
+ build: "npm run build:server && npm run build:ui && npm run build:codex-plugin",
88
+ prepare: "[ -d src ] && npm run build || true",
89
+ "ui:dev": "vite --config src/ui/vite.config.ts",
90
+ test: "vitest run",
91
+ "test:watch": "vitest",
92
+ "test:unit": "vitest run tests/unit",
93
+ "test:integration": "vitest run tests/integration",
94
+ "test:pg": "vitest run .pg.test.ts --test-timeout=20000",
95
+ typecheck: "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json && tsc -p tsconfig.scripts.json",
96
+ "bench:longmemeval": "tsx scripts/longmemeval/run-harness.ts",
97
+ "bench:classifier": "tsx scripts/longmemeval/run-harness.ts --classifier",
98
+ "bench:compare": "tsx scripts/longmemeval/compare-classifiers.ts",
99
+ "eval:signals": "tsx scripts/eval/signals-eval.ts",
100
+ "eval:classifier": "tsx scripts/eval/classifier-eval.ts",
101
+ "eval:fact-recall": "tsx scripts/eval/fact-recall-eval.ts",
102
+ "eval:recall-impact-replay": "tsx scripts/eval/recall-impact-replay.ts",
103
+ "eval:code-exemplar": "tsx scripts/eval/code-exemplar-eval.ts",
104
+ "eval:reranker": "tsx scripts/eval/reranker-ablation.ts",
105
+ "eval:floor": "tsx scripts/eval/floor-calibration.ts",
106
+ "eval:matcher": "tsx scripts/eval/tune-matcher.ts",
107
+ "eval:naming": "tsx scripts/eval/tune-naming.ts",
108
+ "eval:rederiv-sample": "tsx scripts/eval/re-derivation-sample.ts",
109
+ "eval:rederiv-label": "tsx scripts/eval/re-derivation-label.ts",
110
+ "eval:rederiv-calibrate": "tsx scripts/eval/re-derivation-calibrate.ts"
111
+ },
112
+ dependencies: {
113
+ "@clack/prompts": "^1.4.0",
114
+ "@hono/node-server": "^2.0.3",
115
+ "@huggingface/transformers": "4.2.0",
116
+ "@modelcontextprotocol/sdk": "^1.29.0",
117
+ "@toon-format/toon": "^2.3.0",
118
+ "better-sqlite3": "^13.0.1",
119
+ commander: "^15.0.0",
120
+ hono: "^4.6.0",
121
+ pg: "^8.21.0",
122
+ pgvector: "^0.3.0",
123
+ "sqlite-vec": "^0.1.6",
124
+ yaml: "^2.9.0",
125
+ zod: "^4.4.3"
126
+ },
127
+ devDependencies: {
128
+ "@types/better-sqlite3": "^7.6.13",
129
+ "@types/node": "^22.10.0",
130
+ "@types/pg": "^8.20.0",
131
+ "@types/react": "^19.2.17",
132
+ "@types/react-dom": "^19.2.3",
133
+ "@vitejs/plugin-react": "^6.0.2",
134
+ esbuild: "^0.28.0",
135
+ react: "^19.2.7",
136
+ "react-dom": "^19.2.7",
137
+ "react-router-dom": "^6.30.3",
138
+ "tsc-alias": "^1.8.17",
139
+ tsx: "^4.19.0",
140
+ typescript: "^6.0.3",
141
+ vite: "^8.0.16",
142
+ vitest: "^4.1.8"
143
+ }
144
+ };
145
+
146
+ // src/shared/version.ts
147
+ var NLM_VERSION = package_default.version;
148
+
149
+ // src/core/hook/hook-log.ts
150
+ function logPath(tenantId) {
151
+ if (tenantId === DEFAULT_TEAM_ID) {
152
+ return process.env["NLM_HOOK_LOG"] ?? tenantStatePath(tenantId, "hook-log.jsonl");
153
+ }
154
+ return tenantStatePath(tenantId, "hook-log.jsonl");
12
155
  }
13
- function appendHookLog(entry) {
156
+ function appendHookLog(tenantId, entry) {
14
157
  try {
15
- const path = logPath();
158
+ const path = logPath(tenantId);
16
159
  mkdirSync(dirname(path), { recursive: true });
17
- appendFileSync(path, `${JSON.stringify(entry)}
160
+ appendFileSync(path, `${JSON.stringify({ ...entry, v: NLM_VERSION })}
18
161
  `, "utf8");
19
162
  } catch {
20
163
  }
@@ -30,18 +173,20 @@ import {
30
173
  statSync,
31
174
  writeFileSync
32
175
  } from "node:fs";
33
- import { homedir as homedir2 } from "node:os";
34
176
  import { join as join2 } from "node:path";
35
- function stateDir() {
36
- return process.env["NLM_HOOK_STATE_DIR"] ?? join2(homedir2(), ".nlm", "hook-state");
177
+ function stateDir(tenantId) {
178
+ if (tenantId === DEFAULT_TEAM_ID) {
179
+ return process.env["NLM_HOOK_STATE_DIR"] ?? tenantStatePath(tenantId, "hook-state");
180
+ }
181
+ return tenantStatePath(tenantId, "hook-state");
37
182
  }
38
- function memoPath(conversationId) {
183
+ function memoPath(tenantId, conversationId) {
39
184
  const safe = conversationId.replace(/[^A-Za-z0-9_-]/g, "_") || "unknown";
40
- return join2(stateDir(), `${safe}.json`);
185
+ return join2(stateDir(tenantId), `${safe}.json`);
41
186
  }
42
- function loadSurfaced(conversationId) {
187
+ function loadSurfaced(tenantId, conversationId) {
43
188
  try {
44
- const path = memoPath(conversationId);
189
+ const path = memoPath(tenantId, conversationId);
45
190
  if (!existsSync(path)) return /* @__PURE__ */ new Set();
46
191
  const parsed = JSON.parse(readFileSync(path, "utf8"));
47
192
  if (!Array.isArray(parsed)) return /* @__PURE__ */ new Set();
@@ -50,12 +195,12 @@ function loadSurfaced(conversationId) {
50
195
  return /* @__PURE__ */ new Set();
51
196
  }
52
197
  }
53
- function recordSurfaced(conversationId, ids) {
198
+ function recordSurfaced(tenantId, conversationId, ids) {
54
199
  try {
55
- const merged = loadSurfaced(conversationId);
200
+ const merged = loadSurfaced(tenantId, conversationId);
56
201
  for (const id of ids) merged.add(id);
57
- mkdirSync2(stateDir(), { recursive: true });
58
- writeFileSync(memoPath(conversationId), JSON.stringify([...merged]), "utf8");
202
+ mkdirSync2(stateDir(tenantId), { recursive: true });
203
+ writeFileSync(memoPath(tenantId, conversationId), JSON.stringify([...merged]), "utf8");
59
204
  } catch {
60
205
  }
61
206
  }
@@ -81,8 +226,8 @@ function truncateSummary(s, max = 200) {
81
226
  }
82
227
  return window + " ...";
83
228
  }
84
- function formatPointerBlock(hits, facts = [], exemplars = []) {
85
- if (hits.length === 0 && facts.length === 0 && exemplars.length === 0) return "";
229
+ function formatPointerBlock(hits, facts = [], exemplars = [], concepts = []) {
230
+ if (hits.length === 0 && facts.length === 0 && exemplars.length === 0 && concepts.length === 0) return "";
86
231
  const out = [];
87
232
  if (hits.length > 0) {
88
233
  out.push("## Possibly-relevant prior sessions (nlm-memory)");
@@ -111,7 +256,19 @@ function formatPointerBlock(hits, facts = [], exemplars = []) {
111
256
  out.push(`- [${e.outcome}] ${langPart}${e.repo} - ${truncateSummary(e.taskContext)}`);
112
257
  }
113
258
  }
114
- const tools = exemplars.length > 0 ? "NLM tools: recall_sessions (search), get_session (full transcript), recall_facts (prior decisions), get_fact_history (how a decision evolved), recall_code (pull the full code for a related exemplar)." : "NLM tools: recall_sessions (search), get_session (full transcript), recall_facts (prior decisions), get_fact_history (how a decision evolved).";
259
+ if (concepts.length > 0) {
260
+ if (out.length > 0) out.push("");
261
+ out.push("## Learning state (nlm-memory)");
262
+ for (const c of concepts) {
263
+ const n = c.attemptCount === 1 ? "1 attempt" : `${c.attemptCount} attempts`;
264
+ out.push(`- [${c.status}] ${c.concept} (${n})`);
265
+ }
266
+ const nextSteps = [...new Set(concepts.map((c) => c.nextStep).filter((s) => !!s))].slice(0, 2);
267
+ for (const next of nextSteps) {
268
+ out.push(`Next: ${truncateSummary(next, 120)}`);
269
+ }
270
+ }
271
+ const tools = exemplars.length > 0 ? "NLM tools: recall_sessions (search), get_session (full transcript), recall_facts (prior decisions), get_fact_history (how a decision evolved), recall_code (pull the full code for a related exemplar), learner_summary (concept mastery + next step)." : "NLM tools: recall_sessions (search), get_session (full transcript), recall_facts (prior decisions), get_fact_history (how a decision evolved), learner_summary (concept mastery + next step).";
115
272
  out.push(tools);
116
273
  return out.join("\n");
117
274
  }
@@ -123,10 +280,10 @@ function medianScore(hits) {
123
280
  return sorted[Math.floor(sorted.length / 2)] ?? 0;
124
281
  }
125
282
  function selectHits(params) {
126
- const { hits, surfaced, scoreThreshold, perFireCap, perConversationCap, relativeFloor = 0 } = params;
127
- const relCut = relativeFloor > 0 ? relativeFloor * medianScore(hits) : 0;
283
+ const { hits, surfaced, scoreThreshold: scoreThreshold2, perFireCap, perConversationCap, relativeFloor: relativeFloor2 = 0 } = params;
284
+ const relCut = relativeFloor2 > 0 ? relativeFloor2 * medianScore(hits) : 0;
128
285
  const eligible = hits.filter(
129
- (h) => h.matchScore >= scoreThreshold && h.matchScore >= relCut && !surfaced.has(h.id)
286
+ (h) => h.matchScore >= scoreThreshold2 && h.matchScore >= relCut && !surfaced.has(h.id)
130
287
  );
131
288
  const budget = Math.max(0, perConversationCap - surfaced.size);
132
289
  const limit = Math.min(perFireCap, budget);
@@ -135,7 +292,7 @@ function selectHits(params) {
135
292
 
136
293
  // src/llm/env-autoload.ts
137
294
  import { readFileSync as readFileSync2, existsSync as existsSync2 } from "node:fs";
138
- import { homedir as homedir3 } from "node:os";
295
+ import { homedir as homedir2 } from "node:os";
139
296
  import { resolve } from "node:path";
140
297
  var DEFAULT_SEARCH_PATHS = [
141
298
  "~/.nlm/.env",
@@ -144,7 +301,7 @@ var DEFAULT_SEARCH_PATHS = [
144
301
  "../../.env"
145
302
  ];
146
303
  function expandHome(p) {
147
- if (p.startsWith("~/")) return resolve(homedir3(), p.slice(2));
304
+ if (p.startsWith("~/")) return resolve(homedir2(), p.slice(2));
148
305
  return p;
149
306
  }
150
307
  function autoloadEnv(extraPaths = []) {
@@ -340,6 +497,18 @@ function extractRecallQuery(prompt) {
340
497
  }
341
498
 
342
499
  // src/hook/hook-helpers.ts
500
+ import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync3, realpathSync } from "node:fs";
501
+ import { pathToFileURL } from "node:url";
502
+ function isMainModule(metaUrl, argv1) {
503
+ if (!argv1) return false;
504
+ let resolved;
505
+ try {
506
+ resolved = realpathSync(argv1);
507
+ } catch {
508
+ return false;
509
+ }
510
+ return metaUrl === pathToFileURL(resolved).href;
511
+ }
343
512
  function readStdin() {
344
513
  return new Promise((resolve2) => {
345
514
  let data = "";
@@ -372,27 +541,36 @@ function parseRecallTimeout(raw) {
372
541
  const n = Number(raw);
373
542
  return Number.isFinite(n) && n > 0 ? n : 4e3;
374
543
  }
375
- var RECALL_TIMEOUT_MS = parseRecallTimeout(process.env["NLM_HOOK_RECALL_TIMEOUT_MS"]);
376
- async function recallOverHttp(prompt, runtime, conversationId, mode = "keyword") {
544
+ function recallTimeoutMs() {
545
+ return parseRecallTimeout(process.env["NLM_HOOK_RECALL_TIMEOUT_MS"]);
546
+ }
547
+ var emptyResult = (outcome) => ({
548
+ hits: [],
549
+ facts: [],
550
+ exemplars: [],
551
+ concepts: [],
552
+ outcome
553
+ });
554
+ async function recallOverHttp(prompt, runtime, conversationId, mode = "keyword", source = "hook") {
377
555
  const query = extractRecallQuery(prompt);
378
- if (query === null) return { hits: [], facts: [], exemplars: [] };
556
+ if (query === null) return emptyResult("skipped");
379
557
  const portValue = process.env["NLM_PORT"] ?? DEFAULT_NLM_PORT;
380
558
  const url = (
381
559
  // 127.0.0.1, not localhost: each hook is a fresh process with no connection
382
560
  // reuse, and Node resolves localhost to IPv6 ::1 first — a measured ~50-300ms
383
561
  // per-fire connect penalty vs ~3ms on the explicit IPv4 loopback.
384
- `http://127.0.0.1:${portValue}/api/recall?q=${encodeURIComponent(query)}&mode=${mode}&limit=${RECALL_LIMIT}&withFacts=true&withExemplars=true` + (conversationId ? `&conversation_id=${encodeURIComponent(conversationId)}` : "")
562
+ `http://127.0.0.1:${portValue}/api/recall?q=${encodeURIComponent(query)}&mode=${mode}&limit=${RECALL_LIMIT}&withFacts=true&withExemplars=true&withConcepts=true` + (conversationId ? `&conversation_id=${encodeURIComponent(conversationId)}` : "")
385
563
  );
386
564
  try {
387
- const extra = { "x-recall-source": "hook" };
565
+ const extra = { "x-recall-source": source };
388
566
  if (runtime) extra["x-recall-runtime"] = runtime;
389
- const res = await fetchWithTimeout(url, { headers: hookAuthHeaders(extra) }, RECALL_TIMEOUT_MS);
390
- if (!res.ok) return { hits: [], facts: [], exemplars: [] };
567
+ const res = await fetchWithTimeout(url, { headers: hookAuthHeaders(extra) }, recallTimeoutMs());
568
+ if (!res.ok) return emptyResult("http-error");
391
569
  let body;
392
570
  try {
393
571
  body = await res.json();
394
572
  } catch {
395
- return { hits: [], facts: [], exemplars: [] };
573
+ return emptyResult("http-error");
396
574
  }
397
575
  const hits = (body.results ?? []).map((r) => ({
398
576
  id: r.id,
@@ -413,37 +591,47 @@ async function recallOverHttp(prompt, runtime, conversationId, mode = "keyword")
413
591
  repo: e.repo,
414
592
  taskContext: e.taskContext
415
593
  }));
416
- return { hits, facts, exemplars };
417
- } catch {
418
- return { hits: [], facts: [], exemplars: [] };
594
+ const concepts = (body.relatedConcepts ?? []).map((c) => ({
595
+ concept: c.concept,
596
+ status: c.status,
597
+ attemptCount: c.attemptCount,
598
+ nextStep: c.nextStep
599
+ }));
600
+ return { hits, facts, exemplars, concepts, outcome: "ok" };
601
+ } catch (err) {
602
+ const aborted = err instanceof Error && err.name === "AbortError";
603
+ return emptyResult(aborted ? "timeout" : "unreachable");
419
604
  }
420
605
  }
421
606
 
422
607
  // src/hook/session-start-hook.ts
423
- var SCORE_THRESHOLD = parseScoreFloor(process.env["NLM_RECALL_SCORE_FLOOR"]);
424
- var RELATIVE_FLOOR = parseRelativeFloor(process.env["NLM_RECALL_REL_FLOOR"], 0.9);
608
+ var scoreThreshold = () => parseScoreFloor(process.env["NLM_RECALL_SCORE_FLOOR"]);
609
+ var relativeFloor = () => parseRelativeFloor(process.env["NLM_RECALL_REL_FLOOR"], 0.9);
425
610
  var PER_FIRE_CAP = 3;
426
611
  var PER_CONVERSATION_CAP = 10;
427
- var RECALL_TIMEOUT_MS2 = 2e3;
612
+ var RECALL_TIMEOUT_MS = 2e3;
428
613
  async function runHook(input, deps) {
429
614
  let hits = [];
615
+ let recallOutcome = "unreachable";
430
616
  try {
431
- hits = await deps.recall(input.query, input.conversationId);
617
+ const fetched = await deps.recall(input.query, input.conversationId);
618
+ hits = fetched.hits;
619
+ recallOutcome = fetched.outcome;
432
620
  } catch {
433
621
  hits = [];
434
622
  }
435
- const surfaced = loadSurfaced(input.conversationId);
623
+ const surfaced = loadSurfaced(DEFAULT_TEAM_ID, input.conversationId);
436
624
  const selected = selectHits({
437
625
  hits,
438
626
  surfaced,
439
- scoreThreshold: SCORE_THRESHOLD,
440
- relativeFloor: RELATIVE_FLOOR,
627
+ scoreThreshold: scoreThreshold(),
628
+ relativeFloor: relativeFloor(),
441
629
  perFireCap: PER_FIRE_CAP,
442
630
  perConversationCap: PER_CONVERSATION_CAP
443
631
  });
444
632
  const block = formatPointerBlock(selected);
445
633
  const estTokens = Math.ceil(block.length / 4);
446
- appendHookLog({
634
+ appendHookLog(DEFAULT_TEAM_ID, {
447
635
  ts: (/* @__PURE__ */ new Date()).toISOString(),
448
636
  conversationId: input.conversationId,
449
637
  promptPreview: input.query,
@@ -451,10 +639,11 @@ async function runHook(input, deps) {
451
639
  hits: hits.map((h) => ({ id: h.id, score: h.matchScore })),
452
640
  wouldInject: selected.map((h) => h.id),
453
641
  estTokens,
454
- mode: deps.mode
642
+ mode: deps.mode,
643
+ recallOutcome
455
644
  });
456
645
  if (deps.mode === "live" && selected.length > 0) {
457
- recordSurfaced(input.conversationId, selected.map((h) => h.id));
646
+ recordSurfaced(DEFAULT_TEAM_ID, input.conversationId, selected.map((h) => h.id));
458
647
  return block;
459
648
  }
460
649
  return "";
@@ -469,7 +658,7 @@ async function fetchFailureModeBlock(repo) {
469
658
  try {
470
659
  const res = await fetchWithTimeout(url, {
471
660
  headers: hookAuthHeaders({ "x-recall-source": "session-start-hook" })
472
- }, RECALL_TIMEOUT_MS2);
661
+ }, RECALL_TIMEOUT_MS);
473
662
  if (!res.ok) return "";
474
663
  const body = await res.json();
475
664
  return typeof body.block === "string" ? body.block : "";
@@ -477,9 +666,29 @@ async function fetchFailureModeBlock(repo) {
477
666
  return "";
478
667
  }
479
668
  }
480
- function buildQuery(workingDirectory, projectName) {
669
+ var GIT_TIMEOUT_MS = 300;
670
+ var RECENT_COMMITS = 3;
671
+ function git(cwd, args) {
672
+ try {
673
+ return execFileSync("git", ["-C", cwd, ...args], {
674
+ encoding: "utf8",
675
+ timeout: GIT_TIMEOUT_MS,
676
+ stdio: ["ignore", "pipe", "ignore"]
677
+ }).trim();
678
+ } catch {
679
+ return "";
680
+ }
681
+ }
682
+ function readGitContext(workingDirectory) {
683
+ if (!workingDirectory) return "";
684
+ const branch = git(workingDirectory, ["rev-parse", "--abbrev-ref", "HEAD"]);
685
+ const subjects = git(workingDirectory, ["log", `-${RECENT_COMMITS}`, "--format=%s"]);
686
+ const branchWords = branch === "HEAD" ? "" : branch.replace(/[/_-]+/g, " ");
687
+ return [branchWords, subjects.replace(/\n/g, " ")].filter(Boolean).join(" ");
688
+ }
689
+ function buildQuery(workingDirectory, projectName, gitContext) {
481
690
  const dirTail = workingDirectory.split("/").filter(Boolean).at(-1) ?? "";
482
- const parts = [dirTail, projectName].filter(Boolean);
691
+ const parts = [dirTail, projectName, gitContext].filter(Boolean);
483
692
  return parts.join(" ").trim() || "session start";
484
693
  }
485
694
  async function main() {
@@ -490,14 +699,23 @@ async function main() {
490
699
  const conversationId = typeof payload.session_id === "string" ? payload.session_id : "unknown";
491
700
  const workingDirectory = typeof payload.cwd === "string" ? payload.cwd : typeof payload.working_directory === "string" ? payload.working_directory : "";
492
701
  const projectName = typeof payload.project_name === "string" ? payload.project_name : "";
493
- const query = buildQuery(workingDirectory, projectName);
702
+ const query = buildQuery(workingDirectory, projectName, readGitContext(workingDirectory));
494
703
  const mode = hookModeFromEnv();
495
704
  const [out, failureModes] = await Promise.all([
496
705
  runHook(
497
706
  { conversationId, query },
498
707
  {
499
708
  mode,
500
- recall: async (q, cid) => (await recallOverHttp(q, "claude-code", cid === "unknown" ? void 0 : cid, "hybrid")).hits
709
+ recall: async (q, cid) => {
710
+ const r = await recallOverHttp(
711
+ q,
712
+ "claude-code",
713
+ cid === "unknown" ? void 0 : cid,
714
+ "hybrid",
715
+ "session-start-hook"
716
+ );
717
+ return { hits: r.hits, outcome: r.outcome };
718
+ }
501
719
  }
502
720
  ),
503
721
  mode === "live" ? fetchFailureModeBlock(workingDirectory) : Promise.resolve("")
@@ -507,10 +725,12 @@ async function main() {
507
725
  } catch {
508
726
  }
509
727
  }
510
- if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
728
+ if (isMainModule(import.meta.url, process.argv[1])) {
511
729
  void main();
512
730
  }
513
731
  export {
732
+ buildQuery,
514
733
  composeSessionStartOutput,
734
+ readGitContext,
515
735
  runHook
516
736
  };