nlm-memory 0.20.0 → 0.21.0

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 (471) hide show
  1. package/README.md +19 -10
  2. package/dist/cli/digest.js +60 -1
  3. package/dist/cli/digest.js.map +1 -1
  4. package/dist/cli/init.d.ts +12 -0
  5. package/dist/cli/init.js +49 -0
  6. package/dist/cli/init.js.map +1 -0
  7. package/dist/cli/nlm.d.ts +13 -1
  8. package/dist/cli/nlm.js +872 -61
  9. package/dist/cli/nlm.js.map +1 -1
  10. package/dist/cli/scope-backfill.d.ts +34 -0
  11. package/dist/cli/scope-backfill.js +237 -0
  12. package/dist/cli/scope-backfill.js.map +1 -0
  13. package/dist/cli/scope-coverage.d.ts +44 -0
  14. package/dist/cli/scope-coverage.js +205 -0
  15. package/dist/cli/scope-coverage.js.map +1 -0
  16. package/dist/core/actions/overlay.d.ts +20 -6
  17. package/dist/core/actions/overlay.js +32 -18
  18. package/dist/core/actions/overlay.js.map +1 -1
  19. package/dist/core/adapters/claude-code.d.ts +14 -0
  20. package/dist/core/adapters/claude-code.js +36 -0
  21. package/dist/core/adapters/claude-code.js.map +1 -1
  22. package/dist/core/classifier/prompt.js +3 -3
  23. package/dist/core/dataset/build-dataset.js +1 -0
  24. package/dist/core/dataset/build-dataset.js.map +1 -1
  25. package/dist/core/digest/compose.d.ts +13 -3
  26. package/dist/core/digest/compose.js +23 -18
  27. package/dist/core/digest/compose.js.map +1 -1
  28. package/dist/core/digest/hook-injection.d.ts +43 -0
  29. package/dist/core/digest/hook-injection.js +79 -0
  30. package/dist/core/digest/hook-injection.js.map +1 -0
  31. package/dist/core/embedding/embed-backfill.d.ts +13 -2
  32. package/dist/core/embedding/embed-backfill.js +181 -43
  33. package/dist/core/embedding/embed-backfill.js.map +1 -1
  34. package/dist/core/embedding/embedding-config.d.ts +17 -0
  35. package/dist/core/embedding/embedding-config.js +12 -0
  36. package/dist/core/embedding/embedding-config.js.map +1 -0
  37. package/dist/core/embedding/pg-embed-backfill.d.ts +31 -0
  38. package/dist/core/embedding/pg-embed-backfill.js +264 -0
  39. package/dist/core/embedding/pg-embed-backfill.js.map +1 -0
  40. package/dist/core/entities/dedup-suggest.d.ts +25 -0
  41. package/dist/core/entities/dedup-suggest.js +107 -0
  42. package/dist/core/entities/dedup-suggest.js.map +1 -0
  43. package/dist/core/eval/classifier-fixture-eval.d.ts +29 -0
  44. package/dist/core/eval/classifier-fixture-eval.js +217 -0
  45. package/dist/core/eval/classifier-fixture-eval.js.map +1 -0
  46. package/dist/core/eval/extraction-scoring.d.ts +63 -0
  47. package/dist/core/eval/extraction-scoring.js +79 -0
  48. package/dist/core/eval/extraction-scoring.js.map +1 -0
  49. package/dist/core/eval/run-eval.d.ts +40 -0
  50. package/dist/core/eval/run-eval.js +34 -0
  51. package/dist/core/eval/run-eval.js.map +1 -0
  52. package/dist/core/exemplars/capture-from-session.d.ts +2 -0
  53. package/dist/core/exemplars/capture-from-session.js +7 -3
  54. package/dist/core/exemplars/capture-from-session.js.map +1 -1
  55. package/dist/core/exemplars/diff-parse.d.ts +23 -0
  56. package/dist/core/exemplars/diff-parse.js +73 -0
  57. package/dist/core/exemplars/diff-parse.js.map +1 -0
  58. package/dist/core/exemplars/embed-backfill.d.ts +36 -0
  59. package/dist/core/exemplars/embed-backfill.js +85 -0
  60. package/dist/core/exemplars/embed-backfill.js.map +1 -0
  61. package/dist/core/exemplars/embed-text.d.ts +15 -0
  62. package/dist/core/exemplars/embed-text.js +18 -0
  63. package/dist/core/exemplars/embed-text.js.map +1 -0
  64. package/dist/core/exemplars/extract-exemplar.d.ts +2 -0
  65. package/dist/core/exemplars/extract-exemplar.js +9 -66
  66. package/dist/core/exemplars/extract-exemplar.js.map +1 -1
  67. package/dist/core/exemplars/ingest-exemplar.d.ts +1 -0
  68. package/dist/core/exemplars/ingest-exemplar.js +1 -0
  69. package/dist/core/exemplars/ingest-exemplar.js.map +1 -1
  70. package/dist/core/exemplars/recall-code.js +4 -0
  71. package/dist/core/exemplars/recall-code.js.map +1 -1
  72. package/dist/core/exemplars/warm-embedder.d.ts +14 -0
  73. package/dist/core/exemplars/warm-embedder.js +18 -0
  74. package/dist/core/exemplars/warm-embedder.js.map +1 -0
  75. package/dist/core/health/corpus-state.d.ts +8 -0
  76. package/dist/core/health/corpus-state.js +11 -0
  77. package/dist/core/health/corpus-state.js.map +1 -0
  78. package/dist/core/health/embed-inflight.d.ts +9 -0
  79. package/dist/core/health/embed-inflight.js +30 -0
  80. package/dist/core/health/embed-inflight.js.map +1 -0
  81. package/dist/core/health/embedding-lane-state.d.ts +6 -0
  82. package/dist/core/health/embedding-lane-state.js +18 -0
  83. package/dist/core/health/embedding-lane-state.js.map +1 -0
  84. package/dist/core/health/warmup-state.d.ts +12 -0
  85. package/dist/core/health/warmup-state.js +12 -0
  86. package/dist/core/health/warmup-state.js.map +1 -0
  87. package/dist/core/hook/claude-settings.d.ts +1 -1
  88. package/dist/core/hook/claude-settings.js +0 -1
  89. package/dist/core/hook/claude-settings.js.map +1 -1
  90. package/dist/core/hook/gate.d.ts +13 -6
  91. package/dist/core/hook/gate.js +47 -6
  92. package/dist/core/hook/gate.js.map +1 -1
  93. package/dist/core/hook/hook-log.d.ts +5 -0
  94. package/dist/core/hook/hook-log.js.map +1 -1
  95. package/dist/core/hook/memo.d.ts +12 -0
  96. package/dist/core/hook/memo.js +41 -1
  97. package/dist/core/hook/memo.js.map +1 -1
  98. package/dist/core/hook/pointer-block.d.ts +1 -0
  99. package/dist/core/hook/pointer-block.js +23 -2
  100. package/dist/core/hook/pointer-block.js.map +1 -1
  101. package/dist/core/hook/query-extract.d.ts +2 -1
  102. package/dist/core/hook/query-extract.js +10 -1
  103. package/dist/core/hook/query-extract.js.map +1 -1
  104. package/dist/core/hook/resolve-conversation-by-query.d.ts +28 -0
  105. package/dist/core/hook/resolve-conversation-by-query.js +98 -0
  106. package/dist/core/hook/resolve-conversation-by-query.js.map +1 -0
  107. package/dist/core/hook/select.d.ts +8 -0
  108. package/dist/core/hook/select.js +9 -2
  109. package/dist/core/hook/select.js.map +1 -1
  110. package/dist/core/hook/transcript.js +16 -2
  111. package/dist/core/hook/transcript.js.map +1 -1
  112. package/dist/core/ingest/backfill-derivables.d.ts +92 -0
  113. package/dist/core/ingest/backfill-derivables.js +175 -0
  114. package/dist/core/ingest/backfill-derivables.js.map +1 -0
  115. package/dist/core/ingest/ingest-session.d.ts +5 -0
  116. package/dist/core/ingest/ingest-session.js +23 -0
  117. package/dist/core/ingest/ingest-session.js.map +1 -1
  118. package/dist/core/ingest/reclassify-oversized.d.ts +5 -0
  119. package/dist/core/ingest/reclassify-oversized.js +9 -0
  120. package/dist/core/ingest/reclassify-oversized.js.map +1 -1
  121. package/dist/core/ingest/reprocess.d.ts +96 -0
  122. package/dist/core/ingest/reprocess.js +280 -0
  123. package/dist/core/ingest/reprocess.js.map +1 -0
  124. package/dist/core/ingest/transcript-derivables.d.ts +27 -0
  125. package/dist/core/ingest/transcript-derivables.js +138 -0
  126. package/dist/core/ingest/transcript-derivables.js.map +1 -0
  127. package/dist/core/integrity/check-invariants.d.ts +6 -1
  128. package/dist/core/integrity/check-invariants.js +209 -3
  129. package/dist/core/integrity/check-invariants.js.map +1 -1
  130. package/dist/core/metrics/corpus-stats.d.ts +49 -0
  131. package/dist/core/metrics/corpus-stats.js +111 -0
  132. package/dist/core/metrics/corpus-stats.js.map +1 -0
  133. package/dist/core/metrics/re-derivation.d.ts +48 -0
  134. package/dist/core/metrics/re-derivation.js +87 -0
  135. package/dist/core/metrics/re-derivation.js.map +1 -0
  136. package/dist/core/outcome/coverage.d.ts +33 -0
  137. package/dist/core/outcome/coverage.js +46 -0
  138. package/dist/core/outcome/coverage.js.map +1 -0
  139. package/dist/core/outcome/rollup.d.ts +33 -0
  140. package/dist/core/outcome/rollup.js +113 -0
  141. package/dist/core/outcome/rollup.js.map +1 -0
  142. package/dist/core/recall/citation-log.d.ts +8 -0
  143. package/dist/core/recall/citation-log.js +17 -0
  144. package/dist/core/recall/citation-log.js.map +1 -1
  145. package/dist/core/recall/hook-recall-log.d.ts +2 -2
  146. package/dist/core/recall/hook-recall-log.js +2 -2
  147. package/dist/core/recall/query-intent.d.ts +7 -0
  148. package/dist/core/recall/query-intent.js +25 -0
  149. package/dist/core/recall/query-intent.js.map +1 -0
  150. package/dist/core/recall/query-log.d.ts +4 -0
  151. package/dist/core/recall/query-log.js +4 -0
  152. package/dist/core/recall/query-log.js.map +1 -1
  153. package/dist/core/recall/recall-service.d.ts +37 -1
  154. package/dist/core/recall/recall-service.js +106 -63
  155. package/dist/core/recall/recall-service.js.map +1 -1
  156. package/dist/core/recall/related-exemplars.d.ts +1 -0
  157. package/dist/core/recall/related-exemplars.js +4 -1
  158. package/dist/core/recall/related-exemplars.js.map +1 -1
  159. package/dist/core/recall/related-facts.js +2 -2
  160. package/dist/core/recall/related-facts.js.map +1 -1
  161. package/dist/core/recall/reranker.d.ts +2 -1
  162. package/dist/core/recall/reranker.js +3 -3
  163. package/dist/core/recall/reranker.js.map +1 -1
  164. package/dist/core/recall-facts/fact-query-log.d.ts +7 -0
  165. package/dist/core/recall-facts/fact-query-log.js +2 -0
  166. package/dist/core/recall-facts/fact-query-log.js.map +1 -1
  167. package/dist/core/recall-facts/fact-recall-service.d.ts +9 -1
  168. package/dist/core/recall-facts/fact-recall-service.js +22 -8
  169. package/dist/core/recall-facts/fact-recall-service.js.map +1 -1
  170. package/dist/core/scheduler/scan-once.d.ts +6 -6
  171. package/dist/core/scheduler/scan-once.js +15 -49
  172. package/dist/core/scheduler/scan-once.js.map +1 -1
  173. package/dist/core/scheduler/scheduler.d.ts +10 -0
  174. package/dist/core/scheduler/scheduler.js +109 -13
  175. package/dist/core/scheduler/scheduler.js.map +1 -1
  176. package/dist/core/scope/alias-map.d.ts +10 -0
  177. package/dist/core/scope/alias-map.js +41 -0
  178. package/dist/core/scope/alias-map.js.map +1 -0
  179. package/dist/core/scope/derive-scope.d.ts +8 -0
  180. package/dist/core/scope/derive-scope.js +54 -0
  181. package/dist/core/scope/derive-scope.js.map +1 -0
  182. package/dist/core/scope/scope-clause.d.ts +16 -0
  183. package/dist/core/scope/scope-clause.js +21 -0
  184. package/dist/core/scope/scope-clause.js.map +1 -0
  185. package/dist/core/scope/stamp-flag.d.ts +1 -0
  186. package/dist/core/scope/stamp-flag.js +4 -0
  187. package/dist/core/scope/stamp-flag.js.map +1 -0
  188. package/dist/core/signals/code-signal.d.ts +50 -0
  189. package/dist/core/signals/code-signal.js +54 -0
  190. package/dist/core/signals/code-signal.js.map +1 -0
  191. package/dist/core/signals/ingest-signal.d.ts +1 -1
  192. package/dist/core/signals/ingest-signal.js +3 -1
  193. package/dist/core/signals/ingest-signal.js.map +1 -1
  194. package/dist/core/signals/stamp-scope.d.ts +18 -0
  195. package/dist/core/signals/stamp-scope.js +28 -0
  196. package/dist/core/signals/stamp-scope.js.map +1 -0
  197. package/dist/core/storage/db-restore.js +3 -1
  198. package/dist/core/storage/db-restore.js.map +1 -1
  199. package/dist/core/storage/fact-batch.d.ts +9 -0
  200. package/dist/core/storage/fact-batch.js +14 -0
  201. package/dist/core/storage/fact-batch.js.map +1 -0
  202. package/dist/core/storage/pg-code-exemplar-store.d.ts +1 -0
  203. package/dist/core/storage/pg-code-exemplar-store.js +13 -2
  204. package/dist/core/storage/pg-code-exemplar-store.js.map +1 -1
  205. package/dist/core/storage/pg-embedding-config.d.ts +29 -0
  206. package/dist/core/storage/pg-embedding-config.js +53 -0
  207. package/dist/core/storage/pg-embedding-config.js.map +1 -0
  208. package/dist/core/storage/pg-entity-store.d.ts +12 -0
  209. package/dist/core/storage/pg-entity-store.js +79 -0
  210. package/dist/core/storage/pg-entity-store.js.map +1 -0
  211. package/dist/core/storage/pg-fact-ingest.d.ts +15 -0
  212. package/dist/core/storage/pg-fact-ingest.js +34 -0
  213. package/dist/core/storage/pg-fact-ingest.js.map +1 -0
  214. package/dist/core/storage/pg-fact-store.d.ts +3 -0
  215. package/dist/core/storage/pg-fact-store.js +26 -30
  216. package/dist/core/storage/pg-fact-store.js.map +1 -1
  217. package/dist/core/storage/pg-migrate.d.ts +18 -0
  218. package/dist/core/storage/pg-migrate.js +73 -0
  219. package/dist/core/storage/pg-migrate.js.map +1 -0
  220. package/dist/core/storage/pg-session-store.d.ts +11 -2
  221. package/dist/core/storage/pg-session-store.js +224 -96
  222. package/dist/core/storage/pg-session-store.js.map +1 -1
  223. package/dist/core/storage/pg-signal-store.js +4 -3
  224. package/dist/core/storage/pg-signal-store.js.map +1 -1
  225. package/dist/core/storage/pg-storage.d.ts +9 -7
  226. package/dist/core/storage/pg-storage.js +20 -50
  227. package/dist/core/storage/pg-storage.js.map +1 -1
  228. package/dist/core/storage/pg-workstream-store.d.ts +25 -0
  229. package/dist/core/storage/pg-workstream-store.js +97 -0
  230. package/dist/core/storage/pg-workstream-store.js.map +1 -0
  231. package/dist/core/storage/sqlite-code-exemplar-store.d.ts +1 -0
  232. package/dist/core/storage/sqlite-code-exemplar-store.js +15 -2
  233. package/dist/core/storage/sqlite-code-exemplar-store.js.map +1 -1
  234. package/dist/core/storage/sqlite-embedding-config.d.ts +10 -0
  235. package/dist/core/storage/sqlite-embedding-config.js +27 -0
  236. package/dist/core/storage/sqlite-embedding-config.js.map +1 -0
  237. package/dist/core/storage/sqlite-entity-store.d.ts +13 -0
  238. package/dist/core/storage/sqlite-entity-store.js +96 -0
  239. package/dist/core/storage/sqlite-entity-store.js.map +1 -0
  240. package/dist/core/storage/sqlite-fact-store.d.ts +15 -7
  241. package/dist/core/storage/sqlite-fact-store.js +81 -27
  242. package/dist/core/storage/sqlite-fact-store.js.map +1 -1
  243. package/dist/core/storage/sqlite-outcome-store.d.ts +89 -0
  244. package/dist/core/storage/sqlite-outcome-store.js +158 -0
  245. package/dist/core/storage/sqlite-outcome-store.js.map +1 -0
  246. package/dist/core/storage/sqlite-session-store.d.ts +42 -7
  247. package/dist/core/storage/sqlite-session-store.js +208 -95
  248. package/dist/core/storage/sqlite-session-store.js.map +1 -1
  249. package/dist/core/storage/sqlite-signal-store.js +4 -2
  250. package/dist/core/storage/sqlite-signal-store.js.map +1 -1
  251. package/dist/core/storage/sqlite-storage.d.ts +8 -8
  252. package/dist/core/storage/sqlite-storage.js +21 -32
  253. package/dist/core/storage/sqlite-storage.js.map +1 -1
  254. package/dist/core/storage/sqlite-workstream-store.d.ts +25 -0
  255. package/dist/core/storage/sqlite-workstream-store.js +99 -0
  256. package/dist/core/storage/sqlite-workstream-store.js.map +1 -0
  257. package/dist/core/storage/supersedence-log.js +2 -0
  258. package/dist/core/storage/supersedence-log.js.map +1 -1
  259. package/dist/core/telemetry/probe-filter.d.ts +35 -0
  260. package/dist/core/telemetry/probe-filter.js +56 -0
  261. package/dist/core/telemetry/probe-filter.js.map +1 -0
  262. package/dist/core/update-check/check.d.ts +6 -0
  263. package/dist/core/update-check/check.js +35 -0
  264. package/dist/core/update-check/check.js.map +1 -1
  265. package/dist/core/work-digest/active-spans.d.ts +8 -0
  266. package/dist/core/work-digest/active-spans.js +29 -0
  267. package/dist/core/work-digest/active-spans.js.map +1 -0
  268. package/dist/core/work-digest/attribute.d.ts +15 -0
  269. package/dist/core/work-digest/attribute.js +76 -0
  270. package/dist/core/work-digest/attribute.js.map +1 -0
  271. package/dist/core/work-digest/build-work-digest.d.ts +12 -0
  272. package/dist/core/work-digest/build-work-digest.js +69 -0
  273. package/dist/core/work-digest/build-work-digest.js.map +1 -0
  274. package/dist/core/work-digest/compose-work-digest.d.ts +3 -0
  275. package/dist/core/work-digest/compose-work-digest.js +52 -0
  276. package/dist/core/work-digest/compose-work-digest.js.map +1 -0
  277. package/dist/core/work-digest/merge-active.d.ts +10 -0
  278. package/dist/core/work-digest/merge-active.js +22 -0
  279. package/dist/core/work-digest/merge-active.js.map +1 -0
  280. package/dist/core/work-digest/read-transcript-timestamps.d.ts +7 -0
  281. package/dist/core/work-digest/read-transcript-timestamps.js +40 -0
  282. package/dist/core/work-digest/read-transcript-timestamps.js.map +1 -0
  283. package/dist/core/work-digest/topics.d.ts +18 -0
  284. package/dist/core/work-digest/topics.js +26 -0
  285. package/dist/core/work-digest/topics.js.map +1 -0
  286. package/dist/core/work-digest/types.d.ts +45 -0
  287. package/dist/core/work-digest/types.js +2 -0
  288. package/dist/core/work-digest/types.js.map +1 -0
  289. package/dist/core/workstream/bind.d.ts +26 -0
  290. package/dist/core/workstream/bind.js +42 -0
  291. package/dist/core/workstream/bind.js.map +1 -0
  292. package/dist/core/workstream/compose-recall.d.ts +2 -0
  293. package/dist/core/workstream/compose-recall.js +39 -0
  294. package/dist/core/workstream/compose-recall.js.map +1 -0
  295. package/dist/core/workstream/merge-suggest.d.ts +19 -0
  296. package/dist/core/workstream/merge-suggest.js +61 -0
  297. package/dist/core/workstream/merge-suggest.js.map +1 -0
  298. package/dist/core/workstream/model.d.ts +21 -0
  299. package/dist/core/workstream/model.js +9 -0
  300. package/dist/core/workstream/model.js.map +1 -0
  301. package/dist/core/workstream/name-match.d.ts +8 -0
  302. package/dist/core/workstream/name-match.js +18 -0
  303. package/dist/core/workstream/name-match.js.map +1 -0
  304. package/dist/core/workstream/resolve.d.ts +10 -0
  305. package/dist/core/workstream/resolve.js +21 -0
  306. package/dist/core/workstream/resolve.js.map +1 -0
  307. package/dist/core/workstream/rollup.d.ts +12 -0
  308. package/dist/core/workstream/rollup.js +17 -0
  309. package/dist/core/workstream/rollup.js.map +1 -0
  310. package/dist/core/workstream/work-topics.d.ts +10 -0
  311. package/dist/core/workstream/work-topics.js +55 -0
  312. package/dist/core/workstream/work-topics.js.map +1 -0
  313. package/dist/hook/hook-helpers.d.ts +4 -0
  314. package/dist/hook/hook-helpers.js +36 -0
  315. package/dist/hook/hook-helpers.js.map +1 -0
  316. package/dist/hook/pre-compact-hook.d.ts +23 -0
  317. package/dist/hook/pre-compact-hook.js +67 -0
  318. package/dist/hook/pre-compact-hook.js.map +1 -0
  319. package/dist/hook/prompt-recall-hook.d.ts +38 -0
  320. package/dist/hook/prompt-recall-hook.js +124 -20
  321. package/dist/hook/prompt-recall-hook.js.map +1 -1
  322. package/dist/hook/recall-gate.d.ts +29 -0
  323. package/dist/hook/recall-gate.js +50 -0
  324. package/dist/hook/recall-gate.js.map +1 -0
  325. package/dist/hook/recall-over-http.d.ts +3 -2
  326. package/dist/hook/recall-over-http.js +26 -13
  327. package/dist/hook/recall-over-http.js.map +1 -1
  328. package/dist/hook/recent-context.d.ts +25 -0
  329. package/dist/hook/recent-context.js +104 -0
  330. package/dist/hook/recent-context.js.map +1 -0
  331. package/dist/hook/score-floor.d.ts +27 -0
  332. package/dist/hook/score-floor.js +42 -0
  333. package/dist/hook/score-floor.js.map +1 -0
  334. package/dist/hook/session-end-hook.js +8 -29
  335. package/dist/hook/session-end-hook.js.map +1 -1
  336. package/dist/hook/session-start-hook.js +26 -60
  337. package/dist/hook/session-start-hook.js.map +1 -1
  338. package/dist/hook/stop-hook.js +24 -60
  339. package/dist/hook/stop-hook.js.map +1 -1
  340. package/dist/http/app.d.ts +6 -0
  341. package/dist/http/app.js +52 -44
  342. package/dist/http/app.js.map +1 -1
  343. package/dist/install/setup.js +2 -0
  344. package/dist/install/setup.js.map +1 -1
  345. package/dist/llm/build-classifier.d.ts +22 -0
  346. package/dist/llm/build-classifier.js +42 -0
  347. package/dist/llm/build-classifier.js.map +1 -0
  348. package/dist/llm/build-embedder.d.ts +11 -0
  349. package/dist/llm/build-embedder.js +42 -0
  350. package/dist/llm/build-embedder.js.map +1 -0
  351. package/dist/llm/bundled-embedder-client.d.ts +37 -0
  352. package/dist/llm/bundled-embedder-client.js +90 -0
  353. package/dist/llm/bundled-embedder-client.js.map +1 -0
  354. package/dist/llm/classifier-box.d.ts +13 -5
  355. package/dist/llm/classifier-box.js +28 -6
  356. package/dist/llm/classifier-box.js.map +1 -1
  357. package/dist/llm/classifier-egress.d.ts +18 -0
  358. package/dist/llm/classifier-egress.js +59 -0
  359. package/dist/llm/classifier-egress.js.map +1 -0
  360. package/dist/llm/client-shared.d.ts +4 -0
  361. package/dist/llm/client-shared.js +39 -0
  362. package/dist/llm/client-shared.js.map +1 -0
  363. package/dist/llm/deepseek-client.d.ts +20 -0
  364. package/dist/llm/deepseek-client.js +59 -45
  365. package/dist/llm/deepseek-client.js.map +1 -1
  366. package/dist/llm/embedder-info.d.ts +15 -0
  367. package/dist/llm/embedder-info.js +27 -0
  368. package/dist/llm/embedder-info.js.map +1 -0
  369. package/dist/llm/model-quirks.d.ts +4 -0
  370. package/dist/llm/model-quirks.js +7 -0
  371. package/dist/llm/model-quirks.js.map +1 -0
  372. package/dist/llm/naming.d.ts +5 -0
  373. package/dist/llm/naming.js +20 -0
  374. package/dist/llm/naming.js.map +1 -0
  375. package/dist/llm/ollama-client.d.ts +7 -8
  376. package/dist/llm/ollama-client.js +59 -51
  377. package/dist/llm/ollama-client.js.map +1 -1
  378. package/dist/llm/ollama-code-embedder.d.ts +8 -3
  379. package/dist/llm/ollama-code-embedder.js +14 -24
  380. package/dist/llm/ollama-code-embedder.js.map +1 -1
  381. package/dist/llm/openai-code-embedder-client.d.ts +25 -0
  382. package/dist/llm/openai-code-embedder-client.js +52 -0
  383. package/dist/llm/openai-code-embedder-client.js.map +1 -0
  384. package/dist/llm/openai-embedder-client.d.ts +41 -0
  385. package/dist/llm/openai-embedder-client.js +83 -0
  386. package/dist/llm/openai-embedder-client.js.map +1 -0
  387. package/dist/mcp/server.d.ts +69 -2
  388. package/dist/mcp/server.js +404 -19
  389. package/dist/mcp/server.js.map +1 -1
  390. package/dist/ports/code-embedder.d.ts +6 -1
  391. package/dist/ports/code-exemplar-store.d.ts +5 -0
  392. package/dist/ports/entity-store.d.ts +35 -0
  393. package/dist/ports/entity-store.js +7 -0
  394. package/dist/ports/entity-store.js.map +1 -0
  395. package/dist/ports/fact-store.d.ts +0 -0
  396. package/dist/ports/fact-store.js.map +1 -1
  397. package/dist/ports/llm-client.d.ts +9 -1
  398. package/dist/ports/outcome.d.ts +85 -0
  399. package/dist/ports/outcome.js +11 -0
  400. package/dist/ports/outcome.js.map +1 -0
  401. package/dist/ports/session-store.d.ts +12 -6
  402. package/dist/ports/storage.d.ts +7 -30
  403. package/dist/ports/storage.js +3 -7
  404. package/dist/ports/storage.js.map +1 -1
  405. package/dist/ports/transcript-adapter.d.ts +2 -0
  406. package/dist/ports/workstream-store.d.ts +22 -0
  407. package/dist/ports/workstream-store.js +2 -0
  408. package/dist/ports/workstream-store.js.map +1 -0
  409. package/dist/shared/net.d.ts +3 -0
  410. package/dist/shared/net.js +4 -0
  411. package/dist/shared/net.js.map +1 -0
  412. package/dist/shared/types.d.ts +56 -2
  413. package/dist/shared/types.js +4 -1
  414. package/dist/shared/types.js.map +1 -1
  415. package/dist/ui/assets/{index-CMpQkbQy.js → index-CSaBtgXD.js} +1 -1
  416. package/dist/ui/index.html +1 -1
  417. package/fixtures/classifier-gold/README.md +94 -0
  418. package/fixtures/classifier-gold/reference.json +318 -0
  419. package/fixtures/classifier-gold/transcripts/01-bug-fix-null-pointer-api.txt +75 -0
  420. package/fixtures/classifier-gold/transcripts/02-bug-fix-race-condition-queue.txt +77 -0
  421. package/fixtures/classifier-gold/transcripts/03-bug-fix-jwt-clock-skew.txt +86 -0
  422. package/fixtures/classifier-gold/transcripts/04-feature-webhook-retry.txt +95 -0
  423. package/fixtures/classifier-gold/transcripts/05-feature-csv-export.txt +86 -0
  424. package/fixtures/classifier-gold/transcripts/06-feature-rate-limiting.txt +61 -0
  425. package/fixtures/classifier-gold/transcripts/07-refactor-db-abstraction.txt +72 -0
  426. package/fixtures/classifier-gold/transcripts/08-refactor-config-loading.txt +89 -0
  427. package/fixtures/classifier-gold/transcripts/09-ops-docker-staging.txt +94 -0
  428. package/fixtures/classifier-gold/transcripts/10-ops-nginx-ssl.txt +121 -0
  429. package/fixtures/classifier-gold/transcripts/11-ops-postgres-migration.txt +74 -0
  430. package/fixtures/classifier-gold/transcripts/12-ops-cron-debugging.txt +73 -0
  431. package/fixtures/classifier-gold/transcripts/13-research-vector-db-comparison.txt +59 -0
  432. package/fixtures/classifier-gold/transcripts/14-research-oauth-provider.txt +74 -0
  433. package/fixtures/classifier-gold/transcripts/15-writing-api-docs.txt +154 -0
  434. package/fixtures/classifier-gold/transcripts/16-meeting-sprint-planning.txt +69 -0
  435. package/fixtures/classifier-gold/transcripts/17-trivial-list-files.txt +14 -0
  436. package/fixtures/classifier-gold/transcripts/18-trivial-version-check.txt +21 -0
  437. package/fixtures/classifier-gold/transcripts/19-trivial-syntax-help.txt +29 -0
  438. package/fixtures/classifier-gold/transcripts/20-trivial-read-package-json.txt +41 -0
  439. package/migrations/000_initial_schema.sql +1 -1
  440. package/migrations/024_backfill_exemplar_repo_basename.sql +32 -0
  441. package/migrations/025_workstreams.sql +30 -0
  442. package/migrations/026_embedding_config.sql +12 -0
  443. package/migrations/027_drop_legacy_session_embeddings.sql +7 -0
  444. package/migrations/028_classifier_provenance.sql +5 -0
  445. package/migrations/029_project_scope.sql +21 -0
  446. package/migrations/032_session_derivables.sql +11 -0
  447. package/migrations/pg/001_initial.sql +34 -0
  448. package/migrations/pg/019_split_replaces.sql +16 -7
  449. package/migrations/pg/025_workstreams.sql +34 -0
  450. package/migrations/pg/026_embedding_config.sql +12 -0
  451. package/migrations/pg/028_classifier_provenance.sql +5 -0
  452. package/migrations/pg/029_entity_variants.sql +9 -0
  453. package/migrations/pg/030_project_scope.sql +23 -0
  454. package/migrations/pg/031_widen_session_edges_kind.sql +11 -0
  455. package/migrations/pg/032_session_derivables.sql +17 -0
  456. package/nlm/index.js +405 -39
  457. package/package.json +12 -2
  458. package/plugin/.codex-plugin/plugin.json +2 -2
  459. package/plugin/scripts/prompt-recall-hook.mjs +413 -43
  460. package/plugin/scripts/session-start-hook.mjs +295 -61
  461. package/plugin/scripts/stop-hook.mjs +89 -66
  462. package/plugin-hermes-agent/__init__.py +2 -1
  463. package/templates/agent-contract/README.md +24 -0
  464. package/templates/agent-contract/claude-code.md +40 -0
  465. package/templates/agent-contract/generic.md +38 -0
  466. package/dist/core/embedding/embed-normalize.d.ts +0 -28
  467. package/dist/core/embedding/embed-normalize.js +0 -98
  468. package/dist/core/embedding/embed-normalize.js.map +0 -1
  469. package/dist/core/storage/pg-tx-context.d.ts +0 -52
  470. package/dist/core/storage/pg-tx-context.js +0 -149
  471. package/dist/core/storage/pg-tx-context.js.map +0 -1
@@ -0,0 +1,61 @@
1
+ import { normalizeLabel } from "./model.js";
2
+ function jaccard(a, b) {
3
+ const sa = new Set(a);
4
+ const sb = new Set(b);
5
+ let shared = 0;
6
+ for (const x of sa)
7
+ if (sb.has(x))
8
+ shared++;
9
+ const union = sa.size + sb.size - shared;
10
+ return { shared, score: union === 0 ? 0 : shared / union };
11
+ }
12
+ function levenshtein(a, b) {
13
+ const m = a.length;
14
+ const n = b.length;
15
+ if (m === 0)
16
+ return n;
17
+ if (n === 0)
18
+ return m;
19
+ let prev = Array.from({ length: n + 1 }, (_, i) => i);
20
+ let cur = new Array(n + 1);
21
+ for (let i = 1; i <= m; i++) {
22
+ cur[0] = i;
23
+ for (let j = 1; j <= n; j++) {
24
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
25
+ cur[j] = Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + cost);
26
+ }
27
+ [prev, cur] = [cur, prev];
28
+ }
29
+ return prev[n];
30
+ }
31
+ function labelSimilarity(a, b) {
32
+ const na = normalizeLabel(a);
33
+ const nb = normalizeLabel(b);
34
+ const maxLen = Math.max(na.length, nb.length);
35
+ if (maxLen === 0)
36
+ return 1;
37
+ return 1 - levenshtein(na, nb) / maxLen;
38
+ }
39
+ export function scoreMergePair(a, b) {
40
+ const ent = jaccard(a.entities, b.entities);
41
+ const sess = jaccard(a.sessionIds, b.sessionIds);
42
+ const lab = labelSimilarity(a.label, b.label);
43
+ const score = (ent.score + sess.score + lab) / 3;
44
+ return {
45
+ aId: a.id, aLabel: a.label, bId: b.id, bLabel: b.label,
46
+ score, sharedEntities: ent.shared, sharedSessions: sess.shared, labelSimilarity: lab,
47
+ };
48
+ }
49
+ /** All unordered pairs scoring >= minScore, ranked desc. Pure; O(n^2) over the (small) workstream set. */
50
+ export function suggestMerges(items, minScore) {
51
+ const out = [];
52
+ for (let i = 0; i < items.length; i++) {
53
+ for (let j = i + 1; j < items.length; j++) {
54
+ const s = scoreMergePair(items[i], items[j]);
55
+ if (s.score >= minScore)
56
+ out.push(s);
57
+ }
58
+ }
59
+ return out.sort((x, y) => y.score - x.score);
60
+ }
61
+ //# sourceMappingURL=merge-suggest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge-suggest.js","sourceRoot":"","sources":["../../../src/core/workstream/merge-suggest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { Fact, CodeExemplar } from "../../shared/types.js";
2
+ export type WorkstreamStatus = "active" | "merged" | "retired";
3
+ export interface Workstream {
4
+ readonly id: string;
5
+ readonly label: string;
6
+ readonly status: WorkstreamStatus;
7
+ readonly mergedInto: string | null;
8
+ readonly createdAt: string;
9
+ readonly updatedAt: string;
10
+ readonly lastSessionAt: string | null;
11
+ readonly scope: string | null;
12
+ }
13
+ export type BindingSource = "classifier" | "operator" | "backfill";
14
+ export interface WorkstreamRollup {
15
+ readonly workstream: Workstream;
16
+ readonly sessionIds: ReadonlyArray<string>;
17
+ readonly facts: ReadonlyArray<Fact>;
18
+ readonly exemplars: ReadonlyArray<CodeExemplar>;
19
+ }
20
+ export declare function makeWorkstreamId(): string;
21
+ export declare function normalizeLabel(label: string): string;
@@ -0,0 +1,9 @@
1
+ // src/core/workstream/model.ts
2
+ import { randomUUID } from "node:crypto";
3
+ export function makeWorkstreamId() {
4
+ return `ws_${randomUUID()}`;
5
+ }
6
+ export function normalizeLabel(label) {
7
+ return label.trim().toLowerCase().replace(/\s+/g, " ");
8
+ }
9
+ //# sourceMappingURL=model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../../../src/core/workstream/model.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAyBzC,MAAM,UAAU,gBAAgB;IAC9B,OAAO,MAAM,UAAU,EAAE,EAAE,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AACzD,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { type Workstream } from "./model.js";
2
+ export type NameDecision = {
3
+ kind: "bind";
4
+ workstreamId: string;
5
+ } | {
6
+ kind: "abstain";
7
+ };
8
+ export declare function decideWorkstreamByName(named: string | null, workstreams: ReadonlyArray<Pick<Workstream, "id" | "label">>, aliasToLabel: ReadonlyMap<string, string>): NameDecision;
@@ -0,0 +1,18 @@
1
+ // src/core/workstream/name-match.ts
2
+ import { normalizeLabel } from "./model.js";
3
+ export function decideWorkstreamByName(named, workstreams, aliasToLabel) {
4
+ if (!named || !named.trim())
5
+ return { kind: "abstain" };
6
+ const byLabel = new Map(workstreams.map((w) => [normalizeLabel(w.label), w.id]));
7
+ const direct = byLabel.get(normalizeLabel(named));
8
+ if (direct)
9
+ return { kind: "bind", workstreamId: direct };
10
+ const canonical = aliasToLabel.get(normalizeLabel(named));
11
+ if (canonical) {
12
+ const viaAlias = byLabel.get(normalizeLabel(canonical));
13
+ if (viaAlias)
14
+ return { kind: "bind", workstreamId: viaAlias };
15
+ }
16
+ return { kind: "abstain" };
17
+ }
18
+ //# sourceMappingURL=name-match.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"name-match.js","sourceRoot":"","sources":["../../../src/core/workstream/name-match.ts"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,OAAO,EAAE,cAAc,EAAmB,MAAM,YAAY,CAAC;AAI7D,MAAM,UAAU,sBAAsB,CACpC,KAAoB,EACpB,WAA4D,EAC5D,YAAyC;IAEzC,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IACxD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACjF,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC;IAClD,IAAI,MAAM;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC;IAC1D,MAAM,SAAS,GAAG,YAAY,CAAC,GAAG,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1D,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC;QACxD,IAAI,QAAQ;YAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC;IAChE,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Walk the merged_into chain to the live survivor. Mirrors the replaces-chain
3
+ * resolution in ui/lib/thread-groups.ts. Iterative + visited-set guarded so a
4
+ * (data-corrupt) cycle terminates instead of looping. Fail-open: an id absent
5
+ * from the map resolves to itself.
6
+ */
7
+ export declare function resolveWorkstreamId(id: string, byId: ReadonlyMap<string, {
8
+ id: string;
9
+ mergedInto: string | null;
10
+ }>): string;
@@ -0,0 +1,21 @@
1
+ // src/core/workstream/resolve.ts
2
+ /**
3
+ * Walk the merged_into chain to the live survivor. Mirrors the replaces-chain
4
+ * resolution in ui/lib/thread-groups.ts. Iterative + visited-set guarded so a
5
+ * (data-corrupt) cycle terminates instead of looping. Fail-open: an id absent
6
+ * from the map resolves to itself.
7
+ */
8
+ export function resolveWorkstreamId(id, byId) {
9
+ const seen = new Set();
10
+ let cur = id;
11
+ while (true) {
12
+ if (seen.has(cur))
13
+ return cur;
14
+ seen.add(cur);
15
+ const node = byId.get(cur);
16
+ if (!node || node.mergedInto === null)
17
+ return cur;
18
+ cur = node.mergedInto;
19
+ }
20
+ }
21
+ //# sourceMappingURL=resolve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../../src/core/workstream/resolve.ts"],"names":[],"mappings":"AAAA,iCAAiC;AAEjC;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CACjC,EAAU,EACV,IAAoE;IAEpE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,GAAG,CAAC;QAC9B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC3B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI;YAAE,OAAO,GAAG,CAAC;QAClD,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC;IACxB,CAAC;AACH,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { WorkstreamStore } from "../../ports/workstream-store.js";
2
+ import type { SessionStore } from "../../ports/session-store.js";
3
+ import type { FactStore } from "../../ports/fact-store.js";
4
+ import type { CodeExemplarStore } from "../../ports/code-exemplar-store.js";
5
+ import type { WorkstreamRollup } from "./model.js";
6
+ export interface RollupDeps {
7
+ readonly workstreams: Pick<WorkstreamStore, "listAll" | "getById">;
8
+ readonly sessions: Pick<SessionStore, "listSessionIdsByWorkstreams">;
9
+ readonly facts: Pick<FactStore, "listBySessions">;
10
+ readonly exemplars: Pick<CodeExemplarStore, "listBySessions">;
11
+ }
12
+ export declare function rollupWorkstream(deps: RollupDeps, workstreamId: string): Promise<WorkstreamRollup | null>;
@@ -0,0 +1,17 @@
1
+ import { resolveWorkstreamId } from "./resolve.js";
2
+ export async function rollupWorkstream(deps, workstreamId) {
3
+ const all = await deps.workstreams.listAll();
4
+ const byId = new Map(all.map((w) => [w.id, { id: w.id, mergedInto: w.mergedInto }]));
5
+ const survivorId = resolveWorkstreamId(workstreamId, byId);
6
+ const workstream = await deps.workstreams.getById(survivorId);
7
+ if (!workstream)
8
+ return null;
9
+ const memberIds = all.filter((w) => resolveWorkstreamId(w.id, byId) === survivorId).map((w) => w.id);
10
+ const sessionIds = await deps.sessions.listSessionIdsByWorkstreams(memberIds);
11
+ const [facts, exemplars] = await Promise.all([
12
+ deps.facts.listBySessions(sessionIds),
13
+ deps.exemplars.listBySessions(sessionIds),
14
+ ]);
15
+ return { workstream, sessionIds, facts, exemplars };
16
+ }
17
+ //# sourceMappingURL=rollup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rollup.js","sourceRoot":"","sources":["../../../src/core/workstream/rollup.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AASnD,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAgB,EAAE,YAAoB;IAC3E,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;IAC7C,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;IACrF,MAAM,UAAU,GAAG,mBAAmB,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IAC3D,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC9D,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAE7B,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACrG,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,2BAA2B,CAAC,SAAS,CAAC,CAAC;IAC9E,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC3C,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC;QACrC,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,UAAU,CAAC;KAC1C,CAAC,CAAC;IACH,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;AACtD,CAAC"}
@@ -0,0 +1,10 @@
1
+ export interface WorkTopic {
2
+ readonly label: string;
3
+ readonly entities: ReadonlyArray<string>;
4
+ }
5
+ export declare function parseWorkTopics(raw: unknown): ReadonlyArray<WorkTopic>;
6
+ /**
7
+ * Build a map from normalized alias -> canonical label for all topics.
8
+ * Used by the binding path to resolve classifier output through aliases.
9
+ */
10
+ export declare function aliasToLabelMap(topics: ReadonlyArray<WorkTopic>): Map<string, string>;
@@ -0,0 +1,55 @@
1
+ // src/core/workstream/work-topics.ts
2
+ import { normalizeLabel } from "./model.js";
3
+ export function parseWorkTopics(raw) {
4
+ if (Array.isArray(raw)) {
5
+ return raw.map((t) => {
6
+ if (!t ||
7
+ typeof t !== "object" ||
8
+ typeof t.label !== "string" ||
9
+ !Array.isArray(t.entities)) {
10
+ throw new Error(`work-topics: array item is not {label, entities[]}: ${JSON.stringify(t)}`);
11
+ }
12
+ return {
13
+ label: t.label,
14
+ entities: (t.entities).map(String),
15
+ };
16
+ });
17
+ }
18
+ if (raw && typeof raw === "object") {
19
+ const entries = Object.entries(raw);
20
+ // Alias-map shape { "<alias>": "<canonical>" }: group aliases under their
21
+ // canonical label. Canonical = workstream label; aliases (+ the canonical itself)
22
+ // = its entities.
23
+ if (entries.length > 0 && entries.every(([, v]) => typeof v === "string")) {
24
+ const byCanonical = new Map();
25
+ for (const [alias, canonical] of entries) {
26
+ const set = byCanonical.get(canonical) ?? new Set([canonical]);
27
+ set.add(alias);
28
+ byCanonical.set(canonical, set);
29
+ }
30
+ return [...byCanonical].map(([label, entities]) => ({ label, entities: [...entities] }));
31
+ }
32
+ // Label-to-entities map { "<label>": ["<entity>", ...] }.
33
+ return entries.map(([label, ents]) => {
34
+ if (!Array.isArray(ents)) {
35
+ throw new Error(`work-topics: value for "${label}" is neither a string (alias map) nor an array (entity map)`);
36
+ }
37
+ return { label, entities: ents.map(String) };
38
+ });
39
+ }
40
+ throw new Error("work-topics: expected an object map or an array of {label, entities[]}");
41
+ }
42
+ /**
43
+ * Build a map from normalized alias -> canonical label for all topics.
44
+ * Used by the binding path to resolve classifier output through aliases.
45
+ */
46
+ export function aliasToLabelMap(topics) {
47
+ const out = new Map();
48
+ for (const topic of topics) {
49
+ for (const entity of topic.entities) {
50
+ out.set(normalizeLabel(entity), topic.label);
51
+ }
52
+ }
53
+ return out;
54
+ }
55
+ //# sourceMappingURL=work-topics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"work-topics.js","sourceRoot":"","sources":["../../../src/core/workstream/work-topics.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAO5C,MAAM,UAAU,eAAe,CAAC,GAAY;IAC1C,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACnB,IACE,CAAC,CAAC;gBACF,OAAO,CAAC,KAAK,QAAQ;gBACrB,OAAQ,CAAyB,CAAC,KAAK,KAAK,QAAQ;gBACpD,CAAC,KAAK,CAAC,OAAO,CAAE,CAA4B,CAAC,QAAQ,CAAC,EACtD,CAAC;gBACD,MAAM,IAAI,KAAK,CACb,uDAAuD,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAC3E,CAAC;YACJ,CAAC;YACD,OAAO;gBACL,KAAK,EAAG,CAAuB,CAAC,KAAK;gBACrC,QAAQ,EAAE,CAAE,CAA6B,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;aAChE,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IACD,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAA8B,CAAC,CAAC;QAC/D,0EAA0E;QAC1E,kFAAkF;QAClF,kBAAkB;QAClB,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,EAAE,CAAC;YAC1E,MAAM,WAAW,GAAG,IAAI,GAAG,EAAuB,CAAC;YACnD,KAAK,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,IAAI,OAAkC,EAAE,CAAC;gBACpE,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI,GAAG,CAAS,CAAC,SAAS,CAAC,CAAC,CAAC;gBACvE,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBACf,WAAW,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;YAClC,CAAC;YACD,OAAO,CAAC,GAAG,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3F,CAAC;QACD,0DAA0D;QAC1D,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE;YACnC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzB,MAAM,IAAI,KAAK,CAAC,2BAA2B,KAAK,6DAA6D,CAAC,CAAC;YACjH,CAAC;YACD,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/C,CAAC,CAAC,CAAC;IACL,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAC;AAC5F,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,MAAgC;IAC9D,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;IACtC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACpC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function readStdin(): Promise<string>;
2
+ export declare function fetchWithTimeout(url: string, init: RequestInit, ms: number): Promise<Response>;
3
+ export declare function hookModeFromEnv(): "shadow" | "live";
4
+ export declare function appendHookEvent(data: Record<string, unknown>): void;
@@ -0,0 +1,36 @@
1
+ import { appendFileSync, mkdirSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { dirname, join } from "node:path";
4
+ export function readStdin() {
5
+ return new Promise((resolve) => {
6
+ let data = "";
7
+ process.stdin.setEncoding("utf8");
8
+ process.stdin.on("data", (chunk) => (data += chunk));
9
+ process.stdin.on("end", () => resolve(data));
10
+ process.stdin.on("error", () => resolve(data));
11
+ });
12
+ }
13
+ export async function fetchWithTimeout(url, init, ms) {
14
+ const controller = new AbortController();
15
+ const timer = setTimeout(() => controller.abort(), ms);
16
+ try {
17
+ return await fetch(url, { ...init, signal: controller.signal });
18
+ }
19
+ finally {
20
+ clearTimeout(timer);
21
+ }
22
+ }
23
+ export function hookModeFromEnv() {
24
+ return process.env["NLM_HOOK_MODE"] === "live" ? "live" : "shadow";
25
+ }
26
+ export function appendHookEvent(data) {
27
+ try {
28
+ const path = process.env["NLM_HOOK_LOG"] ?? join(homedir(), ".nlm", "hook-log.jsonl");
29
+ mkdirSync(dirname(path), { recursive: true });
30
+ appendFileSync(path, `${JSON.stringify(data)}\n`, "utf8");
31
+ }
32
+ catch {
33
+ // Telemetry failure must never break the hook.
34
+ }
35
+ }
36
+ //# sourceMappingURL=hook-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-helpers.js","sourceRoot":"","sources":["../../src/hook/hook-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,UAAU,SAAS;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAClC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC;QACrD,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QAC7C,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAW,EACX,IAAiB,EACjB,EAAU;IAEV,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;IACvD,IAAI,CAAC;QACH,OAAO,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;IAClE,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAA6B;IAC3D,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC;QACtF,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,cAAc,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,+CAA+C;IACjD,CAAC;AACH,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Claude Code PreCompact hook entrypoint for NLM.
3
+ *
4
+ * Fires before Claude Code compacts a long transcript. At compaction time the
5
+ * in-flight surfaced-IDs memo and any pending citation state would be lost.
6
+ * This hook POSTs a compaction event to the daemon so it can do a final
7
+ * synchronous citation scan of the transcript before the shape is lost.
8
+ *
9
+ * Daemon endpoint: POST /api/hook/pre-compact
10
+ *
11
+ * Payload: { conversation_id, transcript_path, surfaced_set, ts }
12
+ *
13
+ * Fail-open by design: any error yields a clean exit with no output.
14
+ */
15
+ export interface PreCompactInput {
16
+ readonly conversationId: string;
17
+ readonly transcriptPath: string;
18
+ }
19
+ export interface PreCompactResult {
20
+ readonly conversationId: string;
21
+ readonly posted: boolean;
22
+ }
23
+ export declare function runPreCompact(input: PreCompactInput, portValue?: string): Promise<PreCompactResult>;
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Claude Code PreCompact hook entrypoint for NLM.
3
+ *
4
+ * Fires before Claude Code compacts a long transcript. At compaction time the
5
+ * in-flight surfaced-IDs memo and any pending citation state would be lost.
6
+ * This hook POSTs a compaction event to the daemon so it can do a final
7
+ * synchronous citation scan of the transcript before the shape is lost.
8
+ *
9
+ * Daemon endpoint: POST /api/hook/pre-compact
10
+ *
11
+ * Payload: { conversation_id, transcript_path, surfaced_set, ts }
12
+ *
13
+ * Fail-open by design: any error yields a clean exit with no output.
14
+ */
15
+ import { pathToFileURL } from "node:url";
16
+ import { loadSurfaced } from "../core/hook/memo.js";
17
+ import { autoloadEnv } from "../llm/env-autoload.js";
18
+ import { hookAuthHeaders } from "./hook-auth.js";
19
+ import { readStdin, fetchWithTimeout, appendHookEvent } from "./hook-helpers.js";
20
+ import { DEFAULT_NLM_PORT } from "../shared/net.js";
21
+ const POST_TIMEOUT_MS = 1500;
22
+ export async function runPreCompact(input, portValue = process.env["NLM_PORT"] ?? DEFAULT_NLM_PORT) {
23
+ const surfacedSet = [...loadSurfaced(input.conversationId)];
24
+ const payload = {
25
+ conversation_id: input.conversationId,
26
+ transcript_path: input.transcriptPath,
27
+ surfaced_set: surfacedSet,
28
+ ts: new Date().toISOString(),
29
+ };
30
+ try {
31
+ const res = await fetchWithTimeout(`http://127.0.0.1:${portValue}/api/hook/pre-compact`, {
32
+ method: "POST",
33
+ headers: hookAuthHeaders({ "content-type": "application/json" }),
34
+ body: JSON.stringify(payload),
35
+ }, POST_TIMEOUT_MS);
36
+ return { conversationId: input.conversationId, posted: res.ok };
37
+ }
38
+ catch {
39
+ return { conversationId: input.conversationId, posted: false };
40
+ }
41
+ }
42
+ function logResult(result) {
43
+ appendHookEvent({
44
+ ts: new Date().toISOString(),
45
+ kind: "pre-compact",
46
+ conversationId: result.conversationId,
47
+ posted: result.posted,
48
+ });
49
+ }
50
+ async function main() {
51
+ try {
52
+ autoloadEnv();
53
+ const raw = await readStdin();
54
+ const payload = JSON.parse(raw);
55
+ const conversationId = typeof payload.session_id === "string" ? payload.session_id : "unknown";
56
+ const transcriptPath = typeof payload.transcript_path === "string" ? payload.transcript_path : "";
57
+ const result = await runPreCompact({ conversationId, transcriptPath });
58
+ logResult(result);
59
+ }
60
+ catch {
61
+ // Fail open — never block Claude Code compaction.
62
+ }
63
+ }
64
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
65
+ void main();
66
+ }
67
+ //# sourceMappingURL=pre-compact-hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pre-compact-hook.js","sourceRoot":"","sources":["../../src/hook/pre-compact-hook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,eAAe,GAAG,IAAI,CAAC;AAY7B,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,KAAsB,EACtB,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,gBAAgB;IAEvD,MAAM,WAAW,GAAG,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC;IAC5D,MAAM,OAAO,GAAG;QACd,eAAe,EAAE,KAAK,CAAC,cAAc;QACrC,eAAe,EAAE,KAAK,CAAC,cAAc;QACrC,YAAY,EAAE,WAAW;QACzB,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KAC7B,CAAC;IACF,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAChC,oBAAoB,SAAS,uBAAuB,EACpD;YACE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,eAAe,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC;YAChE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;SAC9B,EACD,eAAe,CAChB,CAAC;QACF,OAAO,EAAE,cAAc,EAAE,KAAK,CAAC,cAAc,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC;IAClE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,cAAc,EAAE,KAAK,CAAC,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IACjE,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,MAAwB;IACzC,eAAe,CAAC;QACd,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QAC5B,IAAI,EAAE,aAAa;QACnB,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,MAAM,EAAE,MAAM,CAAC,MAAM;KACtB,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,WAAW,EAAE,CAAC;QACd,MAAM,GAAG,GAAG,MAAM,SAAS,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAG7B,CAAC;QACF,MAAM,cAAc,GAClB,OAAO,OAAO,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;QAC1E,MAAM,cAAc,GAClB,OAAO,OAAO,CAAC,eAAe,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7E,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,EAAE,cAAc,EAAE,cAAc,EAAE,CAAC,CAAC;QACvE,SAAS,CAAC,MAAM,CAAC,CAAC;IACpB,CAAC;IAAC,MAAM,CAAC;QACP,kDAAkD;IACpD,CAAC;AACH,CAAC;AAED,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/E,KAAK,IAAI,EAAE,CAAC;AACd,CAAC"}
@@ -11,17 +11,51 @@
11
11
  */
12
12
  import { type PointerExemplar, type PointerFact } from "../core/hook/pointer-block.js";
13
13
  import { type RecallHitInput } from "../core/hook/select.js";
14
+ export declare function parseHookDeadline(raw: string | undefined, defaultMs?: number): number;
15
+ export declare const HOOK_DEADLINE_MS: number;
14
16
  export type HookMode = "shadow" | "live";
15
17
  export declare function hookRuntimeFromEnv(env?: NodeJS.ProcessEnv): string;
18
+ /**
19
+ * Whether the per-prompt ambient recall hook should run at all.
20
+ *
21
+ * Pull-first posture (default since #392, 2026-07-03): fresh installs run
22
+ * per-prompt ambient recall OFF and agents pull memory on demand via the
23
+ * recall MCP tools. Measured basis (U1, locked judge): pulls 72.4% useful
24
+ * vs ambient injection 18.2%/7.9%. NLM_HOOK_PROMPT_RECALL=on opts back in;
25
+ * any other already-set value keeps its pre-flip meaning (non-"off" = on)
26
+ * so existing installs are untouched. Independent of NLM_HOOK_MODE, which
27
+ * governs the once-per-session passive layer (session-start hook), which
28
+ * stays on.
29
+ */
30
+ export declare function promptRecallEnabled(env?: NodeJS.ProcessEnv): boolean;
16
31
  export interface HookInput {
17
32
  readonly prompt: string;
18
33
  readonly conversationId: string;
34
+ /** Runtime transcript path, when the runtime exposes one (Claude Code does). */
35
+ readonly transcriptPath?: string;
19
36
  }
37
+ /**
38
+ * The recall query. Default is the bare prompt (today's behavior). When the
39
+ * context-recall flag is on AND the prompt is thin (few content words — the
40
+ * measured off-topic failure band) AND a transcript is available, prepend the
41
+ * recent conversation turns so the query carries the topic the thin prompt
42
+ * lacks. Flag-gated + thin-only + fallback => never worse than today.
43
+ */
44
+ export declare function buildRecallQuery(input: HookInput, env?: NodeJS.ProcessEnv): string;
20
45
  export interface RecallFetchResult {
21
46
  readonly hits: ReadonlyArray<RecallHitInput>;
22
47
  readonly facts: ReadonlyArray<PointerFact>;
23
48
  readonly exemplars?: ReadonlyArray<PointerExemplar>;
24
49
  }
50
+ export type GateMode = "shadow" | "live";
51
+ export interface RecallGate {
52
+ /** shadow = log decisions, inject as usual; live = drop irrelevant candidates. */
53
+ readonly mode: GateMode;
54
+ /** Predict, from the prompt and a candidate's context, whether to inject it. */
55
+ readonly judge: (prompt: string, candidate: string) => Promise<"relevant" | "irrelevant">;
56
+ /** Judge only the top N candidates (bounds hot-path latency). Unset = all. */
57
+ readonly maxCandidates?: number;
58
+ }
25
59
  export interface RunHookDeps {
26
60
  readonly mode: HookMode;
27
61
  /**
@@ -29,6 +63,10 @@ export interface RunHookDeps {
29
63
  * bare hit array; runHook normalizes both shapes.
30
64
  */
31
65
  readonly recall: (prompt: string) => Promise<ReadonlyArray<RecallHitInput> | RecallFetchResult>;
66
+ /** Optional pre-injection relevance gate. Absent => no gating (today's behavior). */
67
+ readonly recallGate?: RecallGate;
68
+ /** Wall-clock deadline for the combined recall + gate stages. Defaults to NLM_HOOK_DEADLINE_MS (6000ms; must exceed the recall HTTP timeout, see #396). */
69
+ readonly deadlineMs?: number;
32
70
  }
33
71
  /** Orchestration. Returns the text to emit on stdout ("" for nothing). */
34
72
  export declare function runHook(input: HookInput, deps: RunHookDeps): Promise<string>;