hippo-memory 1.44.0 → 1.45.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 (528) hide show
  1. package/README.md +12 -10
  2. package/bin/hippo.js +3 -1
  3. package/dist/api.d.ts +21 -21
  4. package/dist/api.js +69 -42
  5. package/dist/audit.d.ts +1 -1
  6. package/dist/audit.js +9 -0
  7. package/dist/autolearn.d.ts +1 -1
  8. package/dist/autolearn.js +2 -1
  9. package/dist/cli.d.ts +3 -0
  10. package/dist/cli.js +151 -72
  11. package/dist/client.d.ts +4 -21
  12. package/dist/client.js +3 -112
  13. package/dist/config.js +2 -1
  14. package/dist/consolidate.d.ts +3 -0
  15. package/dist/consolidate.js +44 -42
  16. package/dist/dag.d.ts +1 -0
  17. package/dist/dag.js +10 -5
  18. package/dist/dashboard.js +7 -3
  19. package/dist/db.js +12 -23
  20. package/dist/dedupe.d.ts +1 -0
  21. package/dist/dedupe.js +4 -7
  22. package/dist/embedding-provider.js +2 -1
  23. package/dist/embeddings.js +81 -8
  24. package/dist/extract.d.ts +2 -0
  25. package/dist/extract.js +9 -4
  26. package/dist/mcp/server.js +21 -36
  27. package/dist/memory.d.ts +3 -0
  28. package/dist/memory.js +7 -1
  29. package/dist/refine-llm.js +3 -2
  30. package/dist/rerankers/jev.js +3 -2
  31. package/dist/rerankers/llm.js +3 -2
  32. package/dist/search.js +3 -3
  33. package/dist/server.d.ts +5 -0
  34. package/dist/server.js +39 -29
  35. package/dist/shared.js +1 -1
  36. package/dist/store.d.ts +18 -11
  37. package/dist/store.js +144 -63
  38. package/dist/version.d.ts +4 -6
  39. package/dist/version.js +4 -7
  40. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  41. package/extensions/openclaw-plugin/package.json +1 -1
  42. package/openclaw.plugin.json +1 -1
  43. package/package.json +6 -3
  44. package/dist/ablation.d.ts.map +0 -1
  45. package/dist/ablation.js.map +0 -1
  46. package/dist/ambient.d.ts.map +0 -1
  47. package/dist/ambient.js.map +0 -1
  48. package/dist/api.d.ts.map +0 -1
  49. package/dist/api.js.map +0 -1
  50. package/dist/audit-prune.d.ts.map +0 -1
  51. package/dist/audit-prune.js.map +0 -1
  52. package/dist/audit.d.ts.map +0 -1
  53. package/dist/audit.js.map +0 -1
  54. package/dist/auth.d.ts.map +0 -1
  55. package/dist/auth.js.map +0 -1
  56. package/dist/autolearn.d.ts.map +0 -1
  57. package/dist/autolearn.js.map +0 -1
  58. package/dist/availability.d.ts.map +0 -1
  59. package/dist/availability.js.map +0 -1
  60. package/dist/benchmarks/e1.3/incident-recall-eval.js +0 -78
  61. package/dist/benchmarks/e1.3/incident-recall-eval.js.map +0 -1
  62. package/dist/benchmarks/e1.3/slack-1000-event-smoke.js +0 -103
  63. package/dist/benchmarks/e1.3/slack-1000-event-smoke.js.map +0 -1
  64. package/dist/capture.d.ts.map +0 -1
  65. package/dist/capture.js.map +0 -1
  66. package/dist/card-detail.d.ts.map +0 -1
  67. package/dist/card-detail.js.map +0 -1
  68. package/dist/card.d.ts.map +0 -1
  69. package/dist/card.js.map +0 -1
  70. package/dist/cli.d.ts.map +0 -1
  71. package/dist/cli.js.map +0 -1
  72. package/dist/client.d.ts.map +0 -1
  73. package/dist/client.js.map +0 -1
  74. package/dist/compare.d.ts.map +0 -1
  75. package/dist/compare.js.map +0 -1
  76. package/dist/config.d.ts.map +0 -1
  77. package/dist/config.js.map +0 -1
  78. package/dist/connectors/github/backfill.d.ts.map +0 -1
  79. package/dist/connectors/github/backfill.js.map +0 -1
  80. package/dist/connectors/github/cli-impl.d.ts.map +0 -1
  81. package/dist/connectors/github/cli-impl.js.map +0 -1
  82. package/dist/connectors/github/deletion.d.ts.map +0 -1
  83. package/dist/connectors/github/deletion.js.map +0 -1
  84. package/dist/connectors/github/dlq.d.ts.map +0 -1
  85. package/dist/connectors/github/dlq.js.map +0 -1
  86. package/dist/connectors/github/idempotency.d.ts.map +0 -1
  87. package/dist/connectors/github/idempotency.js.map +0 -1
  88. package/dist/connectors/github/ingest.d.ts.map +0 -1
  89. package/dist/connectors/github/ingest.js.map +0 -1
  90. package/dist/connectors/github/octokit-client.d.ts.map +0 -1
  91. package/dist/connectors/github/octokit-client.js.map +0 -1
  92. package/dist/connectors/github/ratelimit.d.ts.map +0 -1
  93. package/dist/connectors/github/ratelimit.js.map +0 -1
  94. package/dist/connectors/github/scope.d.ts.map +0 -1
  95. package/dist/connectors/github/scope.js.map +0 -1
  96. package/dist/connectors/github/signature.d.ts.map +0 -1
  97. package/dist/connectors/github/signature.js.map +0 -1
  98. package/dist/connectors/github/tenant-routing.d.ts.map +0 -1
  99. package/dist/connectors/github/tenant-routing.js.map +0 -1
  100. package/dist/connectors/github/transform.d.ts.map +0 -1
  101. package/dist/connectors/github/transform.js.map +0 -1
  102. package/dist/connectors/github/types.d.ts.map +0 -1
  103. package/dist/connectors/github/types.js.map +0 -1
  104. package/dist/connectors/slack/backfill.d.ts.map +0 -1
  105. package/dist/connectors/slack/backfill.js.map +0 -1
  106. package/dist/connectors/slack/deletion.d.ts.map +0 -1
  107. package/dist/connectors/slack/deletion.js.map +0 -1
  108. package/dist/connectors/slack/dlq.d.ts.map +0 -1
  109. package/dist/connectors/slack/dlq.js.map +0 -1
  110. package/dist/connectors/slack/idempotency.d.ts.map +0 -1
  111. package/dist/connectors/slack/idempotency.js.map +0 -1
  112. package/dist/connectors/slack/ingest.d.ts.map +0 -1
  113. package/dist/connectors/slack/ingest.js.map +0 -1
  114. package/dist/connectors/slack/ratelimit.d.ts.map +0 -1
  115. package/dist/connectors/slack/ratelimit.js.map +0 -1
  116. package/dist/connectors/slack/scope.d.ts.map +0 -1
  117. package/dist/connectors/slack/scope.js.map +0 -1
  118. package/dist/connectors/slack/signature.d.ts.map +0 -1
  119. package/dist/connectors/slack/signature.js.map +0 -1
  120. package/dist/connectors/slack/tenant-routing.d.ts.map +0 -1
  121. package/dist/connectors/slack/tenant-routing.js.map +0 -1
  122. package/dist/connectors/slack/transform.d.ts.map +0 -1
  123. package/dist/connectors/slack/transform.js.map +0 -1
  124. package/dist/connectors/slack/types.d.ts.map +0 -1
  125. package/dist/connectors/slack/types.js.map +0 -1
  126. package/dist/connectors/slack/web-client.d.ts.map +0 -1
  127. package/dist/connectors/slack/web-client.js.map +0 -1
  128. package/dist/connectors/slack/workspaces.d.ts.map +0 -1
  129. package/dist/connectors/slack/workspaces.js.map +0 -1
  130. package/dist/consolidate.d.ts.map +0 -1
  131. package/dist/consolidate.js.map +0 -1
  132. package/dist/correction-latency.d.ts.map +0 -1
  133. package/dist/correction-latency.js.map +0 -1
  134. package/dist/customer-notes.d.ts.map +0 -1
  135. package/dist/customer-notes.js.map +0 -1
  136. package/dist/dag.d.ts.map +0 -1
  137. package/dist/dag.js.map +0 -1
  138. package/dist/dashboard.d.ts.map +0 -1
  139. package/dist/dashboard.js.map +0 -1
  140. package/dist/db.d.ts.map +0 -1
  141. package/dist/db.js.map +0 -1
  142. package/dist/decisions.d.ts.map +0 -1
  143. package/dist/decisions.js.map +0 -1
  144. package/dist/dedupe.d.ts.map +0 -1
  145. package/dist/dedupe.js.map +0 -1
  146. package/dist/embedding-provider.d.ts.map +0 -1
  147. package/dist/embedding-provider.js.map +0 -1
  148. package/dist/embeddings.d.ts.map +0 -1
  149. package/dist/embeddings.js.map +0 -1
  150. package/dist/eval-suite.d.ts.map +0 -1
  151. package/dist/eval-suite.js.map +0 -1
  152. package/dist/eval.d.ts.map +0 -1
  153. package/dist/eval.js.map +0 -1
  154. package/dist/extensions/openclaw-plugin/index.js.map +0 -1
  155. package/dist/extract.d.ts.map +0 -1
  156. package/dist/extract.js.map +0 -1
  157. package/dist/forward-claim-detector.d.ts.map +0 -1
  158. package/dist/forward-claim-detector.js.map +0 -1
  159. package/dist/goals.d.ts.map +0 -1
  160. package/dist/goals.js.map +0 -1
  161. package/dist/graph-extract.d.ts.map +0 -1
  162. package/dist/graph-extract.js.map +0 -1
  163. package/dist/graph-recall.d.ts.map +0 -1
  164. package/dist/graph-recall.js.map +0 -1
  165. package/dist/graph-stream.d.ts.map +0 -1
  166. package/dist/graph-stream.js.map +0 -1
  167. package/dist/graph-view.d.ts.map +0 -1
  168. package/dist/graph-view.js.map +0 -1
  169. package/dist/graph.d.ts.map +0 -1
  170. package/dist/graph.js.map +0 -1
  171. package/dist/handoff.d.ts.map +0 -1
  172. package/dist/handoff.js.map +0 -1
  173. package/dist/hooks.d.ts.map +0 -1
  174. package/dist/hooks.js.map +0 -1
  175. package/dist/importers.d.ts.map +0 -1
  176. package/dist/importers.js.map +0 -1
  177. package/dist/incidents.d.ts.map +0 -1
  178. package/dist/incidents.js.map +0 -1
  179. package/dist/index.d.ts.map +0 -1
  180. package/dist/index.js.map +0 -1
  181. package/dist/invalidation.d.ts.map +0 -1
  182. package/dist/invalidation.js.map +0 -1
  183. package/dist/mcp/framing.d.ts.map +0 -1
  184. package/dist/mcp/framing.js.map +0 -1
  185. package/dist/mcp/server.d.ts.map +0 -1
  186. package/dist/mcp/server.js.map +0 -1
  187. package/dist/memory-value-weights.d.ts.map +0 -1
  188. package/dist/memory-value-weights.js.map +0 -1
  189. package/dist/memory-value.d.ts.map +0 -1
  190. package/dist/memory-value.js.map +0 -1
  191. package/dist/memory.d.ts.map +0 -1
  192. package/dist/memory.js.map +0 -1
  193. package/dist/multihop.d.ts.map +0 -1
  194. package/dist/multihop.js.map +0 -1
  195. package/dist/owner-validation.d.ts.map +0 -1
  196. package/dist/owner-validation.js.map +0 -1
  197. package/dist/path-context.d.ts.map +0 -1
  198. package/dist/path-context.js.map +0 -1
  199. package/dist/physics-config.d.ts.map +0 -1
  200. package/dist/physics-config.js.map +0 -1
  201. package/dist/physics-state.d.ts.map +0 -1
  202. package/dist/physics-state.js.map +0 -1
  203. package/dist/physics.d.ts.map +0 -1
  204. package/dist/physics.js.map +0 -1
  205. package/dist/policies.d.ts.map +0 -1
  206. package/dist/policies.js.map +0 -1
  207. package/dist/postinstall.d.ts.map +0 -1
  208. package/dist/postinstall.js.map +0 -1
  209. package/dist/predictions.d.ts.map +0 -1
  210. package/dist/predictions.js.map +0 -1
  211. package/dist/processes.d.ts.map +0 -1
  212. package/dist/processes.js.map +0 -1
  213. package/dist/project-briefs.d.ts.map +0 -1
  214. package/dist/project-briefs.js.map +0 -1
  215. package/dist/project-identity.d.ts.map +0 -1
  216. package/dist/project-identity.js.map +0 -1
  217. package/dist/provenance-coverage.d.ts.map +0 -1
  218. package/dist/provenance-coverage.js.map +0 -1
  219. package/dist/rate-limit.d.ts.map +0 -1
  220. package/dist/rate-limit.js.map +0 -1
  221. package/dist/raw-archive-mirror-cleanup.d.ts.map +0 -1
  222. package/dist/raw-archive-mirror-cleanup.js.map +0 -1
  223. package/dist/raw-archive.d.ts.map +0 -1
  224. package/dist/raw-archive.js.map +0 -1
  225. package/dist/recall-history.d.ts.map +0 -1
  226. package/dist/recall-history.js.map +0 -1
  227. package/dist/recall-scope.d.ts.map +0 -1
  228. package/dist/recall-scope.js.map +0 -1
  229. package/dist/recall-trace.d.ts.map +0 -1
  230. package/dist/recall-trace.js.map +0 -1
  231. package/dist/refine-llm.d.ts.map +0 -1
  232. package/dist/refine-llm.js.map +0 -1
  233. package/dist/reject-flow.d.ts.map +0 -1
  234. package/dist/reject-flow.js.map +0 -1
  235. package/dist/rejection.d.ts.map +0 -1
  236. package/dist/rejection.js.map +0 -1
  237. package/dist/replay.d.ts.map +0 -1
  238. package/dist/replay.js.map +0 -1
  239. package/dist/rerankers/cross-encoder.d.ts.map +0 -1
  240. package/dist/rerankers/cross-encoder.js.map +0 -1
  241. package/dist/rerankers/index.d.ts.map +0 -1
  242. package/dist/rerankers/index.js.map +0 -1
  243. package/dist/rerankers/jev.d.ts.map +0 -1
  244. package/dist/rerankers/jev.js.map +0 -1
  245. package/dist/rerankers/llm.d.ts.map +0 -1
  246. package/dist/rerankers/llm.js.map +0 -1
  247. package/dist/rerankers/types.d.ts.map +0 -1
  248. package/dist/rerankers/types.js.map +0 -1
  249. package/dist/rrf.d.ts.map +0 -1
  250. package/dist/rrf.js.map +0 -1
  251. package/dist/salience.d.ts.map +0 -1
  252. package/dist/salience.js.map +0 -1
  253. package/dist/scheduler.d.ts.map +0 -1
  254. package/dist/scheduler.js.map +0 -1
  255. package/dist/scope.d.ts.map +0 -1
  256. package/dist/scope.js.map +0 -1
  257. package/dist/search.d.ts.map +0 -1
  258. package/dist/search.js.map +0 -1
  259. package/dist/secret-detect.d.ts.map +0 -1
  260. package/dist/secret-detect.js.map +0 -1
  261. package/dist/server-detect.d.ts.map +0 -1
  262. package/dist/server-detect.js.map +0 -1
  263. package/dist/server.d.ts.map +0 -1
  264. package/dist/server.js.map +0 -1
  265. package/dist/shared.d.ts.map +0 -1
  266. package/dist/shared.js.map +0 -1
  267. package/dist/skills.d.ts.map +0 -1
  268. package/dist/skills.js.map +0 -1
  269. package/dist/sleep-redact.d.ts +0 -58
  270. package/dist/sleep-redact.d.ts.map +0 -1
  271. package/dist/sleep-redact.js +0 -80
  272. package/dist/sleep-redact.js.map +0 -1
  273. package/dist/src/ablation.js +0 -138
  274. package/dist/src/ablation.js.map +0 -1
  275. package/dist/src/ambient.js +0 -148
  276. package/dist/src/ambient.js.map +0 -1
  277. package/dist/src/api.js +0 -2109
  278. package/dist/src/api.js.map +0 -1
  279. package/dist/src/audit-prune.js +0 -109
  280. package/dist/src/audit-prune.js.map +0 -1
  281. package/dist/src/audit.js +0 -213
  282. package/dist/src/audit.js.map +0 -1
  283. package/dist/src/auth.js +0 -97
  284. package/dist/src/auth.js.map +0 -1
  285. package/dist/src/autolearn.js +0 -174
  286. package/dist/src/autolearn.js.map +0 -1
  287. package/dist/src/availability.js +0 -94
  288. package/dist/src/availability.js.map +0 -1
  289. package/dist/src/capture.js +0 -1346
  290. package/dist/src/capture.js.map +0 -1
  291. package/dist/src/card-detail.js +0 -15
  292. package/dist/src/card-detail.js.map +0 -1
  293. package/dist/src/card.js +0 -19
  294. package/dist/src/card.js.map +0 -1
  295. package/dist/src/cli.js +0 -9387
  296. package/dist/src/cli.js.map +0 -1
  297. package/dist/src/client.js +0 -237
  298. package/dist/src/client.js.map +0 -1
  299. package/dist/src/compare.js +0 -122
  300. package/dist/src/compare.js.map +0 -1
  301. package/dist/src/config.js +0 -135
  302. package/dist/src/config.js.map +0 -1
  303. package/dist/src/connectors/github/backfill.js +0 -281
  304. package/dist/src/connectors/github/backfill.js.map +0 -1
  305. package/dist/src/connectors/github/cli-impl.js +0 -234
  306. package/dist/src/connectors/github/cli-impl.js.map +0 -1
  307. package/dist/src/connectors/github/deletion.js +0 -85
  308. package/dist/src/connectors/github/deletion.js.map +0 -1
  309. package/dist/src/connectors/github/dlq.js +0 -190
  310. package/dist/src/connectors/github/dlq.js.map +0 -1
  311. package/dist/src/connectors/github/idempotency.js +0 -27
  312. package/dist/src/connectors/github/idempotency.js.map +0 -1
  313. package/dist/src/connectors/github/ingest.js +0 -156
  314. package/dist/src/connectors/github/ingest.js.map +0 -1
  315. package/dist/src/connectors/github/octokit-client.js +0 -70
  316. package/dist/src/connectors/github/octokit-client.js.map +0 -1
  317. package/dist/src/connectors/github/ratelimit.js +0 -31
  318. package/dist/src/connectors/github/ratelimit.js.map +0 -1
  319. package/dist/src/connectors/github/scope.js +0 -13
  320. package/dist/src/connectors/github/scope.js.map +0 -1
  321. package/dist/src/connectors/github/signature.js +0 -81
  322. package/dist/src/connectors/github/signature.js.map +0 -1
  323. package/dist/src/connectors/github/tenant-routing.js +0 -69
  324. package/dist/src/connectors/github/tenant-routing.js.map +0 -1
  325. package/dist/src/connectors/github/transform.js +0 -103
  326. package/dist/src/connectors/github/transform.js.map +0 -1
  327. package/dist/src/connectors/github/types.js +0 -100
  328. package/dist/src/connectors/github/types.js.map +0 -1
  329. package/dist/src/connectors/slack/backfill.js +0 -78
  330. package/dist/src/connectors/slack/backfill.js.map +0 -1
  331. package/dist/src/connectors/slack/deletion.js +0 -59
  332. package/dist/src/connectors/slack/deletion.js.map +0 -1
  333. package/dist/src/connectors/slack/dlq.js +0 -224
  334. package/dist/src/connectors/slack/dlq.js.map +0 -1
  335. package/dist/src/connectors/slack/idempotency.js +0 -31
  336. package/dist/src/connectors/slack/idempotency.js.map +0 -1
  337. package/dist/src/connectors/slack/ingest.js +0 -109
  338. package/dist/src/connectors/slack/ingest.js.map +0 -1
  339. package/dist/src/connectors/slack/ratelimit.js +0 -18
  340. package/dist/src/connectors/slack/ratelimit.js.map +0 -1
  341. package/dist/src/connectors/slack/scope.js +0 -13
  342. package/dist/src/connectors/slack/scope.js.map +0 -1
  343. package/dist/src/connectors/slack/signature.js +0 -27
  344. package/dist/src/connectors/slack/signature.js.map +0 -1
  345. package/dist/src/connectors/slack/tenant-routing.js +0 -41
  346. package/dist/src/connectors/slack/tenant-routing.js.map +0 -1
  347. package/dist/src/connectors/slack/transform.js +0 -47
  348. package/dist/src/connectors/slack/transform.js.map +0 -1
  349. package/dist/src/connectors/slack/types.js +0 -35
  350. package/dist/src/connectors/slack/types.js.map +0 -1
  351. package/dist/src/connectors/slack/web-client.js +0 -43
  352. package/dist/src/connectors/slack/web-client.js.map +0 -1
  353. package/dist/src/connectors/slack/workspaces.js +0 -62
  354. package/dist/src/connectors/slack/workspaces.js.map +0 -1
  355. package/dist/src/consolidate.js +0 -978
  356. package/dist/src/consolidate.js.map +0 -1
  357. package/dist/src/correction-latency.js +0 -74
  358. package/dist/src/correction-latency.js.map +0 -1
  359. package/dist/src/customer-notes.js +0 -325
  360. package/dist/src/customer-notes.js.map +0 -1
  361. package/dist/src/dag.js +0 -352
  362. package/dist/src/dag.js.map +0 -1
  363. package/dist/src/dashboard.js +0 -258
  364. package/dist/src/dashboard.js.map +0 -1
  365. package/dist/src/db.js +0 -2731
  366. package/dist/src/db.js.map +0 -1
  367. package/dist/src/decisions.js +0 -304
  368. package/dist/src/decisions.js.map +0 -1
  369. package/dist/src/dedupe.js +0 -141
  370. package/dist/src/dedupe.js.map +0 -1
  371. package/dist/src/embedding-provider.js +0 -314
  372. package/dist/src/embedding-provider.js.map +0 -1
  373. package/dist/src/embeddings.js +0 -543
  374. package/dist/src/embeddings.js.map +0 -1
  375. package/dist/src/eval-suite.js +0 -294
  376. package/dist/src/eval-suite.js.map +0 -1
  377. package/dist/src/eval.js +0 -187
  378. package/dist/src/eval.js.map +0 -1
  379. package/dist/src/extract.js +0 -117
  380. package/dist/src/extract.js.map +0 -1
  381. package/dist/src/forward-claim-detector.js +0 -117
  382. package/dist/src/forward-claim-detector.js.map +0 -1
  383. package/dist/src/goals.js +0 -399
  384. package/dist/src/goals.js.map +0 -1
  385. package/dist/src/graph-extract.js +0 -314
  386. package/dist/src/graph-extract.js.map +0 -1
  387. package/dist/src/graph-recall.js +0 -277
  388. package/dist/src/graph-recall.js.map +0 -1
  389. package/dist/src/graph-stream.js +0 -176
  390. package/dist/src/graph-stream.js.map +0 -1
  391. package/dist/src/graph-view.js +0 -310
  392. package/dist/src/graph-view.js.map +0 -1
  393. package/dist/src/graph.js +0 -762
  394. package/dist/src/graph.js.map +0 -1
  395. package/dist/src/handoff.js +0 -65
  396. package/dist/src/handoff.js.map +0 -1
  397. package/dist/src/hooks.js +0 -926
  398. package/dist/src/hooks.js.map +0 -1
  399. package/dist/src/importers.js +0 -881
  400. package/dist/src/importers.js.map +0 -1
  401. package/dist/src/incidents.js +0 -336
  402. package/dist/src/incidents.js.map +0 -1
  403. package/dist/src/index.js +0 -32
  404. package/dist/src/index.js.map +0 -1
  405. package/dist/src/invalidation.js +0 -129
  406. package/dist/src/invalidation.js.map +0 -1
  407. package/dist/src/mcp/framing.js +0 -45
  408. package/dist/src/mcp/framing.js.map +0 -1
  409. package/dist/src/mcp/server.js +0 -1298
  410. package/dist/src/mcp/server.js.map +0 -1
  411. package/dist/src/memory-value-weights.js +0 -31
  412. package/dist/src/memory-value-weights.js.map +0 -1
  413. package/dist/src/memory-value.js +0 -261
  414. package/dist/src/memory-value.js.map +0 -1
  415. package/dist/src/memory.js +0 -425
  416. package/dist/src/memory.js.map +0 -1
  417. package/dist/src/multihop.js +0 -35
  418. package/dist/src/multihop.js.map +0 -1
  419. package/dist/src/owner-validation.js +0 -56
  420. package/dist/src/owner-validation.js.map +0 -1
  421. package/dist/src/path-context.js +0 -48
  422. package/dist/src/path-context.js.map +0 -1
  423. package/dist/src/physics-config.js +0 -26
  424. package/dist/src/physics-config.js.map +0 -1
  425. package/dist/src/physics-state.js +0 -172
  426. package/dist/src/physics-state.js.map +0 -1
  427. package/dist/src/physics.js +0 -378
  428. package/dist/src/physics.js.map +0 -1
  429. package/dist/src/policies.js +0 -414
  430. package/dist/src/policies.js.map +0 -1
  431. package/dist/src/postinstall.js +0 -101
  432. package/dist/src/postinstall.js.map +0 -1
  433. package/dist/src/predictions.js +0 -629
  434. package/dist/src/predictions.js.map +0 -1
  435. package/dist/src/processes.js +0 -349
  436. package/dist/src/processes.js.map +0 -1
  437. package/dist/src/project-briefs.js +0 -492
  438. package/dist/src/project-briefs.js.map +0 -1
  439. package/dist/src/project-identity.js +0 -200
  440. package/dist/src/project-identity.js.map +0 -1
  441. package/dist/src/provenance-coverage.js +0 -23
  442. package/dist/src/provenance-coverage.js.map +0 -1
  443. package/dist/src/rate-limit.js +0 -60
  444. package/dist/src/rate-limit.js.map +0 -1
  445. package/dist/src/raw-archive-mirror-cleanup.js +0 -55
  446. package/dist/src/raw-archive-mirror-cleanup.js.map +0 -1
  447. package/dist/src/raw-archive.js +0 -91
  448. package/dist/src/raw-archive.js.map +0 -1
  449. package/dist/src/recall-history.js +0 -235
  450. package/dist/src/recall-history.js.map +0 -1
  451. package/dist/src/recall-scope.js +0 -89
  452. package/dist/src/recall-scope.js.map +0 -1
  453. package/dist/src/recall-trace.js +0 -186
  454. package/dist/src/recall-trace.js.map +0 -1
  455. package/dist/src/refine-llm.js +0 -156
  456. package/dist/src/refine-llm.js.map +0 -1
  457. package/dist/src/reject-flow.js +0 -209
  458. package/dist/src/reject-flow.js.map +0 -1
  459. package/dist/src/rejection.js +0 -160
  460. package/dist/src/rejection.js.map +0 -1
  461. package/dist/src/replay.js +0 -122
  462. package/dist/src/replay.js.map +0 -1
  463. package/dist/src/rerankers/cross-encoder.js +0 -137
  464. package/dist/src/rerankers/cross-encoder.js.map +0 -1
  465. package/dist/src/rerankers/index.js +0 -20
  466. package/dist/src/rerankers/index.js.map +0 -1
  467. package/dist/src/rerankers/jev.js +0 -119
  468. package/dist/src/rerankers/jev.js.map +0 -1
  469. package/dist/src/rerankers/llm.js +0 -80
  470. package/dist/src/rerankers/llm.js.map +0 -1
  471. package/dist/src/rerankers/types.js +0 -2
  472. package/dist/src/rerankers/types.js.map +0 -1
  473. package/dist/src/rrf.js +0 -61
  474. package/dist/src/rrf.js.map +0 -1
  475. package/dist/src/salience.js +0 -74
  476. package/dist/src/salience.js.map +0 -1
  477. package/dist/src/scheduler.js +0 -77
  478. package/dist/src/scheduler.js.map +0 -1
  479. package/dist/src/scope.js +0 -35
  480. package/dist/src/scope.js.map +0 -1
  481. package/dist/src/search.js +0 -1003
  482. package/dist/src/search.js.map +0 -1
  483. package/dist/src/secret-detect.js +0 -95
  484. package/dist/src/secret-detect.js.map +0 -1
  485. package/dist/src/server-detect.js +0 -231
  486. package/dist/src/server-detect.js.map +0 -1
  487. package/dist/src/server.js +0 -3255
  488. package/dist/src/server.js.map +0 -1
  489. package/dist/src/shared.js +0 -502
  490. package/dist/src/shared.js.map +0 -1
  491. package/dist/src/skills.js +0 -346
  492. package/dist/src/skills.js.map +0 -1
  493. package/dist/src/sleep-redact.js +0 -80
  494. package/dist/src/sleep-redact.js.map +0 -1
  495. package/dist/src/sso.js +0 -22
  496. package/dist/src/sso.js.map +0 -1
  497. package/dist/src/stdin.js +0 -41
  498. package/dist/src/stdin.js.map +0 -1
  499. package/dist/src/store.js +0 -3749
  500. package/dist/src/store.js.map +0 -1
  501. package/dist/src/tenant.js +0 -17
  502. package/dist/src/tenant.js.map +0 -1
  503. package/dist/src/trace.js +0 -72
  504. package/dist/src/trace.js.map +0 -1
  505. package/dist/src/version.js +0 -40
  506. package/dist/src/version.js.map +0 -1
  507. package/dist/src/working-memory.js +0 -157
  508. package/dist/src/working-memory.js.map +0 -1
  509. package/dist/src/yaml.js +0 -107
  510. package/dist/src/yaml.js.map +0 -1
  511. package/dist/sso.d.ts +0 -13
  512. package/dist/sso.d.ts.map +0 -1
  513. package/dist/sso.js +0 -22
  514. package/dist/sso.js.map +0 -1
  515. package/dist/stdin.d.ts.map +0 -1
  516. package/dist/stdin.js.map +0 -1
  517. package/dist/store.d.ts.map +0 -1
  518. package/dist/store.js.map +0 -1
  519. package/dist/tenant.d.ts.map +0 -1
  520. package/dist/tenant.js.map +0 -1
  521. package/dist/trace.d.ts.map +0 -1
  522. package/dist/trace.js.map +0 -1
  523. package/dist/version.d.ts.map +0 -1
  524. package/dist/version.js.map +0 -1
  525. package/dist/working-memory.d.ts.map +0 -1
  526. package/dist/working-memory.js.map +0 -1
  527. package/dist/yaml.d.ts.map +0 -1
  528. package/dist/yaml.js.map +0 -1
package/README.md CHANGED
@@ -49,7 +49,7 @@ claim we retracted.
49
49
  - **R@1 0.41 to 0.62 with `hippo recall "<query>" --reranker jev`** on a private 300-query developer store ([full eval](docs/evals/2026-09-19-jev-reranker.md)). The opt-in [TypeSafe Jev](https://typesafe.ai) reranker, off by default, about 0.0004 USD a recall. 2000-draw paired bootstrap; the margin held in 20 of 20 seeds and a permutation null reached it in 0 of 200 runs. Ranking only: three graded tests did **not** show a better answer rate than the free local cross-encoder, and that negative result is in the same doc. What it buys today is a shorter context, 2 memories ranked by Jev answering as well as 5 ranked by the cross-encoder.
50
50
  - **10 of 10 incident scenarios beat transcript replay** on a staged Slack corpus ([benchmarks/e1.3/](benchmarks/e1.3/)). Recall surfaces the cause faster than scrolling the last N messages.
51
51
  - **0 outbound HTTP** on the 1000-event ingestion smoke. Proven by a `globalThis.fetch` spy that throws on call, not a hardcoded zero. The default recall path makes no network call either; opt-in features such as the Jev reranker above, the LLM reranker and the API embedders do.
52
- - **926 tests, real DB, zero mocks.** Project rule. The one mocks-vs-prod divergence that bit us early is now the constraint that kept the next ten releases honest.
52
+ - **3,500+ tests on a real database.** No module mocks and no mocked store; only paid network calls are stubbed. Project rule. The one mocks-vs-prod divergence that bit us early is now the constraint that kept the next ten releases honest.
53
53
  - **dlPFC goal-conditioned cluster discrimination, 3/3 queries pass** — full goal stack with policy weighting and lifespan-windowed outcome propagation. Per-goal lift on a 3-cluster fixture where BM25 alone cannot discriminate; deterministic test in [`benchmarks/micro/results/b3-depth.json`](benchmarks/micro/results/b3-depth.json).
54
54
 
55
55
  ---
@@ -254,6 +254,8 @@ hippo recall "data pipeline" --why --limit 5
254
254
 
255
255
  Input enters the buffer. Important things get encoded into episodic memory. During "sleep," repeated episodes compress into semantic patterns. Weak memories decay and disappear.
256
256
 
257
+ The store is SQLite (`.hippo/hippo.db`). The markdown files and `index.json` are mirrors written after each change. From 1.46.0, `index.json` is no longer refreshed on every write; it comes only from an explicit export, so read the store through the CLI, the MCP server or the HTTP API.
258
+
257
259
  ```mermaid
258
260
  flowchart TD
259
261
  I[New information] --> B[Buffer<br/>session-only, no decay]
@@ -745,7 +747,7 @@ Plugin docs: [extensions/openclaw-plugin/](extensions/openclaw-plugin/). Integra
745
747
 
746
748
  ### Claude Code Plugin
747
749
 
748
- Plugin with SessionStart/Stop hooks and error auto-capture. See [extensions/claude-code-plugin/](extensions/claude-code-plugin/).
750
+ Plugin with session, prompt and compaction hooks plus error auto-capture. See [extensions/claude-code-plugin/](extensions/claude-code-plugin/).
749
751
 
750
752
  Full integration details: [integrations/](integrations/)
751
753
 
@@ -799,12 +801,12 @@ The AI-memory category matured fast in 2026. Hippo's specific take — bio-decay
799
801
  | Auto-hook install | Yes | No | No | No | No | No | No | No | No | No |
800
802
  | MCP server | Yes | Yes | No | No | Yes (stdio + HTTP/OAuth) | Partial (managed) | Yes (via Letta Code) | Yes (first-party Claude/LangGraph) | Yes | ? |
801
803
  | Zero runtime deps | Yes | No (ChromaDB) | No | No | No (PGLite or PG+pgvector) | No (managed service) | No (Python deps) | No (Python deps) | Yes (single Rust binary) | No (managed + OSS) |
802
- | LongMemEval (best published) | 98.6% default / 99.8% voyage R@5 (s_cleaned, per-haystack)\* | 96.6% raw / 100% reranked R@5 | ~49-85% R@5 | N/A | 97.6-97.9% R@5 (s_cleaned\*) | N/A (LoCoMo 80.3%) | N/A | N/A | 88.78% overall accuracy w/ reader\*\* | 83.00% overall\*\* (LoCoMo 93.05%, HaluMem 93.04%) |
804
+ | LongMemEval (best published) | 98.0% local / 99.8% voyage R@5 (s_cleaned, per-haystack)\* | 96.6% raw / 100% reranked R@5 | ~49-85% R@5 | N/A | 97.6-97.9% R@5 (s_cleaned\*) | N/A (LoCoMo 80.3%) | N/A | N/A | 88.78% overall accuracy w/ reader\*\* | 83.00% overall\*\* (LoCoMo 93.05%, HaluMem 93.04%) |
803
805
  | Git-friendly | Yes | No | No | Yes | Yes | No | No | No | Yes (Git is the model) | ? |
804
806
  | Framework agnostic | Yes | Yes | Partial | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
805
807
  | License | MIT | (open) | Apache-2.0 | (open) | MIT | Apache-2.0 (community) | Apache-2.0 | MIT (core) | Apache-2.0 | Apache-2.0 (OSS) + cloud |
806
808
 
807
- \* Hippo's 98.6% (zero-dep default) and 99.8% (voyage-3-large) are on `longmemeval_s_cleaned`, per-question haystack, directly comparable to gbrain's 97.6% on the same split and metric (measured 2026-06-09, see [`docs/evals/2026-06-09-longmemeval-per-haystack-dual.md`](docs/evals/2026-06-09-longmemeval-per-haystack-dual.md)). gbrain's figure is their published claim. An older hippo number, 86.8% R@5 on `longmemeval_oracle` under pooled (non-per-haystack) retrieval, is not comparable to per-haystack figures.
809
+ \* Hippo's 98.0% uses the free local MiniLM embedder (an optional install) and 99.8% uses voyage-3-large (measured 2026-06-09, not re-run). Both are on `longmemeval_s_cleaned` with a per-question haystack, the split and metric of gbrain's published 97.6%. Each is the best of five retrieval settings in the benchmark scripts, not `hippo recall`. At 500 questions the 95% interval is about ±1.2 points, so 98.0 and 97.6 are a tie. The June 2026 build scored 98.6; [`docs/evals/2026-09-23-longmemeval-reproduction.md`](docs/evals/2026-09-23-longmemeval-reproduction.md) has both runs. An older hippo number, 86.8% R@5 on `longmemeval_oracle` under pooled (non-per-haystack) retrieval, is not comparable to per-haystack figures.
808
810
 
809
811
  \*\* Different metric: Memoria's 88.78% and EverMind's 83% are reported as overall accuracy with a reader LLM, not retrieval R@5. Higher denominator + LLM helps. Not directly comparable to retrieval-only R@5 numbers above.
810
812
 
@@ -820,16 +822,16 @@ Three benchmarks testing three different things. Full details in [`benchmarks/`]
820
822
 
821
823
  [LongMemEval](https://arxiv.org/abs/2410.10813) (ICLR 2025) is the industry-standard benchmark: 500 questions across 5 memory abilities, embedded in 115k+ token chat histories.
822
824
 
823
- **Standard per-haystack result (`_s` split, measured 2026-06-09).** Each question is scored against its own ~48-session haystack, the same way gbrain and other published systems report. The v1.23.0 pluggable embedding provider lets you choose the embedder:
825
+ **Standard per-haystack result (`_s` split; MiniLM re-measured 2026-09-23, voyage measured 2026-06-09).** Each question is scored against its own ~48-session haystack, the same way gbrain and other published systems report. The v1.23.0 pluggable embedding provider lets you choose the embedder:
824
826
 
825
827
  | Embedder | Dense-only R@5 | Best hybrid R@5 | R@1 |
826
828
  |----------|----------------|-----------------|-----|
827
- | MiniLM-L6 (zero-dependency default) | 96.6 | 98.6 | 89.6 |
828
- | voyage-3-large (opt-in) | 99.8 | 99.8 | 94.6 |
829
+ | MiniLM-L6 (local, optional install) | 96.8 | 98.0 | 88.4 |
830
+ | voyage-3-large (opt-in, paid) | 99.8 | 99.8 | 94.6 |
829
831
 
830
- gbrain reports 97.6 R@5 on this split with a paid frontier embedder. Hippo's free, local, zero-dependency default reaches 98.6. Retrieval recall on the standard task is effectively saturated, so the embedder is a swappable commodity, not the differentiator. Method and the global-pool comparison: [`docs/evals/2026-06-09-longmemeval-per-haystack-dual.md`](docs/evals/2026-06-09-longmemeval-per-haystack-dual.md).
832
+ gbrain reports 97.6 R@5 on this split with a paid frontier embedder. Hippo reaches 98.0 with a free local embedder, a tie at 500 questions. These numbers come from the scripts in `benchmarks/longmemeval/`, which index every turn and fuse BM25 with dense ranks; they are not `hippo recall`, and a default install has no embedder. Re-measure: [`docs/evals/2026-09-23-longmemeval-reproduction.md`](docs/evals/2026-09-23-longmemeval-reproduction.md). Retrieval recall on the standard task is effectively saturated, so the embedder is a swappable commodity, not the differentiator. Method and the global-pool comparison: [`docs/evals/2026-06-09-longmemeval-per-haystack-dual.md`](docs/evals/2026-06-09-longmemeval-per-haystack-dual.md).
831
833
 
832
- The differentiator is what happens as one store grows. Point retrieval at a single unified memory of tens of thousands of sessions, with no pre-scoped haystack, and recall stops being free (default 47, voyage 56 on the 19,195-session `_s` store). That is where memory lifecycle (decay, consolidation, supersession) earns its keep, and it is what hippo measures next (see ROADMAP Part III).
834
+ The differentiator is what happens as one store grows. Point retrieval at a single unified memory of tens of thousands of sessions, with no pre-scoped haystack, and recall stops being free (MiniLM 47, voyage 56 on the 19,195-session `_s` store, June 2026). That is where memory lifecycle (decay, consolidation, supersession) earns its keep, and it is what hippo measures next (see ROADMAP Part III).
833
835
 
834
836
  **Hippo v0.28.0 oracle-split results (hybrid BM25 + cosine, full 500 questions, pooled retrieval):**
835
837
 
@@ -909,7 +911,7 @@ node run.mjs --adapter all
909
911
  Issues and PRs welcome. Before contributing, run `hippo status` in the repo root to see the project's own memory.
910
912
 
911
913
  The interesting problems:
912
- - **LongMemEval retrieval (standard task: done).** Per-question-haystack R@5 is 98.6% with the zero-dependency default and 99.8% with voyage-3-large (measured 2026-06-09), at or above the published frontier. Retrieval is no longer the gap; the lifecycle stress eval (ROADMAP Part III) is the next measurement.
914
+ - **LongMemEval retrieval (standard task: done).** Per-question-haystack R@5 is 98.0% with the free local embedder (re-measured 2026-09-23; the June build gave 98.6) and 99.8% with voyage-3-large (measured 2026-06-09), level with the published frontier. Retrieval is no longer the gap; the lifecycle stress eval (ROADMAP Part III) is the next measurement.
913
915
  - Better consolidation heuristics (LLM-powered merge vs current text overlap)
914
916
  - Web UI / dashboard for visualizing decay curves and memory health
915
917
  - Optimal decay parameter tuning from real usage data
package/bin/hippo.js CHANGED
@@ -1,2 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import '../dist/cli.js';
2
+ import { runCli } from '../dist/cli.js';
3
+
4
+ runCli();
package/dist/api.d.ts CHANGED
@@ -31,7 +31,7 @@ import { type AvailabilityHint } from './availability.js';
31
31
  * object carrying both the audit-log subject (formerly the string itself) and
32
32
  * a role for /v1/sleep admin gating. Audit helpers continue accepting `string`
33
33
  * — callers pass `ctx.actor.subject`. Role checks happen at the request
34
- * boundary (e.g. /v1/sleep), not inside api functions.
34
+ * boundary (e.g. /v1/sleep), except in authCreate and authRevoke (ForbiddenError).
35
35
  */
36
36
  export interface Actor {
37
37
  /** 'cli' | 'localhost:cli' | 'api_key:<key_id>' | 'mcp' | 'connector:slack' | 'connector:github' */
@@ -72,6 +72,10 @@ export declare class RecallContractError extends Error {
72
72
  readonly code: 'fresh_tail_requires_session_id' | 'invalid_scorer_window';
73
73
  constructor(code: 'fresh_tail_requires_session_id' | 'invalid_scorer_window', message: string);
74
74
  }
75
+ /** The actor's role or identity does not allow the operation. HTTP maps it to 403. */
76
+ export declare class ForbiddenError extends Error {
77
+ constructor(message: string);
78
+ }
75
79
  import { isPrivateScope, passesScopeFilterForRecall } from './recall-scope.js';
76
80
  export { isPrivateScope, passesScopeFilterForRecall };
77
81
  export { passesCliRecallScopeFilter } from './recall-scope.js';
@@ -141,6 +145,7 @@ export interface RecallOpts {
141
145
  * (e.g. mean-of-children summary re-rank).
142
146
  */
143
147
  scorerWindow?: number;
148
+ /** Candidate order. `recall` always keeps the BM25 order; `retrieve` honours this. */
144
149
  mode?: 'bm25' | 'hybrid' | 'physics';
145
150
  /**
146
151
  * Restrict results to memories whose `scope` equals this value exactly.
@@ -495,9 +500,8 @@ export declare function buildSuppressionSummary(counts: {
495
500
  }): RecallSuppressionSummary;
496
501
  /**
497
502
  * Domain-level recall. Loads BM25-ranked candidates from SQLite scoped to
498
- * `ctx.tenantId`. The `mode` flag is accepted for forward compatibility (the
499
- * CLI exposes hybrid/physics paths) but Task 2 wires only the BM25 candidate
500
- * loader; later tasks can extend this to call the physics/hybrid scorer.
503
+ * `ctx.tenantId` and keeps that order whatever `mode` says; `retrieve` is the
504
+ * mode-aware, strengthening variant the HTTP route uses.
501
505
  *
502
506
  * **api.recall does NOT mutate `index.last_retrieval_ids`** (v1.11.5 contract
503
507
  * lock). The CLI `cmdRecall` (cli.ts) writes `last_retrieval_ids` because the
@@ -510,6 +514,8 @@ export declare function buildSuppressionSummary(counts: {
510
514
  * `tests/api-recall-no-side-effects.test.ts`.
511
515
  */
512
516
  export declare function recall(ctx: Context, opts: RecallOpts): RecallResult;
517
+ /** Mode-aware recall that strengthens each returned row; never writes last_retrieval_ids (v1.11.5 lock). */
518
+ export declare function retrieve(ctx: Context, opts: RecallOpts): Promise<RecallResult>;
513
519
  export interface AssembleOpts {
514
520
  /** Token budget. Default 4000. */
515
521
  budget?: number;
@@ -833,9 +839,8 @@ export interface AuthCreateResult {
833
839
  * `src/server.ts` POST /v1/auth/keys mirrors this: it ignores any body
834
840
  * `tenantId` and uses the resolved Bearer's tenant exclusively.
835
841
  *
836
- * Per A5 v2 follow-ups (TODOS.md), `auth_create` is currently unaudited —
837
- * we intentionally match that behavior here for consistency. When A5 v2
838
- * lands and adds the audit op, this function should mirror the cli handler.
842
+ * Only an admin actor can mint (ForbiddenError otherwise), so a member key
843
+ * can never create a key, least of all an admin one.
839
844
  */
840
845
  export declare function authCreate(ctx: Context, opts: AuthCreateOpts): AuthCreateResult;
841
846
  /**
@@ -853,8 +858,8 @@ export declare function authList(ctx: Context, opts: {
853
858
  * Revoke an API key.
854
859
  *
855
860
  * Security: the key must belong to `ctx.tenantId`. Cross-tenant revoke is
856
- * rejected with the same "not found" message used for missing keys, so that a
857
- * caller cannot probe which key_ids exist on other tenants.
861
+ * rejected with the "not found" message used for missing keys, and a member may
862
+ * revoke only its own key (checked first), so no caller can probe other key_ids.
858
863
  *
859
864
  * Audit: emits 'auth_revoke' with `tenantId` set to the KEY ROW's tenant_id
860
865
  * (M1 fix from A5 review, mirrors src/cli.ts:cmdAuthRevoke). Skipped on no-op
@@ -1014,26 +1019,22 @@ export interface SleepResult {
1014
1019
  * v1.25.0: count of memories the auto-share secret veto withheld this sleep
1015
1020
  * — rows that passed every other admission gate (transfer score,
1016
1021
  * not-already-global) and were blocked solely by `detectSecret`. Absent
1017
- * when 0 or when auto-share did not run. Same redaction class as `shared`
1018
- * (per-invocation activity counter, NOT redacted on egress — see the
1019
- * "NOT redacted" list in src/sleep-redact.ts).
1022
+ * when 0 or when auto-share did not run.
1020
1023
  */
1021
1024
  secretSkipped?: number;
1022
1025
  /**
1023
1026
  * AT1: count of auto-share candidates the GLOBAL store's rejection
1024
1027
  * tombstone refused this sleep (docs/plans/2026-08-15-at1-rejected-value-tombstone.md
1025
1028
  * plan §3 — copy paths must not let one rejected candidate abort the
1026
- * batch). Absent when 0 or when auto-share did not run. Same
1027
- * per-invocation-activity class as `secretSkipped` (sibling counter,
1028
- * same autoShare call) — NOT redacted on egress, see sleep-redact.ts.
1029
+ * batch). Absent when 0 or when auto-share did not run.
1029
1030
  */
1030
1031
  rejectedSkipped?: number;
1031
1032
  ambient?: AmbientState | null;
1032
1033
  /**
1033
1034
  * E3 sleep enqueue-hook: graph re-extraction totals across the tenants rebuilt
1034
1035
  * this sleep. Absent when no tenant was dirty, and under dryRun (the graph
1035
- * phase runs only on a real sleep). Cross-tenant aggregate — zeroed on
1036
- * non-loopback non-self egress by sleep-redact.ts.
1036
+ * phase runs only on a real sleep). Cross-tenant aggregate, one reason
1037
+ * /v1/sleep stays loopback-only.
1037
1038
  */
1038
1039
  graph?: {
1039
1040
  tenants: number;
@@ -1054,10 +1055,9 @@ export interface SleepResult {
1054
1055
  * serving lands — at that point the route will need an admin-role gate OR
1055
1056
  * api.sleep itself will need to scope dedup / audit / delete by ctx.tenantId.
1056
1057
  *
1057
- * Audit emission gap: the consolidation phases (dedup, audit-delete) do
1058
- * NOT emit audit_log rows today, matching pre-refactor cmdSleepCore. Same
1059
- * CLI/MCP parity gap that T6 fixed for cmdOutcome, now visible at the api
1060
- * surface. Tracked in TODOS.md "Episode A follow-ups" for a future minor.
1058
+ * Dedup and audit deletes each log a `forget` row with the ctx actor and a
1059
+ * `metadata.reason`. Pinned and raw rows are never auto-deleted (canAutoDelete).
1060
+ * dryRun previews consolidate, dedup and audit, then returns before share/ambient.
1061
1061
  */
1062
1062
  /**
1063
1063
  * v1.12.2: Test-only DI seam shape for `sleep`'s phase dependencies.
package/dist/api.js CHANGED
@@ -8,7 +8,7 @@
8
8
  */
9
9
  import { createHash } from 'node:crypto';
10
10
  import { openHippoDb, closeHippoDb } from './db.js';
11
- import { writeEntry, writeEntryDbOnly, stampOriginProject, writeEntryMirrors, readEntry, deleteEntry, loadRecallSearchEntries, loadEntriesByIds, loadChildrenOf, loadFreshRawMemories, loadSessionRawMemories, countSessionRawMemories, DEFAULT_SEARCH_CANDIDATE_LIMIT, removeEntryMirrors, loadActiveTaskSnapshot, loadFreshActiveTaskSnapshot, loadLatestHandoff, listSessionEvents, SNAPSHOT_AMBIENT_MAX_AGE_MS, loadIndex, saveIndex, loadAllEntries, loadAmbientCandidates, updateStats, isInitialized, markSummaryDirtyInTx, auditRejectionRefusal, } from './store.js';
11
+ import { writeEntry, writeEntryDbOnly, strengthenRetrieved, stampOriginProject, writeEntryMirrors, readEntry, deleteEntry, loadRecallSearchEntries, loadEntriesByIds, loadChildrenOf, loadFreshRawMemories, loadSessionRawMemories, countSessionRawMemories, DEFAULT_SEARCH_CANDIDATE_LIMIT, removeEntryMirrors, loadActiveTaskSnapshot, loadFreshActiveTaskSnapshot, loadLatestHandoff, listSessionEvents, SNAPSHOT_AMBIENT_MAX_AGE_MS, loadIndex, saveIndex, loadAllEntries, loadAmbientCandidates, updateStats, isInitialized, markSummaryDirtyInTx, auditRejectionRefusal, } from './store.js';
12
12
  import { RejectedValueError } from './rejection.js';
13
13
  import { rejectValue, unrejectValue, listRejectionsForTenant } from './reject-flow.js';
14
14
  import { formatHandoffEvidenceLine } from './handoff.js';
@@ -16,7 +16,7 @@ import { createMemory, applyOutcome, calculateStrength, Layer, } from './memory.
16
16
  import { appendAuditEvent, queryAuditEvents, auditMemories, isContentWorthStoring, } from './audit.js';
17
17
  import { promoteToGlobal, getGlobalRoot, autoShare, searchBothHybrid } from './shared.js';
18
18
  import { writeRecallTrace, writeRecallTraceAtRoot, recordTraceOutcome } from './recall-trace.js';
19
- import { evalNow, isRecallBoostAblated } from './ablation.js';
19
+ import { evalNow } from './ablation.js';
20
20
  import { archiveRawMemory } from './raw-archive.js';
21
21
  import { createApiKey, listApiKeys, revokeApiKey, } from './auth.js';
22
22
  import { applyGoalStackBoost } from './goals.js';
@@ -69,6 +69,13 @@ export class RecallContractError extends Error {
69
69
  this.code = code;
70
70
  }
71
71
  }
72
+ /** The actor's role or identity does not allow the operation. HTTP maps it to 403. */
73
+ export class ForbiddenError extends Error {
74
+ constructor(message) {
75
+ super(message);
76
+ this.name = 'ForbiddenError';
77
+ }
78
+ }
72
79
  // v1.25.0: the recall-side scope predicates (PRIVATE_SCOPE_RE, isPrivateScope,
73
80
  // passesScopeFilterForRecall) live in recall-scope.ts (leaf) so shared.ts can
74
81
  // apply the same default-deny rule to searchBothHybrid's internal loads
@@ -137,6 +144,7 @@ export function remember(ctx, opts) {
137
144
  artifact_ref: opts.artifactRef ?? null,
138
145
  tags: opts.tags,
139
146
  tenantId: ctx.tenantId,
147
+ baseHalfLifeDays: loadConfig(ctx.hippoRoot).defaultHalfLifeDays,
140
148
  });
141
149
  // writeEntry threads ctx.actor.subject into its internal audit hook, so exactly
142
150
  // one 'remember' event lands in the log with the supplied actor.
@@ -162,9 +170,8 @@ export function buildSuppressionSummary(counts) {
162
170
  }
163
171
  /**
164
172
  * Domain-level recall. Loads BM25-ranked candidates from SQLite scoped to
165
- * `ctx.tenantId`. The `mode` flag is accepted for forward compatibility (the
166
- * CLI exposes hybrid/physics paths) but Task 2 wires only the BM25 candidate
167
- * loader; later tasks can extend this to call the physics/hybrid scorer.
173
+ * `ctx.tenantId` and keeps that order whatever `mode` says; `retrieve` is the
174
+ * mode-aware, strengthening variant the HTTP route uses.
168
175
  *
169
176
  * **api.recall does NOT mutate `index.last_retrieval_ids`** (v1.11.5 contract
170
177
  * lock). The CLI `cmdRecall` (cli.ts) writes `last_retrieval_ids` because the
@@ -177,7 +184,27 @@ export function buildSuppressionSummary(counts) {
177
184
  * `tests/api-recall-no-side-effects.test.ts`.
178
185
  */
179
186
  export function recall(ctx, opts) {
180
- const limit = opts.limit ?? 10;
187
+ const windowSize = recallWindowSize(opts);
188
+ return recallFrom(ctx, opts, windowSize, loadRecallSearchEntries(ctx.hippoRoot, opts.query, windowSize, ctx.tenantId, opts.scope, 'exact', false));
189
+ }
190
+ /** Mode-aware recall that strengthens each returned row; never writes last_retrieval_ids (v1.11.5 lock). */
191
+ export async function retrieve(ctx, opts) {
192
+ const windowSize = recallWindowSize(opts);
193
+ let candidates = loadRecallSearchEntries(ctx.hippoRoot, opts.query, windowSize, ctx.tenantId, opts.scope, 'exact', false);
194
+ if (opts.mode === 'hybrid' || opts.mode === 'physics') {
195
+ const searchOpts = { budget: Infinity, hippoRoot: ctx.hippoRoot, scope: opts.scope ?? null };
196
+ const ranked = opts.mode === 'physics'
197
+ ? await physicsSearch(opts.query, candidates, { ...searchOpts, physicsConfig: loadConfig(ctx.hippoRoot).physics })
198
+ : await hybridSearch(opts.query, candidates, searchOpts);
199
+ const rankedIds = new Set(ranked.map((r) => r.entry.id));
200
+ candidates = [...ranked.map((r) => r.entry), ...candidates.filter((e) => !rankedIds.has(e.id))];
201
+ }
202
+ const result = recallFrom(ctx, opts, windowSize, candidates);
203
+ strengthenRetrieved(ctx.hippoRoot, result.results.map((r) => r.id), ctx.tenantId);
204
+ return result;
205
+ }
206
+ /** Contract preflight: throws before any store-touching work. */
207
+ function recallWindowSize(opts) {
181
208
  // F5 (v1.6.5) preflight — codex P1: original guard fired AFTER
182
209
  // loadSearchEntries (which runs initStore, migrating legacy state on first
183
210
  // call). For a true contract preflight we want the throw before any
@@ -207,7 +234,10 @@ export function recall(ctx, opts) {
207
234
  throw new RecallContractError('invalid_scorer_window', `scorerWindow must be a positive integer; got ${opts.scorerWindow}`);
208
235
  }
209
236
  }
210
- const windowSize = opts.scorerWindow ?? DEFAULT_SEARCH_CANDIDATE_LIMIT;
237
+ return opts.scorerWindow ?? DEFAULT_SEARCH_CANDIDATE_LIMIT;
238
+ }
239
+ function recallFrom(ctx, opts, windowSize, all) {
240
+ const limit = opts.limit ?? 10;
211
241
  // v1.7.1 — root-cause fix for the `unknown:legacy` leak. Scope predicate
212
242
  // is now pushed into `loadSearchRows` SQL via `loadRecallSearchEntries`.
213
243
  // - opts.scope undefined / '': SQL excludes `unknown:legacy`.
@@ -233,16 +263,16 @@ export function recall(ctx, opts) {
233
263
  let droppedByBudgetCount = 0;
234
264
  let summarySubstitutionsCount = 0;
235
265
  let freshTailAddedCount = 0;
236
- const all = loadRecallSearchEntries(ctx.hippoRoot, opts.query, windowSize, ctx.tenantId, opts.scope);
237
266
  // v1.12.13 / C5 — WYSIATI totalCandidates counter (post tenant + SQL scope
238
267
  // predicate, pre JS scope filter).
239
268
  totalCandidatesCount = all.length;
269
+ const current = all.filter((e) => !e.superseded_by);
240
270
  let entries;
241
271
  if (opts.scope !== undefined && opts.scope !== '') {
242
272
  // SQL already exact-matched in loadRecallSearchEntries; keep the JS
243
273
  // filter as defense-in-depth so a future SQL-clause regression cannot
244
274
  // silently surface cross-scope rows.
245
- entries = all.filter((e) => e.scope === opts.scope);
275
+ entries = current.filter((e) => e.scope === opts.scope);
246
276
  }
247
277
  else {
248
278
  // SQL already excluded `unknown:legacy` AND (v1.25.0) pre-filtered
@@ -252,7 +282,7 @@ export function recall(ctx, opts) {
252
282
  // anchored `<source>:private:*` rule (v1.2.1 generalization) and
253
283
  // defense-in-depth: connector authors cannot silently surface private
254
284
  // rows to no-scope callers even if the SQL clause regresses.
255
- entries = all.filter((e) => !isPrivateScope(e.scope ?? null));
285
+ entries = current.filter((e) => !isPrivateScope(e.scope ?? null));
256
286
  }
257
287
  // v1.12.13 / C5 — WYSIATI dropped_pre_rank counter (JS scope filter drops
258
288
  // for api.recall; cmdRecall pipeline rolls --outcome/--layer/--as-of/etc.
@@ -326,7 +356,7 @@ export function recall(ctx, opts) {
326
356
  const eligibleParentIds = Array.from(overflowByParent.keys()).filter((pid) => (overflowByParent.get(pid)?.length ?? 0) >= 2 && !baseIds.has(pid));
327
357
  if (eligibleParentIds.length > 0) {
328
358
  const parents = loadEntriesByIds(ctx.hippoRoot, eligibleParentIds, ctx.tenantId);
329
- const eligibleParents = parents.filter((p) => (p.dag_level ?? 0) === 2 && passesScopeFilterForRecall(p.scope ?? null, opts.scope));
359
+ const eligibleParents = parents.filter((p) => (p.dag_level ?? 0) === 2 && !p.superseded_by && passesScopeFilterForRecall(p.scope ?? null, opts.scope));
330
360
  const maxSub = Math.max(1, Math.ceil(limit * 0.3));
331
361
  // Order parents by overflow count descending so the most
332
362
  // information-dense substitutions come first. Overflow count is the
@@ -736,7 +766,7 @@ export function assemble(ctx, sessionId, opts = {}) {
736
766
  const eligibleParentIds = Array.from(olderByParent.keys()).filter((pid) => (olderByParent.get(pid)?.length ?? 0) >= 2);
737
767
  const parents = eligibleParentIds.length > 0
738
768
  ? loadEntriesByIds(ctx.hippoRoot, eligibleParentIds, ctx.tenantId)
739
- .filter((p) => (p.dag_level ?? 0) === 2)
769
+ .filter((p) => (p.dag_level ?? 0) === 2 && !p.superseded_by)
740
770
  .filter((p) => passesScopeFilterForRecall(p.scope ?? null, opts.scope))
741
771
  : [];
742
772
  const claimedRawIds = new Set();
@@ -1258,11 +1288,13 @@ export function archiveRaw(ctx, id, reason, opts = {}) {
1258
1288
  * `src/server.ts` POST /v1/auth/keys mirrors this: it ignores any body
1259
1289
  * `tenantId` and uses the resolved Bearer's tenant exclusively.
1260
1290
  *
1261
- * Per A5 v2 follow-ups (TODOS.md), `auth_create` is currently unaudited —
1262
- * we intentionally match that behavior here for consistency. When A5 v2
1263
- * lands and adds the audit op, this function should mirror the cli handler.
1291
+ * Only an admin actor can mint (ForbiddenError otherwise), so a member key
1292
+ * can never create a key, least of all an admin one.
1264
1293
  */
1265
1294
  export function authCreate(ctx, opts) {
1295
+ if (ctx.actor.role !== 'admin') {
1296
+ throw new ForbiddenError('Only an admin key can create API keys');
1297
+ }
1266
1298
  const db = openHippoDb(ctx.hippoRoot);
1267
1299
  try {
1268
1300
  const role = opts.role ?? 'admin';
@@ -1311,6 +1343,9 @@ export function authList(ctx, opts) {
1311
1343
  }
1312
1344
  }
1313
1345
  export function authRevoke(ctx, keyId) {
1346
+ if (ctx.actor.role !== 'admin' && ctx.actor.subject !== `api_key:${keyId}`) {
1347
+ throw new ForbiddenError('A member key can revoke only itself');
1348
+ }
1314
1349
  const db = openHippoDb(ctx.hippoRoot);
1315
1350
  try {
1316
1351
  // SAFETY: row's shape matches the three columns named in the SELECT
@@ -1767,21 +1802,11 @@ export async function getContext(ctx, opts = {}) {
1767
1802
  const toUpdate = selectedItems.map((s) => s.entry);
1768
1803
  const updatedEntries = markRetrieved(toUpdate);
1769
1804
  const localIndex = loadIndex(ctx.hippoRoot);
1770
- // EVAL-ONLY ablation (see ablation.ts): under the recall flag,
1771
- // markRetrieved returns unmutated entries (ids preserved for outcome
1772
- // attribution) and persistence is skipped (identical-row writes still
1773
- // refresh updated_at / mirrors / DAG dirty flags).
1774
- if (!isRecallBoostAblated()) {
1775
- for (const u of updatedEntries) {
1776
- const targetRoot = localIndex.entries[u.id]
1777
- ? ctx.hippoRoot
1778
- : hasGlobal
1779
- ? globalRoot
1780
- : ctx.hippoRoot;
1781
- writeEntry(targetRoot, u);
1782
- }
1783
- }
1784
- localIndex.last_retrieval_ids = updatedEntries.map((u) => u.id);
1805
+ const retrievedIds = updatedEntries.map((u) => u.id);
1806
+ const strengthenedHere = strengthenRetrieved(ctx.hippoRoot, retrievedIds);
1807
+ if (hasGlobal)
1808
+ strengthenRetrieved(globalRoot, retrievedIds.filter((id) => !strengthenedHere.has(id)));
1809
+ localIndex.last_retrieval_ids = retrievedIds;
1785
1810
  // LC1 F1 structural fix (docs/plans/2026-08-02-lc1-recall-trace-persistence.md):
1786
1811
  // write the trace FIRST — post-limit, post-annotation `selectedItems`
1787
1812
  // actually returned, on a fresh short-lived connection (the audit
@@ -1896,10 +1921,8 @@ export async function sleep(ctx, opts = {}) {
1896
1921
  dryRun,
1897
1922
  details: consolidateResult.details,
1898
1923
  };
1899
- if (dryRun)
1900
- return result;
1901
1924
  // Phase 2: Dedup (post-consolidate near-duplicate cleanup).
1902
- const dedupResult = phases.deduplicateStore(ctx.hippoRoot);
1925
+ const dedupResult = phases.deduplicateStore(ctx.hippoRoot, { dryRun, actor: ctx.actor.subject });
1903
1926
  dedupCount = dedupResult.removed;
1904
1927
  if (dedupResult.removed > 0) {
1905
1928
  const semDups = dedupResult.pairs.filter((p) => p.keptLayer === 'semantic' && p.removedLayer === 'semantic').length;
@@ -1912,25 +1935,29 @@ export async function sleep(ctx, opts = {}) {
1912
1935
  crossDups,
1913
1936
  };
1914
1937
  }
1915
- // Phase 3: Quality audit (remove junk, report warnings).
1916
- const allEntries = phases.loadAllEntries(ctx.hippoRoot);
1938
+ // Phase 3: Quality audit (remove junk, report warnings; a dry run skips rows earlier phases would remove).
1939
+ const planned = new Set(dryRun ? [...(consolidateResult.removedIds ?? []), ...dedupResult.pairs.map((p) => p.removed)] : []);
1940
+ const allEntries = phases.loadAllEntries(ctx.hippoRoot).filter((e) => !planned.has(e.id));
1917
1941
  const auditOut = phases.auditMemories(allEntries);
1918
1942
  if (auditOut.issues.length > 0) {
1919
1943
  const errors = auditOut.issues.filter((i) => i.severity === 'error');
1920
1944
  const warnings = auditOut.issues.filter((i) => i.severity === 'warning');
1921
- if (errors.length > 0) {
1922
- for (const issue of errors) {
1923
- phases.deleteEntry(ctx.hippoRoot, issue.memoryId);
1924
- }
1945
+ let removed = 0;
1946
+ for (const issue of errors) {
1947
+ const reason = `sleep-audit: ${issue.reason}`;
1948
+ if (dryRun || phases.deleteEntry(ctx.hippoRoot, issue.memoryId, { actor: ctx.actor.subject, reason, automatic: true }))
1949
+ removed++;
1925
1950
  }
1926
- auditDeletedCount = errors.length;
1927
- if (errors.length > 0 || warnings.length > 0) {
1951
+ auditDeletedCount = removed;
1952
+ if (removed > 0 || warnings.length > 0) {
1928
1953
  result.audit = {
1929
- errorsRemoved: errors.length,
1954
+ errorsRemoved: removed,
1930
1955
  warningCount: warnings.length,
1931
1956
  };
1932
1957
  }
1933
1958
  }
1959
+ if (dryRun)
1960
+ return result;
1934
1961
  // Phase 4: Auto-share high-transfer-score memories to global.
1935
1962
  if (!opts.noShare) {
1936
1963
  const sleepConfig = phases.loadConfig(ctx.hippoRoot);
package/dist/audit.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { MemoryEntry } from './memory.js';
1
+ import { type MemoryEntry } from './memory.js';
2
2
  import type { DatabaseSyncLike } from './db.js';
3
3
  import type { JsonObject } from './working-memory.js';
4
4
  export type AuditSeverity = 'warning' | 'error';
package/dist/audit.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { canAutoDelete } from './memory.js';
1
2
  const STOP_WORDS = new Set([
2
3
  'the', 'a', 'an', 'is', 'was', 'are', 'were', 'be', 'been', 'being',
3
4
  'to', 'of', 'in', 'for', 'on', 'with', 'at', 'by', 'from', 'it',
@@ -109,6 +110,14 @@ function hasNoSpecificity(text) {
109
110
  return words.length < 8 && VAGUE_ONLY.test(text);
110
111
  }
111
112
  export function auditMemory(entry) {
113
+ const issue = classifyMemory(entry);
114
+ // Error means "auto-remove"; a pinned or raw row is never auto-removed, so it can only warn.
115
+ if (issue?.severity === 'error' && !canAutoDelete(entry)) {
116
+ return { ...issue, severity: 'warning', reason: `${issue.reason} (${entry.pinned ? 'pinned' : 'raw'}, kept)` };
117
+ }
118
+ return issue;
119
+ }
120
+ function classifyMemory(entry) {
112
121
  const content = entry.content.trim();
113
122
  if (content.length < 3) {
114
123
  return { memoryId: entry.id, content, severity: 'error', reason: 'too short (< 3 chars)' };
@@ -7,7 +7,7 @@ import { MemoryEntry } from './memory.js';
7
7
  * Create a MemoryEntry capturing a command failure.
8
8
  * Content format: "Command '<cmd>' failed: <truncated stderr>"
9
9
  */
10
- export declare function captureError(exitCode: number, stderr: string, command: string): MemoryEntry;
10
+ export declare function captureError(exitCode: number, stderr: string, command: string, tenantId?: string): MemoryEntry;
11
11
  /**
12
12
  * Parse git log output for actionable lessons.
13
13
  * Looks for fix:, revert:, bug:, error:, hotfix: commit messages.
package/dist/autolearn.js CHANGED
@@ -11,7 +11,7 @@ import { isContentWorthStoring } from './audit.js';
11
11
  * Create a MemoryEntry capturing a command failure.
12
12
  * Content format: "Command '<cmd>' failed: <truncated stderr>"
13
13
  */
14
- export function captureError(exitCode, stderr, command) {
14
+ export function captureError(exitCode, stderr, command, tenantId) {
15
15
  // Truncate to first 500 chars to avoid storing megabytes of build logs
16
16
  const wasTruncated = stderr.length > 500;
17
17
  const truncated = stderr.slice(0, 500).trim();
@@ -29,6 +29,7 @@ export function captureError(exitCode, stderr, command) {
29
29
  tags,
30
30
  source: 'autolearn',
31
31
  confidence: 'observed',
32
+ tenantId,
32
33
  });
33
34
  }
34
35
  /**
package/dist/cli.d.ts CHANGED
@@ -34,6 +34,7 @@ import * as api from './api.js';
34
34
  /** Test-only: reset the module-level recall-history Map. Call from beforeEach. */
35
35
  export declare function __resetSessionRecallHistoryCli(): void;
36
36
  export declare const BOOLEAN_FLAGS: ReadonlySet<string>;
37
+ export declare const KNOWN_FLAGS: ReadonlySet<string>;
37
38
  export declare function parseArgs(argv: string[]): {
38
39
  command: string;
39
40
  args: string[];
@@ -50,6 +51,7 @@ export declare function learnFromMemoryMd(hippoRoot: string, homeDir?: string):
50
51
  */
51
52
  /** @internal — exported for snapshot tests (tests/cli-context-render-snapshot.test.ts). NOT a stable public API. */
52
53
  export declare function renderSleepResult(result: api.SleepResult): void;
54
+ export declare function shouldAutoRepairCodexWrapper(currentCommand: string, flags: Record<string, string | boolean | string[]>): boolean;
53
55
  /** @internal — exported for snapshot tests (tests/cli-context-render-snapshot.test.ts). NOT a stable public API. */
54
56
  export declare function printContextMarkdown(items: Array<{
55
57
  entry: MemoryEntry;
@@ -57,4 +59,5 @@ export declare function printContextMarkdown(items: Array<{
57
59
  tokens: number;
58
60
  isGlobal: boolean;
59
61
  }>, totalTokens: number, framing?: string): void;
62
+ export declare function runCli(argv?: string[]): Promise<void>;
60
63
  //# sourceMappingURL=cli.d.ts.map