hippo-memory 1.44.0 → 1.46.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 (554) hide show
  1. package/README.md +68 -24
  2. package/bin/hippo.js +3 -1
  3. package/dist/ablation.d.ts +10 -1
  4. package/dist/ablation.js +17 -1
  5. package/dist/api.d.ts +81 -22
  6. package/dist/api.js +258 -49
  7. package/dist/audit.d.ts +2 -2
  8. package/dist/audit.js +9 -0
  9. package/dist/autolearn.d.ts +1 -1
  10. package/dist/autolearn.js +2 -1
  11. package/dist/capture-error.d.ts +20 -0
  12. package/dist/capture-error.js +82 -0
  13. package/dist/capture.d.ts +25 -8
  14. package/dist/capture.js +100 -5
  15. package/dist/cli.d.ts +9 -1
  16. package/dist/cli.js +531 -119
  17. package/dist/client.d.ts +4 -21
  18. package/dist/client.js +3 -112
  19. package/dist/config.d.ts +20 -0
  20. package/dist/config.js +37 -1
  21. package/dist/consolidate.d.ts +9 -0
  22. package/dist/consolidate.js +133 -46
  23. package/dist/dag.d.ts +1 -0
  24. package/dist/dag.js +10 -5
  25. package/dist/dashboard.js +7 -3
  26. package/dist/db.js +69 -24
  27. package/dist/dedupe.d.ts +1 -0
  28. package/dist/dedupe.js +4 -7
  29. package/dist/doctor.d.ts +34 -0
  30. package/dist/doctor.js +174 -0
  31. package/dist/dormant.d.ts +91 -0
  32. package/dist/dormant.js +121 -0
  33. package/dist/embedding-provider.js +2 -1
  34. package/dist/embeddings.js +81 -8
  35. package/dist/eval-stats.d.ts +123 -0
  36. package/dist/eval-stats.js +187 -0
  37. package/dist/extract.d.ts +2 -0
  38. package/dist/extract.js +9 -4
  39. package/dist/half-life-migration.d.ts +55 -0
  40. package/dist/half-life-migration.js +111 -0
  41. package/dist/hooks.d.ts +4 -0
  42. package/dist/hooks.js +47 -0
  43. package/dist/mcp/server.d.ts +6 -0
  44. package/dist/mcp/server.js +90 -48
  45. package/dist/memory.d.ts +18 -1
  46. package/dist/memory.js +33 -5
  47. package/dist/physics-config.js +5 -1
  48. package/dist/recall-scope.d.ts +24 -0
  49. package/dist/recall-scope.js +41 -0
  50. package/dist/refine-llm.js +3 -2
  51. package/dist/reject-flow.d.ts +3 -3
  52. package/dist/reject-flow.js +10 -3
  53. package/dist/rerankers/jev.js +3 -2
  54. package/dist/rerankers/llm.js +3 -2
  55. package/dist/search.d.ts +4 -4
  56. package/dist/search.js +26 -21
  57. package/dist/server.d.ts +5 -0
  58. package/dist/server.js +49 -29
  59. package/dist/shared.js +1 -1
  60. package/dist/store.d.ts +29 -11
  61. package/dist/store.js +197 -70
  62. package/dist/token-ledger.d.ts +119 -0
  63. package/dist/token-ledger.js +181 -0
  64. package/dist/version.d.ts +4 -6
  65. package/dist/version.js +4 -7
  66. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  67. package/extensions/openclaw-plugin/package.json +1 -1
  68. package/openclaw.plugin.json +1 -1
  69. package/package.json +7 -3
  70. package/dist/ablation.d.ts.map +0 -1
  71. package/dist/ablation.js.map +0 -1
  72. package/dist/ambient.d.ts.map +0 -1
  73. package/dist/ambient.js.map +0 -1
  74. package/dist/api.d.ts.map +0 -1
  75. package/dist/api.js.map +0 -1
  76. package/dist/audit-prune.d.ts.map +0 -1
  77. package/dist/audit-prune.js.map +0 -1
  78. package/dist/audit.d.ts.map +0 -1
  79. package/dist/audit.js.map +0 -1
  80. package/dist/auth.d.ts.map +0 -1
  81. package/dist/auth.js.map +0 -1
  82. package/dist/autolearn.d.ts.map +0 -1
  83. package/dist/autolearn.js.map +0 -1
  84. package/dist/availability.d.ts.map +0 -1
  85. package/dist/availability.js.map +0 -1
  86. package/dist/benchmarks/e1.3/incident-recall-eval.js +0 -78
  87. package/dist/benchmarks/e1.3/incident-recall-eval.js.map +0 -1
  88. package/dist/benchmarks/e1.3/slack-1000-event-smoke.js +0 -103
  89. package/dist/benchmarks/e1.3/slack-1000-event-smoke.js.map +0 -1
  90. package/dist/capture.d.ts.map +0 -1
  91. package/dist/capture.js.map +0 -1
  92. package/dist/card-detail.d.ts.map +0 -1
  93. package/dist/card-detail.js.map +0 -1
  94. package/dist/card.d.ts.map +0 -1
  95. package/dist/card.js.map +0 -1
  96. package/dist/cli.d.ts.map +0 -1
  97. package/dist/cli.js.map +0 -1
  98. package/dist/client.d.ts.map +0 -1
  99. package/dist/client.js.map +0 -1
  100. package/dist/compare.d.ts.map +0 -1
  101. package/dist/compare.js.map +0 -1
  102. package/dist/config.d.ts.map +0 -1
  103. package/dist/config.js.map +0 -1
  104. package/dist/connectors/github/backfill.d.ts.map +0 -1
  105. package/dist/connectors/github/backfill.js.map +0 -1
  106. package/dist/connectors/github/cli-impl.d.ts.map +0 -1
  107. package/dist/connectors/github/cli-impl.js.map +0 -1
  108. package/dist/connectors/github/deletion.d.ts.map +0 -1
  109. package/dist/connectors/github/deletion.js.map +0 -1
  110. package/dist/connectors/github/dlq.d.ts.map +0 -1
  111. package/dist/connectors/github/dlq.js.map +0 -1
  112. package/dist/connectors/github/idempotency.d.ts.map +0 -1
  113. package/dist/connectors/github/idempotency.js.map +0 -1
  114. package/dist/connectors/github/ingest.d.ts.map +0 -1
  115. package/dist/connectors/github/ingest.js.map +0 -1
  116. package/dist/connectors/github/octokit-client.d.ts.map +0 -1
  117. package/dist/connectors/github/octokit-client.js.map +0 -1
  118. package/dist/connectors/github/ratelimit.d.ts.map +0 -1
  119. package/dist/connectors/github/ratelimit.js.map +0 -1
  120. package/dist/connectors/github/scope.d.ts.map +0 -1
  121. package/dist/connectors/github/scope.js.map +0 -1
  122. package/dist/connectors/github/signature.d.ts.map +0 -1
  123. package/dist/connectors/github/signature.js.map +0 -1
  124. package/dist/connectors/github/tenant-routing.d.ts.map +0 -1
  125. package/dist/connectors/github/tenant-routing.js.map +0 -1
  126. package/dist/connectors/github/transform.d.ts.map +0 -1
  127. package/dist/connectors/github/transform.js.map +0 -1
  128. package/dist/connectors/github/types.d.ts.map +0 -1
  129. package/dist/connectors/github/types.js.map +0 -1
  130. package/dist/connectors/slack/backfill.d.ts.map +0 -1
  131. package/dist/connectors/slack/backfill.js.map +0 -1
  132. package/dist/connectors/slack/deletion.d.ts.map +0 -1
  133. package/dist/connectors/slack/deletion.js.map +0 -1
  134. package/dist/connectors/slack/dlq.d.ts.map +0 -1
  135. package/dist/connectors/slack/dlq.js.map +0 -1
  136. package/dist/connectors/slack/idempotency.d.ts.map +0 -1
  137. package/dist/connectors/slack/idempotency.js.map +0 -1
  138. package/dist/connectors/slack/ingest.d.ts.map +0 -1
  139. package/dist/connectors/slack/ingest.js.map +0 -1
  140. package/dist/connectors/slack/ratelimit.d.ts.map +0 -1
  141. package/dist/connectors/slack/ratelimit.js.map +0 -1
  142. package/dist/connectors/slack/scope.d.ts.map +0 -1
  143. package/dist/connectors/slack/scope.js.map +0 -1
  144. package/dist/connectors/slack/signature.d.ts.map +0 -1
  145. package/dist/connectors/slack/signature.js.map +0 -1
  146. package/dist/connectors/slack/tenant-routing.d.ts.map +0 -1
  147. package/dist/connectors/slack/tenant-routing.js.map +0 -1
  148. package/dist/connectors/slack/transform.d.ts.map +0 -1
  149. package/dist/connectors/slack/transform.js.map +0 -1
  150. package/dist/connectors/slack/types.d.ts.map +0 -1
  151. package/dist/connectors/slack/types.js.map +0 -1
  152. package/dist/connectors/slack/web-client.d.ts.map +0 -1
  153. package/dist/connectors/slack/web-client.js.map +0 -1
  154. package/dist/connectors/slack/workspaces.d.ts.map +0 -1
  155. package/dist/connectors/slack/workspaces.js.map +0 -1
  156. package/dist/consolidate.d.ts.map +0 -1
  157. package/dist/consolidate.js.map +0 -1
  158. package/dist/correction-latency.d.ts.map +0 -1
  159. package/dist/correction-latency.js.map +0 -1
  160. package/dist/customer-notes.d.ts.map +0 -1
  161. package/dist/customer-notes.js.map +0 -1
  162. package/dist/dag.d.ts.map +0 -1
  163. package/dist/dag.js.map +0 -1
  164. package/dist/dashboard.d.ts.map +0 -1
  165. package/dist/dashboard.js.map +0 -1
  166. package/dist/db.d.ts.map +0 -1
  167. package/dist/db.js.map +0 -1
  168. package/dist/decisions.d.ts.map +0 -1
  169. package/dist/decisions.js.map +0 -1
  170. package/dist/dedupe.d.ts.map +0 -1
  171. package/dist/dedupe.js.map +0 -1
  172. package/dist/embedding-provider.d.ts.map +0 -1
  173. package/dist/embedding-provider.js.map +0 -1
  174. package/dist/embeddings.d.ts.map +0 -1
  175. package/dist/embeddings.js.map +0 -1
  176. package/dist/eval-suite.d.ts.map +0 -1
  177. package/dist/eval-suite.js.map +0 -1
  178. package/dist/eval.d.ts.map +0 -1
  179. package/dist/eval.js.map +0 -1
  180. package/dist/extensions/openclaw-plugin/index.js.map +0 -1
  181. package/dist/extract.d.ts.map +0 -1
  182. package/dist/extract.js.map +0 -1
  183. package/dist/forward-claim-detector.d.ts.map +0 -1
  184. package/dist/forward-claim-detector.js.map +0 -1
  185. package/dist/goals.d.ts.map +0 -1
  186. package/dist/goals.js.map +0 -1
  187. package/dist/graph-extract.d.ts.map +0 -1
  188. package/dist/graph-extract.js.map +0 -1
  189. package/dist/graph-recall.d.ts.map +0 -1
  190. package/dist/graph-recall.js.map +0 -1
  191. package/dist/graph-stream.d.ts.map +0 -1
  192. package/dist/graph-stream.js.map +0 -1
  193. package/dist/graph-view.d.ts.map +0 -1
  194. package/dist/graph-view.js.map +0 -1
  195. package/dist/graph.d.ts.map +0 -1
  196. package/dist/graph.js.map +0 -1
  197. package/dist/handoff.d.ts.map +0 -1
  198. package/dist/handoff.js.map +0 -1
  199. package/dist/hooks.d.ts.map +0 -1
  200. package/dist/hooks.js.map +0 -1
  201. package/dist/importers.d.ts.map +0 -1
  202. package/dist/importers.js.map +0 -1
  203. package/dist/incidents.d.ts.map +0 -1
  204. package/dist/incidents.js.map +0 -1
  205. package/dist/index.d.ts.map +0 -1
  206. package/dist/index.js.map +0 -1
  207. package/dist/invalidation.d.ts.map +0 -1
  208. package/dist/invalidation.js.map +0 -1
  209. package/dist/mcp/framing.d.ts.map +0 -1
  210. package/dist/mcp/framing.js.map +0 -1
  211. package/dist/mcp/server.d.ts.map +0 -1
  212. package/dist/mcp/server.js.map +0 -1
  213. package/dist/memory-value-weights.d.ts.map +0 -1
  214. package/dist/memory-value-weights.js.map +0 -1
  215. package/dist/memory-value.d.ts.map +0 -1
  216. package/dist/memory-value.js.map +0 -1
  217. package/dist/memory.d.ts.map +0 -1
  218. package/dist/memory.js.map +0 -1
  219. package/dist/multihop.d.ts.map +0 -1
  220. package/dist/multihop.js.map +0 -1
  221. package/dist/owner-validation.d.ts.map +0 -1
  222. package/dist/owner-validation.js.map +0 -1
  223. package/dist/path-context.d.ts.map +0 -1
  224. package/dist/path-context.js.map +0 -1
  225. package/dist/physics-config.d.ts.map +0 -1
  226. package/dist/physics-config.js.map +0 -1
  227. package/dist/physics-state.d.ts.map +0 -1
  228. package/dist/physics-state.js.map +0 -1
  229. package/dist/physics.d.ts.map +0 -1
  230. package/dist/physics.js.map +0 -1
  231. package/dist/policies.d.ts.map +0 -1
  232. package/dist/policies.js.map +0 -1
  233. package/dist/postinstall.d.ts.map +0 -1
  234. package/dist/postinstall.js.map +0 -1
  235. package/dist/predictions.d.ts.map +0 -1
  236. package/dist/predictions.js.map +0 -1
  237. package/dist/processes.d.ts.map +0 -1
  238. package/dist/processes.js.map +0 -1
  239. package/dist/project-briefs.d.ts.map +0 -1
  240. package/dist/project-briefs.js.map +0 -1
  241. package/dist/project-identity.d.ts.map +0 -1
  242. package/dist/project-identity.js.map +0 -1
  243. package/dist/provenance-coverage.d.ts.map +0 -1
  244. package/dist/provenance-coverage.js.map +0 -1
  245. package/dist/rate-limit.d.ts.map +0 -1
  246. package/dist/rate-limit.js.map +0 -1
  247. package/dist/raw-archive-mirror-cleanup.d.ts.map +0 -1
  248. package/dist/raw-archive-mirror-cleanup.js.map +0 -1
  249. package/dist/raw-archive.d.ts.map +0 -1
  250. package/dist/raw-archive.js.map +0 -1
  251. package/dist/recall-history.d.ts.map +0 -1
  252. package/dist/recall-history.js.map +0 -1
  253. package/dist/recall-scope.d.ts.map +0 -1
  254. package/dist/recall-scope.js.map +0 -1
  255. package/dist/recall-trace.d.ts.map +0 -1
  256. package/dist/recall-trace.js.map +0 -1
  257. package/dist/refine-llm.d.ts.map +0 -1
  258. package/dist/refine-llm.js.map +0 -1
  259. package/dist/reject-flow.d.ts.map +0 -1
  260. package/dist/reject-flow.js.map +0 -1
  261. package/dist/rejection.d.ts.map +0 -1
  262. package/dist/rejection.js.map +0 -1
  263. package/dist/replay.d.ts.map +0 -1
  264. package/dist/replay.js.map +0 -1
  265. package/dist/rerankers/cross-encoder.d.ts.map +0 -1
  266. package/dist/rerankers/cross-encoder.js.map +0 -1
  267. package/dist/rerankers/index.d.ts.map +0 -1
  268. package/dist/rerankers/index.js.map +0 -1
  269. package/dist/rerankers/jev.d.ts.map +0 -1
  270. package/dist/rerankers/jev.js.map +0 -1
  271. package/dist/rerankers/llm.d.ts.map +0 -1
  272. package/dist/rerankers/llm.js.map +0 -1
  273. package/dist/rerankers/types.d.ts.map +0 -1
  274. package/dist/rerankers/types.js.map +0 -1
  275. package/dist/rrf.d.ts.map +0 -1
  276. package/dist/rrf.js.map +0 -1
  277. package/dist/salience.d.ts.map +0 -1
  278. package/dist/salience.js.map +0 -1
  279. package/dist/scheduler.d.ts.map +0 -1
  280. package/dist/scheduler.js.map +0 -1
  281. package/dist/scope.d.ts.map +0 -1
  282. package/dist/scope.js.map +0 -1
  283. package/dist/search.d.ts.map +0 -1
  284. package/dist/search.js.map +0 -1
  285. package/dist/secret-detect.d.ts.map +0 -1
  286. package/dist/secret-detect.js.map +0 -1
  287. package/dist/server-detect.d.ts.map +0 -1
  288. package/dist/server-detect.js.map +0 -1
  289. package/dist/server.d.ts.map +0 -1
  290. package/dist/server.js.map +0 -1
  291. package/dist/shared.d.ts.map +0 -1
  292. package/dist/shared.js.map +0 -1
  293. package/dist/skills.d.ts.map +0 -1
  294. package/dist/skills.js.map +0 -1
  295. package/dist/sleep-redact.d.ts +0 -58
  296. package/dist/sleep-redact.d.ts.map +0 -1
  297. package/dist/sleep-redact.js +0 -80
  298. package/dist/sleep-redact.js.map +0 -1
  299. package/dist/src/ablation.js +0 -138
  300. package/dist/src/ablation.js.map +0 -1
  301. package/dist/src/ambient.js +0 -148
  302. package/dist/src/ambient.js.map +0 -1
  303. package/dist/src/api.js +0 -2109
  304. package/dist/src/api.js.map +0 -1
  305. package/dist/src/audit-prune.js +0 -109
  306. package/dist/src/audit-prune.js.map +0 -1
  307. package/dist/src/audit.js +0 -213
  308. package/dist/src/audit.js.map +0 -1
  309. package/dist/src/auth.js +0 -97
  310. package/dist/src/auth.js.map +0 -1
  311. package/dist/src/autolearn.js +0 -174
  312. package/dist/src/autolearn.js.map +0 -1
  313. package/dist/src/availability.js +0 -94
  314. package/dist/src/availability.js.map +0 -1
  315. package/dist/src/capture.js +0 -1346
  316. package/dist/src/capture.js.map +0 -1
  317. package/dist/src/card-detail.js +0 -15
  318. package/dist/src/card-detail.js.map +0 -1
  319. package/dist/src/card.js +0 -19
  320. package/dist/src/card.js.map +0 -1
  321. package/dist/src/cli.js +0 -9387
  322. package/dist/src/cli.js.map +0 -1
  323. package/dist/src/client.js +0 -237
  324. package/dist/src/client.js.map +0 -1
  325. package/dist/src/compare.js +0 -122
  326. package/dist/src/compare.js.map +0 -1
  327. package/dist/src/config.js +0 -135
  328. package/dist/src/config.js.map +0 -1
  329. package/dist/src/connectors/github/backfill.js +0 -281
  330. package/dist/src/connectors/github/backfill.js.map +0 -1
  331. package/dist/src/connectors/github/cli-impl.js +0 -234
  332. package/dist/src/connectors/github/cli-impl.js.map +0 -1
  333. package/dist/src/connectors/github/deletion.js +0 -85
  334. package/dist/src/connectors/github/deletion.js.map +0 -1
  335. package/dist/src/connectors/github/dlq.js +0 -190
  336. package/dist/src/connectors/github/dlq.js.map +0 -1
  337. package/dist/src/connectors/github/idempotency.js +0 -27
  338. package/dist/src/connectors/github/idempotency.js.map +0 -1
  339. package/dist/src/connectors/github/ingest.js +0 -156
  340. package/dist/src/connectors/github/ingest.js.map +0 -1
  341. package/dist/src/connectors/github/octokit-client.js +0 -70
  342. package/dist/src/connectors/github/octokit-client.js.map +0 -1
  343. package/dist/src/connectors/github/ratelimit.js +0 -31
  344. package/dist/src/connectors/github/ratelimit.js.map +0 -1
  345. package/dist/src/connectors/github/scope.js +0 -13
  346. package/dist/src/connectors/github/scope.js.map +0 -1
  347. package/dist/src/connectors/github/signature.js +0 -81
  348. package/dist/src/connectors/github/signature.js.map +0 -1
  349. package/dist/src/connectors/github/tenant-routing.js +0 -69
  350. package/dist/src/connectors/github/tenant-routing.js.map +0 -1
  351. package/dist/src/connectors/github/transform.js +0 -103
  352. package/dist/src/connectors/github/transform.js.map +0 -1
  353. package/dist/src/connectors/github/types.js +0 -100
  354. package/dist/src/connectors/github/types.js.map +0 -1
  355. package/dist/src/connectors/slack/backfill.js +0 -78
  356. package/dist/src/connectors/slack/backfill.js.map +0 -1
  357. package/dist/src/connectors/slack/deletion.js +0 -59
  358. package/dist/src/connectors/slack/deletion.js.map +0 -1
  359. package/dist/src/connectors/slack/dlq.js +0 -224
  360. package/dist/src/connectors/slack/dlq.js.map +0 -1
  361. package/dist/src/connectors/slack/idempotency.js +0 -31
  362. package/dist/src/connectors/slack/idempotency.js.map +0 -1
  363. package/dist/src/connectors/slack/ingest.js +0 -109
  364. package/dist/src/connectors/slack/ingest.js.map +0 -1
  365. package/dist/src/connectors/slack/ratelimit.js +0 -18
  366. package/dist/src/connectors/slack/ratelimit.js.map +0 -1
  367. package/dist/src/connectors/slack/scope.js +0 -13
  368. package/dist/src/connectors/slack/scope.js.map +0 -1
  369. package/dist/src/connectors/slack/signature.js +0 -27
  370. package/dist/src/connectors/slack/signature.js.map +0 -1
  371. package/dist/src/connectors/slack/tenant-routing.js +0 -41
  372. package/dist/src/connectors/slack/tenant-routing.js.map +0 -1
  373. package/dist/src/connectors/slack/transform.js +0 -47
  374. package/dist/src/connectors/slack/transform.js.map +0 -1
  375. package/dist/src/connectors/slack/types.js +0 -35
  376. package/dist/src/connectors/slack/types.js.map +0 -1
  377. package/dist/src/connectors/slack/web-client.js +0 -43
  378. package/dist/src/connectors/slack/web-client.js.map +0 -1
  379. package/dist/src/connectors/slack/workspaces.js +0 -62
  380. package/dist/src/connectors/slack/workspaces.js.map +0 -1
  381. package/dist/src/consolidate.js +0 -978
  382. package/dist/src/consolidate.js.map +0 -1
  383. package/dist/src/correction-latency.js +0 -74
  384. package/dist/src/correction-latency.js.map +0 -1
  385. package/dist/src/customer-notes.js +0 -325
  386. package/dist/src/customer-notes.js.map +0 -1
  387. package/dist/src/dag.js +0 -352
  388. package/dist/src/dag.js.map +0 -1
  389. package/dist/src/dashboard.js +0 -258
  390. package/dist/src/dashboard.js.map +0 -1
  391. package/dist/src/db.js +0 -2731
  392. package/dist/src/db.js.map +0 -1
  393. package/dist/src/decisions.js +0 -304
  394. package/dist/src/decisions.js.map +0 -1
  395. package/dist/src/dedupe.js +0 -141
  396. package/dist/src/dedupe.js.map +0 -1
  397. package/dist/src/embedding-provider.js +0 -314
  398. package/dist/src/embedding-provider.js.map +0 -1
  399. package/dist/src/embeddings.js +0 -543
  400. package/dist/src/embeddings.js.map +0 -1
  401. package/dist/src/eval-suite.js +0 -294
  402. package/dist/src/eval-suite.js.map +0 -1
  403. package/dist/src/eval.js +0 -187
  404. package/dist/src/eval.js.map +0 -1
  405. package/dist/src/extract.js +0 -117
  406. package/dist/src/extract.js.map +0 -1
  407. package/dist/src/forward-claim-detector.js +0 -117
  408. package/dist/src/forward-claim-detector.js.map +0 -1
  409. package/dist/src/goals.js +0 -399
  410. package/dist/src/goals.js.map +0 -1
  411. package/dist/src/graph-extract.js +0 -314
  412. package/dist/src/graph-extract.js.map +0 -1
  413. package/dist/src/graph-recall.js +0 -277
  414. package/dist/src/graph-recall.js.map +0 -1
  415. package/dist/src/graph-stream.js +0 -176
  416. package/dist/src/graph-stream.js.map +0 -1
  417. package/dist/src/graph-view.js +0 -310
  418. package/dist/src/graph-view.js.map +0 -1
  419. package/dist/src/graph.js +0 -762
  420. package/dist/src/graph.js.map +0 -1
  421. package/dist/src/handoff.js +0 -65
  422. package/dist/src/handoff.js.map +0 -1
  423. package/dist/src/hooks.js +0 -926
  424. package/dist/src/hooks.js.map +0 -1
  425. package/dist/src/importers.js +0 -881
  426. package/dist/src/importers.js.map +0 -1
  427. package/dist/src/incidents.js +0 -336
  428. package/dist/src/incidents.js.map +0 -1
  429. package/dist/src/index.js +0 -32
  430. package/dist/src/index.js.map +0 -1
  431. package/dist/src/invalidation.js +0 -129
  432. package/dist/src/invalidation.js.map +0 -1
  433. package/dist/src/mcp/framing.js +0 -45
  434. package/dist/src/mcp/framing.js.map +0 -1
  435. package/dist/src/mcp/server.js +0 -1298
  436. package/dist/src/mcp/server.js.map +0 -1
  437. package/dist/src/memory-value-weights.js +0 -31
  438. package/dist/src/memory-value-weights.js.map +0 -1
  439. package/dist/src/memory-value.js +0 -261
  440. package/dist/src/memory-value.js.map +0 -1
  441. package/dist/src/memory.js +0 -425
  442. package/dist/src/memory.js.map +0 -1
  443. package/dist/src/multihop.js +0 -35
  444. package/dist/src/multihop.js.map +0 -1
  445. package/dist/src/owner-validation.js +0 -56
  446. package/dist/src/owner-validation.js.map +0 -1
  447. package/dist/src/path-context.js +0 -48
  448. package/dist/src/path-context.js.map +0 -1
  449. package/dist/src/physics-config.js +0 -26
  450. package/dist/src/physics-config.js.map +0 -1
  451. package/dist/src/physics-state.js +0 -172
  452. package/dist/src/physics-state.js.map +0 -1
  453. package/dist/src/physics.js +0 -378
  454. package/dist/src/physics.js.map +0 -1
  455. package/dist/src/policies.js +0 -414
  456. package/dist/src/policies.js.map +0 -1
  457. package/dist/src/postinstall.js +0 -101
  458. package/dist/src/postinstall.js.map +0 -1
  459. package/dist/src/predictions.js +0 -629
  460. package/dist/src/predictions.js.map +0 -1
  461. package/dist/src/processes.js +0 -349
  462. package/dist/src/processes.js.map +0 -1
  463. package/dist/src/project-briefs.js +0 -492
  464. package/dist/src/project-briefs.js.map +0 -1
  465. package/dist/src/project-identity.js +0 -200
  466. package/dist/src/project-identity.js.map +0 -1
  467. package/dist/src/provenance-coverage.js +0 -23
  468. package/dist/src/provenance-coverage.js.map +0 -1
  469. package/dist/src/rate-limit.js +0 -60
  470. package/dist/src/rate-limit.js.map +0 -1
  471. package/dist/src/raw-archive-mirror-cleanup.js +0 -55
  472. package/dist/src/raw-archive-mirror-cleanup.js.map +0 -1
  473. package/dist/src/raw-archive.js +0 -91
  474. package/dist/src/raw-archive.js.map +0 -1
  475. package/dist/src/recall-history.js +0 -235
  476. package/dist/src/recall-history.js.map +0 -1
  477. package/dist/src/recall-scope.js +0 -89
  478. package/dist/src/recall-scope.js.map +0 -1
  479. package/dist/src/recall-trace.js +0 -186
  480. package/dist/src/recall-trace.js.map +0 -1
  481. package/dist/src/refine-llm.js +0 -156
  482. package/dist/src/refine-llm.js.map +0 -1
  483. package/dist/src/reject-flow.js +0 -209
  484. package/dist/src/reject-flow.js.map +0 -1
  485. package/dist/src/rejection.js +0 -160
  486. package/dist/src/rejection.js.map +0 -1
  487. package/dist/src/replay.js +0 -122
  488. package/dist/src/replay.js.map +0 -1
  489. package/dist/src/rerankers/cross-encoder.js +0 -137
  490. package/dist/src/rerankers/cross-encoder.js.map +0 -1
  491. package/dist/src/rerankers/index.js +0 -20
  492. package/dist/src/rerankers/index.js.map +0 -1
  493. package/dist/src/rerankers/jev.js +0 -119
  494. package/dist/src/rerankers/jev.js.map +0 -1
  495. package/dist/src/rerankers/llm.js +0 -80
  496. package/dist/src/rerankers/llm.js.map +0 -1
  497. package/dist/src/rerankers/types.js +0 -2
  498. package/dist/src/rerankers/types.js.map +0 -1
  499. package/dist/src/rrf.js +0 -61
  500. package/dist/src/rrf.js.map +0 -1
  501. package/dist/src/salience.js +0 -74
  502. package/dist/src/salience.js.map +0 -1
  503. package/dist/src/scheduler.js +0 -77
  504. package/dist/src/scheduler.js.map +0 -1
  505. package/dist/src/scope.js +0 -35
  506. package/dist/src/scope.js.map +0 -1
  507. package/dist/src/search.js +0 -1003
  508. package/dist/src/search.js.map +0 -1
  509. package/dist/src/secret-detect.js +0 -95
  510. package/dist/src/secret-detect.js.map +0 -1
  511. package/dist/src/server-detect.js +0 -231
  512. package/dist/src/server-detect.js.map +0 -1
  513. package/dist/src/server.js +0 -3255
  514. package/dist/src/server.js.map +0 -1
  515. package/dist/src/shared.js +0 -502
  516. package/dist/src/shared.js.map +0 -1
  517. package/dist/src/skills.js +0 -346
  518. package/dist/src/skills.js.map +0 -1
  519. package/dist/src/sleep-redact.js +0 -80
  520. package/dist/src/sleep-redact.js.map +0 -1
  521. package/dist/src/sso.js +0 -22
  522. package/dist/src/sso.js.map +0 -1
  523. package/dist/src/stdin.js +0 -41
  524. package/dist/src/stdin.js.map +0 -1
  525. package/dist/src/store.js +0 -3749
  526. package/dist/src/store.js.map +0 -1
  527. package/dist/src/tenant.js +0 -17
  528. package/dist/src/tenant.js.map +0 -1
  529. package/dist/src/trace.js +0 -72
  530. package/dist/src/trace.js.map +0 -1
  531. package/dist/src/version.js +0 -40
  532. package/dist/src/version.js.map +0 -1
  533. package/dist/src/working-memory.js +0 -157
  534. package/dist/src/working-memory.js.map +0 -1
  535. package/dist/src/yaml.js +0 -107
  536. package/dist/src/yaml.js.map +0 -1
  537. package/dist/sso.d.ts +0 -13
  538. package/dist/sso.d.ts.map +0 -1
  539. package/dist/sso.js +0 -22
  540. package/dist/sso.js.map +0 -1
  541. package/dist/stdin.d.ts.map +0 -1
  542. package/dist/stdin.js.map +0 -1
  543. package/dist/store.d.ts.map +0 -1
  544. package/dist/store.js.map +0 -1
  545. package/dist/tenant.d.ts.map +0 -1
  546. package/dist/tenant.js.map +0 -1
  547. package/dist/trace.d.ts.map +0 -1
  548. package/dist/trace.js.map +0 -1
  549. package/dist/version.d.ts.map +0 -1
  550. package/dist/version.js.map +0 -1
  551. package/dist/working-memory.d.ts.map +0 -1
  552. package/dist/working-memory.js.map +0 -1
  553. package/dist/yaml.d.ts.map +0 -1
  554. package/dist/yaml.js.map +0 -1
package/dist/search.js CHANGED
@@ -2,8 +2,9 @@
2
2
  * BM25 search + optional embedding hybrid search for Hippo.
3
3
  * Zero external dependencies when embeddings are not available.
4
4
  */
5
- import { calculateStrength } from './memory.js';
6
- import { isOutcomeFastAblated, isRecallBoostAblated, evalNow } from './ablation.js';
5
+ import { estimateTokens } from './token-ledger.js';
6
+ import { calculateStrength, netWrong } from './memory.js';
7
+ import { isOutcomeFastAblated, isRecallBoostAblated, isRecencyAblated, evalRecencyScaleDays, evalNow } from './ablation.js';
7
8
  import { extractPathTags, pathBoostMultiplier } from './path-context.js';
8
9
  import { detectScope, scopeMatch } from './scope.js';
9
10
  import { cosineSimilarity, embeddingModelRequiresReindex, loadEmbeddingIndex, } from './embeddings.js';
@@ -68,20 +69,28 @@ function bm25Score(corpus, docIdx, queryTerms) {
68
69
  // ---------------------------------------------------------------------------
69
70
  // Token budget estimation
70
71
  // ---------------------------------------------------------------------------
71
- /**
72
- * Rough token estimate: characters / 4 (works well for English text).
73
- */
74
- export function estimateTokens(text) {
75
- return Math.ceil(text.length / 4);
76
- }
72
+ // Rough token estimate (characters / 4). Defined once in token-ledger.ts and
73
+ // re-exported here, where callers have always imported it from.
74
+ export { estimateTokens };
77
75
  // ---------------------------------------------------------------------------
78
76
  // Recency boost
79
77
  // ---------------------------------------------------------------------------
80
78
  function recencyBoost(entry, now) {
79
+ if (isRecencyAblated())
80
+ return 1; // EVAL-ONLY ablation (see ablation.ts)
81
81
  const created = new Date(entry.created);
82
82
  const ageDays = (now.getTime() - created.getTime()) / (1000 * 60 * 60 * 24);
83
83
  // Exponential decay: memories < 1 day get boost ~1.0, older get less
84
- return Math.exp(-ageDays / 30);
84
+ return Math.exp(-ageDays / (evalRecencyScaleDays() ?? 30));
85
+ }
86
+ /** Retrieval-time outcome nudge in [0.85, 1.15]; the E1 bm25-outcome baseline ranks with it too. */
87
+ export function outcomeMultiplier(entry) {
88
+ const pos = entry.outcome_positive ?? 0;
89
+ const neg = entry.outcome_negative ?? 0;
90
+ // EVAL-ONLY ablation (see ablation.ts): the fast outcome channel.
91
+ if (isOutcomeFastAblated() || (pos === 0 && neg === 0))
92
+ return 1.0;
93
+ return Math.max(0.85, Math.min(1.15, 1 + 0.15 * Math.tanh((pos - neg) / 2)));
85
94
  }
86
95
  // ---------------------------------------------------------------------------
87
96
  // Temporal-aware scoring
@@ -237,8 +246,8 @@ export async function hybridSearch(query, entries, options = {}) {
237
246
  if (options.hippoRoot) {
238
247
  try {
239
248
  const provider = resolveEmbeddingProvider(options.hippoRoot);
240
- if (provider.isAvailable() && !embeddingModelRequiresReindex(options.hippoRoot, provider.id)) {
241
- const idx = loadEmbeddingIndex(options.hippoRoot);
249
+ const idx = provider.isAvailable() ? loadEmbeddingIndex(options.hippoRoot) : {};
250
+ if (provider.isAvailable() && !embeddingModelRequiresReindex(options.hippoRoot, provider.id, idx)) {
242
251
  // Only spend a (possibly paid, off-box) query embedding when at least one
243
252
  // of THIS search's entries has a cached vector to compare against. An
244
253
  // index of only orphaned / out-of-scope vectors yields a meaningless
@@ -364,12 +373,7 @@ export async function hybridSearch(query, entries, options = {}) {
364
373
  compositeScore *= pathBoost;
365
374
  // Retrieval-time outcome personalization: nudge up/down from user feedback.
366
375
  // Distinct from reward-factor-via-strength (slow); this is immediate.
367
- // EVAL-ONLY ablation (see ablation.ts): the fast outcome channel.
368
- const pos = entries[i].outcome_positive ?? 0;
369
- const neg = entries[i].outcome_negative ?? 0;
370
- const outcomeBoost = isOutcomeFastAblated() || (pos === 0 && neg === 0)
371
- ? 1.0
372
- : Math.max(0.85, Math.min(1.15, 1 + 0.15 * Math.tanh((pos - neg) / 2)));
376
+ const outcomeBoost = outcomeMultiplier(entries[i]);
373
377
  compositeScore *= outcomeBoost;
374
378
  // Scope boost: memories tagged with the active scope get 1.5x; mismatching scopes get 0.5x
375
379
  const scopeSignal = scopeMatch(entries[i].tags, activeScope);
@@ -511,7 +515,7 @@ export async function hybridSearch(query, entries, options = {}) {
511
515
  const head = ordered.slice(0, topK);
512
516
  const tail = ordered.slice(topK);
513
517
  const rerankInputWithRank = head.map((r, i) => ({ ...r, preRerankRank: i + 1 }));
514
- const reranked = await options.reranker(query, rerankInputWithRank, options.rerankerOptions);
518
+ const reranked = await options.reranker(query, rerankInputWithRank, { ...options.rerankerOptions, topK });
515
519
  const withPostRank = reranked.map((r, i) => ({ ...r, postRerankRank: i + 1 }));
516
520
  ordered = [...withPostRank, ...tail];
517
521
  }
@@ -929,12 +933,13 @@ export function markRetrieved(entries, now = evalNow()) {
929
933
  return entries.map((e) => {
930
934
  if (e.superseded_by)
931
935
  return e;
936
+ const wrong = netWrong(e) > 0;
932
937
  const updated = {
933
938
  ...e,
934
939
  retrieval_count: e.retrieval_count + 1,
935
- last_retrieved: now.toISOString(),
936
- // Extend half-life by +2 days per retrieval (PLAN.md)
937
- half_life_days: e.half_life_days + 2,
940
+ last_retrieved: wrong ? e.last_retrieved : now.toISOString(),
941
+ // +2 days half-life per retrieval (PLAN.md); a wrong memory keeps both, since last_retrieved is the decay anchor
942
+ half_life_days: wrong ? e.half_life_days : e.half_life_days + 2,
938
943
  };
939
944
  updated.strength = calculateStrength(updated, now);
940
945
  return updated;
package/dist/server.d.ts CHANGED
@@ -15,6 +15,8 @@ export interface ServeOpts {
15
15
  hippoRoot: string;
16
16
  port?: number;
17
17
  host?: string;
18
+ /** Stop and exit on SIGINT/SIGTERM. Only `hippo serve` owns the process, so only it sets this. */
19
+ handleSignals?: boolean;
18
20
  }
19
21
  /**
20
22
  * Recognise loopback remote addresses. Node reports IPv6-mapped IPv4 as
@@ -22,6 +24,9 @@ export interface ServeOpts {
22
24
  * the bare v4 and v6 loopbacks. Anything else is treated as remote.
23
25
  */
24
26
  export declare function isLoopback(remoteAddress: string | undefined): boolean;
27
+ export declare const LOOPBACK_HOST_HEADER: RegExp;
28
+ /** A browser request sent by another site. Non-browser clients send neither header and pass. */
29
+ export declare function isCrossSite(req: IncomingMessage): boolean;
25
30
  /**
26
31
  * Rate-limit key for a request. Defaults to the socket's remote address.
27
32
  *
package/dist/server.js CHANGED
@@ -22,7 +22,7 @@ export function __resetSessionRecallHistoryHttp() {
22
22
  import { PACKAGE_VERSION } from './version.js';
23
23
  import { validateApiKey } from './auth.js';
24
24
  import { createRateLimiter } from './rate-limit.js';
25
- import { remember, recall, RecallContractError, drillDown, assemble, forget, promote, supersede, archiveRaw, authCreate, authList, authRevoke, auditList, outcome, outcomeForLastRecall, getContext, sleep, adminActor, } from './api.js';
25
+ import { remember, retrieve, RecallContractError, ForbiddenError, drillDown, assemble, forget, promote, supersede, archiveRaw, authCreate, authList, authRevoke, auditList, outcome, outcomeForLastRecall, getContext, sleep, adminActor, recordTokens, } from './api.js';
26
26
  import { buildGraphModel } from './graph-view.js';
27
27
  import { MAX_ENTITY_NAME_LEN } from './graph.js';
28
28
  import { savePrediction, closePrediction, loadPredictionById, loadPredictionsByClass, loadOpenPredictions, computePredictionBaserate, VALID_CLOSURE_STATES, } from './predictions.js';
@@ -114,6 +114,8 @@ const VALID_AUDIT_OPS = new Set([
114
114
  'reject_refusal', // AT1 — emitted when the rejection guard refuses a write; lockstep
115
115
  'unreject_value', // AT1 — emitted by `hippo unreject`; lockstep
116
116
  'conflict_resolve', // AT1 — emitted by resolveConflict on every resolution path; lockstep
117
+ 'half_life_migrate', // Decay default change — emitted by migrateDefaultHalfLife; lockstep with AuditOp union
118
+ 'dormant_restore', // Dormant memories — emitted by api.restoreDormant; lockstep with AuditOp union + cli.ts VALID_AUDIT_OPS
117
119
  ]);
118
120
  // Cap on GET /v1/audit?limit=. Matches docs/api.md (when written) and is large
119
121
  // enough to dump a small deployment's full audit log without paginating, but
@@ -289,10 +291,13 @@ async function parseJsonBody(req) {
289
291
  * - /unknown/i → 404 (auth_revoke on unknown key_id)
290
292
  * - /already superseded/i → 409 (chain conflict)
291
293
  * - /not raw/i → 400 (archive_raw on non-raw row)
292
- * Everything else maps to 400 (bad input).
294
+ * ForbiddenError maps to 403; everything else to 400 (bad input).
293
295
  */
294
296
  function mapApiError(err) {
295
297
  const message = err instanceof Error ? err.message : String(err);
298
+ if (err instanceof ForbiddenError) {
299
+ return { status: 403, message };
300
+ }
296
301
  const lower = message.toLowerCase();
297
302
  if (/not found/.test(lower) || /^unknown /.test(lower)) {
298
303
  return { status: 404, message };
@@ -300,6 +305,9 @@ function mapApiError(err) {
300
305
  if (/already superseded/.test(lower)) {
301
306
  return { status: 409, message };
302
307
  }
308
+ if (/requires admin role/.test(lower)) {
309
+ return { status: 403, message };
310
+ }
303
311
  return { status: 400, message };
304
312
  }
305
313
  function parseRequest(req) {
@@ -354,6 +362,25 @@ export function isLoopback(remoteAddress) {
354
362
  return true;
355
363
  return false;
356
364
  }
365
+ // Any other Host on a loopback socket is DNS rebinding: a hostile page resolved to 127.0.0.1.
366
+ export const LOOPBACK_HOST_HEADER = /^(localhost|127\.0\.0\.1|\[::1\])(:\d+)?$/i;
367
+ /** A browser request sent by another site. Non-browser clients send neither header and pass. */
368
+ export function isCrossSite(req) {
369
+ const site = req.headers['sec-fetch-site'];
370
+ if (site !== undefined && site !== 'same-origin' && site !== 'none')
371
+ return true;
372
+ const origin = req.headers.origin;
373
+ return origin !== undefined && origin !== `http://${req.headers.host}`;
374
+ }
375
+ // A browser on this machine is loopback too, so the no-key fallback also needs a local Host and a same-site caller.
376
+ function assertLocalCaller(req) {
377
+ if (!isLoopback(req.socket.remoteAddress))
378
+ throw new HttpError(401, 'auth required');
379
+ const host = req.headers.host;
380
+ if ((host !== undefined && !LOOPBACK_HOST_HEADER.test(host)) || isCrossSite(req)) {
381
+ throw new HttpError(403, 'cross-site or non-local request refused; send an API key');
382
+ }
383
+ }
357
384
  function readAuthHeader(req) {
358
385
  const raw = req.headers['authorization'];
359
386
  if (raw === undefined)
@@ -455,9 +482,7 @@ function buildContextWithAuth(req, hippoRoot) {
455
482
  if (process.env.HIPPO_REQUIRE_AUTH === '1') {
456
483
  throw new HttpError(401, 'auth required');
457
484
  }
458
- if (!isLoopback(req.socket.remoteAddress)) {
459
- throw new HttpError(401, 'auth required');
460
- }
485
+ assertLocalCaller(req);
461
486
  // v1.12.0: loopback fallback is process-local, treat as admin.
462
487
  return {
463
488
  hippoRoot,
@@ -492,9 +517,7 @@ function requireAuth(req, hippoRoot) {
492
517
  if (process.env.HIPPO_REQUIRE_AUTH === '1') {
493
518
  throw new HttpError(401, 'auth required');
494
519
  }
495
- if (!isLoopback(req.socket.remoteAddress)) {
496
- throw new HttpError(401, 'auth required');
497
- }
520
+ assertLocalCaller(req);
498
521
  }
499
522
  function getString(obj, key) {
500
523
  const v = obj[key];
@@ -632,10 +655,7 @@ async function handleRequest(req, res, opts, startedAt, limiter) {
632
655
  throw new HttpError(400, 'q is required');
633
656
  }
634
657
  const limitRaw = query.get('limit');
635
- const limit = limitRaw === null ? undefined : Number(limitRaw);
636
- if (limit !== undefined && (!Number.isFinite(limit) || limit <= 0)) {
637
- throw new HttpError(400, 'limit must be a positive number');
638
- }
658
+ const limit = limitRaw === null ? undefined : parseListLimit(limitRaw);
639
659
  const mode = query.get('mode');
640
660
  if (mode !== null && mode !== 'bm25' && mode !== 'hybrid' && mode !== 'physics') {
641
661
  throw new HttpError(400, "mode must be 'bm25', 'hybrid', or 'physics'");
@@ -671,11 +691,12 @@ async function handleRequest(req, res, opts, startedAt, limiter) {
671
691
  const summarizeOverflow = summarizeOverflowRaw === null
672
692
  ? undefined
673
693
  : (summarizeOverflowRaw === '1' || summarizeOverflowRaw === 'true');
674
- // v1.7.2 T4: forward as Number(...) — NaN, 0, negative all reach
675
- // recall() which throws RecallContractError with code='invalid_scorer_window'.
676
- // No transport-side validation; recall() owns the contract.
694
+ // recall() owns the shape rule (NaN, 0 and negatives throw invalid_scorer_window); the transport caps remote cost.
677
695
  const scorerWindowRaw = query.get('scorer_window');
678
696
  const scorerWindow = scorerWindowRaw === null ? undefined : Number(scorerWindowRaw);
697
+ if (scorerWindow !== undefined && scorerWindow > 1000) {
698
+ throw new HttpError(400, 'scorer_window must be <= 1000');
699
+ }
679
700
  // v1.7.4: session_id for the dlPFC goal-stack boost. 256-char cap mirrors
680
701
  // fresh_tail_session_id (above). Trim then drop if empty so api.recall
681
702
  // sees undefined when the param is omitted or whitespace-only.
@@ -757,7 +778,7 @@ async function handleRequest(req, res, opts, startedAt, limiter) {
757
778
  recallExtra.recallHistory = httpRecallHistory;
758
779
  if (explain)
759
780
  recallExtra.explain = explain;
760
- const result = recall(ctx, {
781
+ const result = await retrieve(ctx, {
761
782
  query: q,
762
783
  limit,
763
784
  mode: mode ?? undefined,
@@ -785,6 +806,7 @@ async function handleRequest(req, res, opts, startedAt, limiter) {
785
806
  if (includeContinuity) {
786
807
  res.setHeader('Cache-Control', 'no-store');
787
808
  }
809
+ recordTokens(ctx, 'http_recall', { items: result.results.length, tokens: result.tokens + (result.continuityTokens ?? 0), sessionId: sessionId ?? null });
788
810
  sendJson(res, 200, result);
789
811
  return;
790
812
  }
@@ -826,6 +848,7 @@ async function handleRequest(req, res, opts, startedAt, limiter) {
826
848
  if (scope !== undefined)
827
849
  assembleExtra.scope = scope;
828
850
  const result = assemble(ctx, assembleMatch.id, assembleExtra);
851
+ recordTokens(ctx, 'http_assemble', { items: result.items.length, tokens: result.tokens, sessionId: assembleMatch.id });
829
852
  sendJson(res, 200, result);
830
853
  return;
831
854
  }
@@ -1026,6 +1049,7 @@ async function handleRequest(req, res, opts, startedAt, limiter) {
1026
1049
  crossProject,
1027
1050
  currentProject: resolveProjectIdentity(dirname(resolve(opts.hippoRoot))).name,
1028
1051
  });
1052
+ recordTokens(ctx, 'http_context', { items: result.entries.length, tokens: result.tokens });
1029
1053
  sendJson(res, 200, result);
1030
1054
  return;
1031
1055
  }
@@ -1038,7 +1062,8 @@ async function handleRequest(req, res, opts, startedAt, limiter) {
1038
1062
  // Tenant scope (Episode A follow-up tracked in TODOS.md): api.sleep operates
1039
1063
  // on the WHOLE hippoRoot (cross-tenant by design, matching CLI cmdSleep).
1040
1064
  // The loopback-only guard is the trust boundary today. Future non-loopback
1041
- // serving needs an admin-role gate before exposing this route.
1065
+ // serving must also zero the cross-tenant counters for other tenants
1066
+ // (D1 in docs/decisions/2026-05-24-blocked-items.md).
1042
1067
  if (method === 'POST' && path === '/v1/sleep') {
1043
1068
  // Defensive per-request loopback guard. Uses the canonical isLoopback()
1044
1069
  // helper above so any future extension (additional mapped/IPv6 forms,
@@ -1084,11 +1109,7 @@ async function handleRequest(req, res, opts, startedAt, limiter) {
1084
1109
  }
1085
1110
  // v1.12.3: optional body.role mirrors the --role CLI flag. Validated
1086
1111
  // strictly — anything other than 'admin'|'member' is a 400 (no silent
1087
- // fallback to admin). Required note: admin Bearer can mint a member
1088
- // key for the same tenant; member Bearer minting an admin key is NOT
1089
- // blocked here today (auth_create is currently unaudited per the A5 v2
1090
- // note in authCreate doc). The HTTP layer trusts the buildContextWithAuth
1091
- // role check at admin-gated routes; mint surface remains permissive.
1112
+ // fallback to admin). authCreate refuses a member caller with a 403.
1092
1113
  const roleRaw = body['role'];
1093
1114
  let role;
1094
1115
  if (roleRaw !== undefined) {
@@ -1128,10 +1149,9 @@ async function handleRequest(req, res, opts, startedAt, limiter) {
1128
1149
  sendJson(res, 200, result);
1129
1150
  return;
1130
1151
  }
1131
- // DELETE /v1/auth/keys/:keyId — revoke. authRevoke throws "Unknown key_id"
1132
- // for missing OR cross-tenant keys (no info leak), which mapApiError
1133
- // converts to 404. We return 200 with the result body rather than 204 to
1134
- // surface revokedAt to the caller.
1152
+ // DELETE /v1/auth/keys/:keyId — revoke. Missing or cross-tenant keys are 404
1153
+ // (no info leak); a member key targeting any key but its own is 403.
1154
+ // 200 with the body rather than 204 so the caller sees revokedAt.
1135
1155
  const keyMatch = matchPath('/v1/auth/keys/:keyId', path);
1136
1156
  if (method === 'DELETE' && keyMatch) {
1137
1157
  validateIdSegment(keyMatch.keyId, 'key id');
@@ -2999,6 +3019,8 @@ async function handleRequest(req, res, opts, startedAt, limiter) {
2999
3019
  tenantId: ctx.tenantId,
3000
3020
  // v1.12.0: McpContext.actor stays string; extract subject at the boundary.
3001
3021
  actor: ctx.actor.subject,
3022
+ // The caller's real role: MCP tools must not run a member key as admin.
3023
+ role: ctx.actor.role,
3002
3024
  clientKey: buildMcpClientKey(req),
3003
3025
  });
3004
3026
  }
@@ -3228,9 +3250,7 @@ export async function serve(opts) {
3228
3250
  server.close(() => resolve());
3229
3251
  });
3230
3252
  };
3231
- // Skip signal handlers under vitest so each test run does not register a
3232
- // stray SIGTERM/SIGINT listener that survives until the runner exits.
3233
- if (!process.env.VITEST) {
3253
+ if (opts.handleSignals) {
3234
3254
  let shuttingDown = false;
3235
3255
  const gracefulShutdown = async (signal) => {
3236
3256
  if (shuttingDown)
package/dist/shared.js CHANGED
@@ -153,7 +153,7 @@ export async function searchBothHybrid(query, localRoot, globalRoot, options = {
153
153
  if (!fs.existsSync(root))
154
154
  return [];
155
155
  return recallScope
156
- ? loadRecallSearchEntries(root, query, searchWindow, tenantId, recallScope.requested, recallScope.additive ? 'additive' : 'exact')
156
+ ? loadRecallSearchEntries(root, query, searchWindow, tenantId, recallScope.requested, recallScope.additive ? 'additive' : 'exact', Boolean(includeSuperseded) || Boolean(asOf))
157
157
  : loadSearchEntries(root, query, searchWindow, tenantId);
158
158
  };
159
159
  let localEntries = loadEntries(localRoot);
package/dist/store.d.ts CHANGED
@@ -10,6 +10,7 @@ import { SessionHandoff, HandoffEvidence, HandoffOutcome } from './handoff.js';
10
10
  import { Card, CardStatus, CardRun, CardComment } from './card.js';
11
11
  import { type ResolveProjectIdentityOpts } from './project-identity.js';
12
12
  import { RejectedValueError } from './rejection.js';
13
+ import { type DormantMove } from './dormant.js';
13
14
  /** A value that round-trips through JSON.stringify/JSON.parse unchanged. */
14
15
  type JsonValue = string | number | boolean | null | JsonValue[] | {
15
16
  [key: string]: JsonValue;
@@ -108,6 +109,8 @@ export declare function assertNonEmpty<T>(arr: readonly T[], name: string): void
108
109
  export declare function getHippoRoot(cwd?: string, opts?: ResolveProjectIdentityOpts): string;
109
110
  export declare function isInitialized(hippoRoot: string): boolean;
110
111
  export declare function initStore(hippoRoot: string): void;
112
+ /** `meta` key holding the default half-life base a store's memories are on (src/half-life-migration.ts). */
113
+ export declare const HALF_LIFE_BASE_META_KEY = "default_half_life_base";
111
114
  /**
112
115
  * Serialize a MemoryEntry to markdown with YAML frontmatter.
113
116
  */
@@ -203,9 +206,7 @@ export declare function buildIndexFromDb(db: ReturnType<typeof openHippoDb>): Hi
203
206
  * `buildIndexFromDb`'s query.
204
207
  */
205
208
  export declare function writeIndexMirror(hippoRoot: string, index: HippoIndex): void;
206
- /**
207
- * Load the current derived index from SQLite and refresh the mirror file.
208
- */
209
+ /** Load the derived index from SQLite. Read-only: writers refresh index.json, so readers never race on it. */
209
210
  export declare function loadIndex(hippoRoot: string): HippoIndex;
210
211
  /**
211
212
  * Persist mutable index metadata. Entry rows themselves are derived from SQLite.
@@ -298,6 +299,9 @@ export declare function readEntry(hippoRoot: string, id: string, tenantId?: stri
298
299
  * to fetch parent summaries for a set of overflowed leaves.
299
300
  */
300
301
  export declare function loadEntriesByIds(hippoRoot: string, ids: readonly string[], tenantId?: string): MemoryEntry[];
302
+ /** Strengthen what a read returned: update only the four retrieval columns on the live row, never a stale copy.
303
+ * Best effort: a failure logs and never fails the read. Returns the ids found in this store. */
304
+ export declare function strengthenRetrieved(hippoRoot: string, ids: readonly string[], tenantId?: string): Set<string>;
301
305
  /**
302
306
  * All `kind='raw'` rows for a given session, tenant-scoped, returned
303
307
  * oldest-first. Used by `api.assemble` to walk a session's chronological
@@ -375,12 +379,14 @@ export declare function loadChildrenOf(hippoRoot: string, parentId: string, tena
375
379
  * removed) and `resolveConflict` (`conflict_resolve` row per resolution).
376
380
  * Default keeps `deleteEntry` byte-identical to its pre-split behavior.
377
381
  *
378
- * Returns `{tenantId, dagParentId}` for the removed row, or `null` if no row
379
- * with `id` existed.
382
+ * Returns `{tenantId, dagParentId}` for the removed row, or `null` if no row with `id`
383
+ * existed or `automatic` refused it (pinned or raw at DELETE time, so a late pin wins).
380
384
  */
381
385
  export declare function deleteEntryCore(db: ReturnType<typeof openHippoDb>, id: string, opts?: {
382
386
  actor?: string;
383
387
  suppressForgetAudit?: boolean;
388
+ reason?: string;
389
+ automatic?: boolean;
384
390
  }): {
385
391
  tenantId: string;
386
392
  dagParentId: string | null;
@@ -398,12 +404,20 @@ export declare function deleteEntryCore(db: ReturnType<typeof openHippoDb>, id:
398
404
  */
399
405
  export declare function deleteEntry(hippoRoot: string, id: string, opts?: {
400
406
  actor?: string;
407
+ reason?: string;
408
+ automatic?: boolean;
401
409
  }): boolean;
402
- /**
403
- * Batch-write and batch-delete entries in a single transaction.
404
- * Used by consolidation to avoid N open/close cycles.
405
- */
406
- export declare function batchWriteAndDelete(hippoRoot: string, toWrite: MemoryEntry[], toDeleteIds: string[]): void;
410
+ /** Consolidation's flush, one transaction. With `snapshot` (rows as the caller loaded them), a write keeps only
411
+ * the fields the caller changed, takes the rest from the live row, and never resurrects a row that is gone.
412
+ *
413
+ * `dormant` (src/dormant.ts): each move's snapshot is inserted into `dormant_memories` and its `memories` row
414
+ * leaves exactly like a delete (FTS row, DAG parent dirty-mark, mirrors), in the same transaction, so a memory
415
+ * is never in both places or in neither. Deletes and moves both skip rows that are no longer auto-deletable
416
+ * (pinned or raw since the caller decided). Returns the ids that left `memories`, deleted or moved. */
417
+ export declare function batchWriteAndDelete(hippoRoot: string, toWrite: MemoryEntry[], toDeleteIds: string[], opts?: {
418
+ snapshot?: ReadonlyMap<string, MemoryEntry>;
419
+ dormant?: DormantMove[];
420
+ }): string[];
407
421
  /**
408
422
  * Load all entries from SQLite.
409
423
  *
@@ -412,6 +426,8 @@ export declare function batchWriteAndDelete(hippoRoot: string, toWrite: MemoryEn
412
426
  * paths that surface results to a user MUST pass a resolved tenant.
413
427
  */
414
428
  export declare function loadAllEntries(hippoRoot: string, tenantId?: string): MemoryEntry[];
429
+ /** Every memory row on an open connection, so a caller can read inside its own transaction. */
430
+ export declare function selectAllEntries(db: DatabaseSyncLike, tenantId?: string): MemoryEntry[];
415
431
  export declare function loadAmbientCandidates(hippoRoot: string, tenantId: string, recentNeeded: number, admit: (e: MemoryEntry) => boolean): MemoryEntry[];
416
432
  /**
417
433
  * Load likely search candidates directly from SQLite.
@@ -445,7 +461,7 @@ export declare function loadSearchEntries(hippoRoot: string, query: string, limi
445
461
  * mode (its `tenantId` option is optional); `loadSearchRows` already treats
446
462
  * undefined as "no tenant filter" for legacy callers.
447
463
  */
448
- export declare function loadRecallSearchEntries(hippoRoot: string, query: string, limit?: number, tenantId?: string, requestedScope?: string, explicitScopeMode?: 'exact' | 'additive'): MemoryEntry[];
464
+ export declare function loadRecallSearchEntries(hippoRoot: string, query: string, limit?: number, tenantId?: string, requestedScope?: string, explicitScopeMode?: 'exact' | 'additive', includeSuperseded?: boolean): MemoryEntry[];
449
465
  /**
450
466
  * Rebuild mirrors from SQLite, importing any legacy markdown files not already present.
451
467
  */
@@ -462,6 +478,8 @@ export declare function appendConsolidationRun(hippoRoot: string, run: {
462
478
  merged: number;
463
479
  removed: number;
464
480
  }): void;
481
+ /** Rows a tenant created since the last sleep (runs are host-wide), looking back at most 24 hours. */
482
+ export declare function countCreatedSinceLastSleep(hippoRoot: string, tenantId: string, now?: Date): number;
465
483
  /**
466
484
  * Session decay context: provides the data needed for session-based and adaptive decay.
467
485
  */