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/doctor.js ADDED
@@ -0,0 +1,174 @@
1
+ /**
2
+ * `hippo doctor`: a health check people and agents can run after installing
3
+ * hippo, or when something seems off. Read-only: it never creates a store,
4
+ * installs a hook or migrates a database. Every non-passing check names the
5
+ * command that fixes it, so an agent can act on the `--json` output.
6
+ */
7
+ import * as fs from 'node:fs';
8
+ import * as os from 'node:os';
9
+ import * as path from 'node:path';
10
+ import { findHippoStoreDir } from './project-identity.js';
11
+ import { getGlobalRoot } from './shared.js';
12
+ import { isInitialized, loadStats } from './store.js';
13
+ import { openHippoDb, closeHippoDb, getSchemaVersion, getCurrentSchemaVersion } from './db.js';
14
+ import { isEmbeddingAvailable } from './embeddings.js';
15
+ /** Minimum Node.js version hippo supports (package.json engines). */
16
+ export const MIN_NODE = '22.16.0';
17
+ function versionAtLeast(actual, min) {
18
+ const a = actual.replace(/^v/, '').split('.').map(Number);
19
+ const b = min.split('.').map(Number);
20
+ for (let i = 0; i < 3; i++) {
21
+ const x = a[i] ?? 0;
22
+ const y = b[i] ?? 0;
23
+ if (x !== y)
24
+ return x > y;
25
+ }
26
+ return true;
27
+ }
28
+ function readJson(file) {
29
+ try {
30
+ // SAFETY: JSON.parse returns a JSON value by definition.
31
+ return JSON.parse(fs.readFileSync(file, 'utf8'));
32
+ }
33
+ catch {
34
+ return null;
35
+ }
36
+ }
37
+ function countRows(db, table) {
38
+ try {
39
+ // SAFETY: COUNT(*) returns one row with one numeric column.
40
+ const row = db.prepare(`SELECT COUNT(*) AS n FROM ${table}`).get();
41
+ return Number(row?.n ?? 0);
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ }
47
+ /** Run every check. Never throws for a broken install; broken parts become failed checks. */
48
+ export function runDoctor(opts) {
49
+ const cwd = opts.cwd ?? process.cwd();
50
+ const home = opts.home ?? os.homedir();
51
+ const now = opts.now ?? new Date();
52
+ const checks = [];
53
+ const node = opts.nodeVersion ?? process.versions.node;
54
+ checks.push(versionAtLeast(node, MIN_NODE)
55
+ ? { id: 'node', status: 'pass', detail: `Node.js ${node}` }
56
+ : { id: 'node', status: 'fail', detail: `Node.js ${node} is older than ${MIN_NODE}`, fix: `Install Node.js ${MIN_NODE} or newer` });
57
+ const local = findHippoStoreDir(cwd);
58
+ const globalRoot = getGlobalRoot();
59
+ const hasGlobal = isInitialized(globalRoot);
60
+ let store = null;
61
+ if (local !== null) {
62
+ store = local;
63
+ checks.push({ id: 'store', status: 'pass', detail: `project store at ${local}${hasGlobal ? ` (global store at ${globalRoot} too)` : ''}` });
64
+ }
65
+ else if (hasGlobal) {
66
+ store = globalRoot;
67
+ checks.push({ id: 'store', status: 'warn', detail: `no project store here; using the global store at ${globalRoot}`, fix: 'hippo init (in the project root)' });
68
+ }
69
+ else {
70
+ checks.push({ id: 'store', status: 'fail', detail: 'no hippo store found (project or global)', fix: 'hippo init (in the project root), or hippo init --global' });
71
+ }
72
+ if (store !== null) {
73
+ let db = null;
74
+ try {
75
+ db = openHippoDb(store);
76
+ const have = getSchemaVersion(db);
77
+ const want = getCurrentSchemaVersion();
78
+ checks.push(have === want
79
+ ? { id: 'schema', status: 'pass', detail: `database schema v${have}` }
80
+ : have > want
81
+ ? { id: 'schema', status: 'fail', detail: `database schema v${have} is newer than this hippo (v${want})`, fix: 'npm install -g hippo-memory@latest' }
82
+ : { id: 'schema', status: 'info', detail: `database schema v${have}; hippo migrates it to v${want} on the next write` });
83
+ const memories = countRows(db, 'memories');
84
+ const dormant = countRows(db, 'dormant_memories');
85
+ const memoryCheck = { id: 'memories', status: 'info', detail: `${memories ?? '?'} memories${dormant !== null ? `, ${dormant} dormant` : ''}` };
86
+ if (memories === 0) {
87
+ memoryCheck.status = 'warn';
88
+ memoryCheck.fix = 'hippo learn --git (seed lessons from git history)';
89
+ }
90
+ checks.push(memoryCheck);
91
+ const since = new Date(now.getTime() - 7 * 86_400_000).toISOString();
92
+ try {
93
+ // SAFETY: COUNT/SUM aggregate row.
94
+ const row = db.prepare(`SELECT COUNT(*) AS n, COALESCE(SUM(tokens), 0) AS t FROM token_ledger WHERE ts >= ? AND event = 'inject'`).get(since);
95
+ checks.push({ id: 'tokens', status: 'info', detail: `${Number(row?.n ?? 0)} memory blocks sent to agents in 7 days, about ${Number(row?.t ?? 0)} tokens (hippo tokens for detail)` });
96
+ }
97
+ catch {
98
+ checks.push({ id: 'tokens', status: 'info', detail: 'no token ledger yet (created on the next write)' });
99
+ }
100
+ }
101
+ catch (err) {
102
+ checks.push({ id: 'schema', status: 'fail', detail: `cannot open the database: ${err instanceof Error ? err.message : String(err)}`, fix: 'check file permissions on the .hippo folder' });
103
+ }
104
+ finally {
105
+ if (db !== null)
106
+ closeHippoDb(db);
107
+ }
108
+ try {
109
+ const runs = loadStats(store)['consolidation_runs'];
110
+ const last = Array.isArray(runs) && runs.length > 0 ? runs[runs.length - 1] : null;
111
+ // SAFETY: the constructor check above narrows `last` to a plain JSON object.
112
+ const ts = last !== null && last !== undefined && !Array.isArray(last) && last.constructor === Object ? last.timestamp : undefined;
113
+ const when = ts !== undefined && ts !== null ? Date.parse(String(ts)) : Number.NaN;
114
+ if (Number.isNaN(when)) {
115
+ checks.push({ id: 'sleep', status: 'warn', detail: 'hippo has never slept (consolidated) in this store', fix: 'hippo sleep (the session-end hook runs it automatically)' });
116
+ }
117
+ else {
118
+ const days = Math.floor((now.getTime() - when) / 86_400_000);
119
+ checks.push(days > 7
120
+ ? { id: 'sleep', status: 'warn', detail: `last sleep ${days} days ago`, fix: 'hippo sleep, and check the session-end hook is installed' }
121
+ : { id: 'sleep', status: 'pass', detail: `last sleep ${days === 0 ? 'today' : `${days} day${days === 1 ? '' : 's'} ago`}` });
122
+ }
123
+ }
124
+ catch {
125
+ checks.push({ id: 'sleep', status: 'info', detail: 'sleep history unavailable' });
126
+ }
127
+ }
128
+ const claudeDir = path.join(home, '.claude');
129
+ if (fs.existsSync(claudeDir)) {
130
+ const settings = readJson(path.join(claudeDir, 'settings.json'));
131
+ const text = settings === null ? '' : JSON.stringify(settings);
132
+ const viaPlugin = /hippo-memory@/.test(text);
133
+ // Each hook and what it does, so a partial install says what is missing.
134
+ const hooks = [
135
+ ['hippo context --pinned-only', 'per-prompt memory'],
136
+ ['hippo session-end', 'session-end capture and sleep'],
137
+ ['hippo pre-compact', 'compaction snapshot and capture'],
138
+ ['hippo compact-resume', 'resume after compaction'],
139
+ ['hippo post-compact', 'the message after compaction'],
140
+ ['hippo capture-error', 'failed-tool capture'],
141
+ ];
142
+ const missing = hooks.filter(([marker]) => !text.includes(marker)).map(([, what]) => what);
143
+ if (viaPlugin) {
144
+ checks.push({ id: 'claude-code', status: 'pass', detail: 'Claude Code: hippo plugin enabled (all hooks, including compaction and failed-tool capture)' });
145
+ }
146
+ else if (missing.length === 0) {
147
+ checks.push({ id: 'claude-code', status: 'pass', detail: 'Claude Code: all hippo hooks installed, including compaction and failed-tool capture' });
148
+ }
149
+ else if (missing.length === hooks.length) {
150
+ checks.push({ id: 'claude-code', status: 'warn', detail: 'Claude Code found, but no hippo hooks are installed', fix: 'hippo hook install claude-code' });
151
+ }
152
+ else {
153
+ checks.push({ id: 'claude-code', status: 'warn', detail: `Claude Code: hippo hooks missing for ${missing.join(', ')}`, fix: 'hippo hook install claude-code (adds only what is missing)' });
154
+ }
155
+ }
156
+ else {
157
+ checks.push({ id: 'claude-code', status: 'info', detail: 'Claude Code not found; other agents can use hippo over MCP (hippo mcp)' });
158
+ }
159
+ checks.push({ id: 'embeddings', status: 'info', detail: isEmbeddingAvailable() ? 'local embeddings available (hybrid search)' : 'embeddings not installed; recall uses BM25 (optional: hippo embed --help)' });
160
+ return { ok: !checks.some((c) => c.status === 'fail'), version: opts.version, store, checks };
161
+ }
162
+ /** Human-readable rendering of a {@link DoctorReport}. */
163
+ export function formatDoctor(report) {
164
+ const mark = { pass: 'ok ', warn: 'warn', fail: 'FAIL', info: 'info' };
165
+ const lines = [`hippo ${report.version} doctor`, ''];
166
+ for (const c of report.checks) {
167
+ lines.push(` [${mark[c.status]}] ${c.id.padEnd(11)} ${c.detail}`);
168
+ if (c.fix && (c.status === 'warn' || c.status === 'fail'))
169
+ lines.push(` ${''.padEnd(11)} fix: ${c.fix}`);
170
+ }
171
+ lines.push('', report.ok ? 'No failures.' : 'Some checks failed; run the fix commands above.');
172
+ return lines.join('\n');
173
+ }
174
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Dormant memories: what sleep does with a faded memory instead of deleting
3
+ * it (config `dormant.enabled`, on by default; `retentionDays` bounds how
4
+ * long one is kept).
5
+ *
6
+ * A dormant memory keeps its full content in `dormant_memories` (schema v44)
7
+ * but is no longer a `memories` row, so recall, context, every sleep pass and
8
+ * every other reader of `memories` stop seeing it exactly as if it had been
9
+ * deleted. `hippo dormant` lists and searches them, `hippo dormant restore`
10
+ * brings one back, `hippo dormant forget` deletes one for good.
11
+ *
12
+ * Not to be confused with the raw archive (`raw_archive`, `archiveRawMemory`,
13
+ * `hippo forget --archive`): that path removes a raw receipt's content and
14
+ * keeps only its metadata. A dormant memory keeps its content.
15
+ *
16
+ * DB-only helpers: the caller owns the handle and any transaction. The
17
+ * tenant-scoped entry points are api.listDormant / restoreDormant /
18
+ * forgetDormant.
19
+ */
20
+ import type { DatabaseSyncLike } from './db.js';
21
+ import type { MemoryEntry } from './memory.js';
22
+ /** Why sleep made a memory dormant. Only the decay pass does today. */
23
+ export type DormantReason = 'decay';
24
+ /** One memory that sleep is moving out of active memory into the dormant store. */
25
+ export interface DormantMove {
26
+ /** The memory as it stood when it faded; restored verbatim apart from its recall clock. */
27
+ entry: MemoryEntry;
28
+ /** Live strength at the moment it went dormant (below the decay threshold). */
29
+ strength: number;
30
+ reason: DormantReason;
31
+ /** ISO time of the sleep that made it dormant. */
32
+ dormantAt: string;
33
+ }
34
+ /** A dormant memory as listed to a user. */
35
+ export interface DormantMemory {
36
+ id: string;
37
+ tenantId: string;
38
+ content: string;
39
+ tags: string[];
40
+ /** Live strength when it went dormant. */
41
+ strength: number;
42
+ /** Why it went dormant (`decay`). */
43
+ reason: string;
44
+ /** ISO time it went dormant. */
45
+ dormantAt: string;
46
+ }
47
+ /** Options for {@link listDormantRows}. */
48
+ export interface ListDormantOpts {
49
+ /** Whitespace-separated terms; a row must contain every term (case-insensitive substring). */
50
+ query?: string;
51
+ /** Maximum rows returned, newest first. Default 20. */
52
+ limit?: number;
53
+ }
54
+ /**
55
+ * Insert (or refresh) the dormant snapshot for `move.entry`. Does not touch
56
+ * the `memories` row: the caller deletes it in the same transaction, so the
57
+ * memory is never in both places or in neither.
58
+ */
59
+ export declare function insertDormantRow(db: DatabaseSyncLike, move: DormantMove): void;
60
+ /** A tenant's dormant memories, newest first, optionally filtered by search terms. */
61
+ export declare function listDormantRows(db: DatabaseSyncLike, tenantId: string, opts?: ListDormantOpts): DormantMemory[];
62
+ /** A dormant memory's stored snapshot plus when and why it went dormant. */
63
+ export interface DormantSnapshot {
64
+ entry: MemoryEntry;
65
+ reason: string;
66
+ strength: number;
67
+ dormantAt: string;
68
+ }
69
+ /**
70
+ * The stored snapshot for a tenant's dormant memory, or null when the tenant
71
+ * has no dormant memory with that id (another tenant's id reads as absent).
72
+ */
73
+ export declare function readDormantSnapshot(db: DatabaseSyncLike, tenantId: string, id: string): DormantSnapshot | null;
74
+ /** Whether a tenant has a dormant memory with this id (snapshot readable or not). */
75
+ export declare function hasDormantRow(db: DatabaseSyncLike, tenantId: string, id: string): boolean;
76
+ /** Delete a tenant's dormant memory. Returns false when there was none. */
77
+ export declare function deleteDormantRow(db: DatabaseSyncLike, tenantId: string, id: string): boolean;
78
+ /**
79
+ * Delete every dormant memory in the tenant whose content has this rejection
80
+ * digest, so a rejected value cannot linger in dormant storage. Returns the
81
+ * ids removed. Same O(N) scan as the live-row sweep in reject-flow.ts.
82
+ */
83
+ export declare function purgeDormantByDigest(db: DatabaseSyncLike, tenantId: string, digest: string): string[];
84
+ /** How many dormant memories went dormant before `cutoffIso` (a dry-run count). */
85
+ export declare function countExpiredDormant(db: DatabaseSyncLike, cutoffIso: string): number;
86
+ /**
87
+ * Delete every dormant memory (all tenants) that went dormant before
88
+ * `cutoffIso`: the `dormant.retentionDays` window. Returns how many went.
89
+ */
90
+ export declare function purgeExpiredDormant(db: DatabaseSyncLike, cutoffIso: string): number;
91
+ //# sourceMappingURL=dormant.d.ts.map
@@ -0,0 +1,121 @@
1
+ import { rejectionDigest } from './rejection.js';
2
+ const DEFAULT_LIST_LIMIT = 20;
3
+ /**
4
+ * Insert (or refresh) the dormant snapshot for `move.entry`. Does not touch
5
+ * the `memories` row: the caller deletes it in the same transaction, so the
6
+ * memory is never in both places or in neither.
7
+ */
8
+ export function insertDormantRow(db, move) {
9
+ db.prepare(`
10
+ INSERT INTO dormant_memories (tenant_id, id, content, entry_json, reason, strength, dormant_at)
11
+ VALUES (?, ?, ?, ?, ?, ?, ?)
12
+ ON CONFLICT(tenant_id, id) DO UPDATE SET
13
+ content = excluded.content,
14
+ entry_json = excluded.entry_json,
15
+ reason = excluded.reason,
16
+ strength = excluded.strength,
17
+ dormant_at = excluded.dormant_at
18
+ `).run(move.entry.tenantId, move.entry.id, move.entry.content, JSON.stringify(move.entry), move.reason, move.strength, move.dormantAt);
19
+ }
20
+ /** Escape LIKE metacharacters so a search term matches literally (ESCAPE '\'). */
21
+ function escapeLike(term) {
22
+ return term.replace(/[\\%_]/g, (ch) => `\\${ch}`);
23
+ }
24
+ /**
25
+ * Parse a stored snapshot back into a MemoryEntry, or null when the row no
26
+ * longer matches the snapshot it carries (edited by hand, or truncated).
27
+ */
28
+ function parseSnapshot(row) {
29
+ try {
30
+ // SAFETY: entry_json is only written by insertDormantRow from a MemoryEntry;
31
+ // the id / tenant / content checks below reject a row edited out of shape.
32
+ const entry = JSON.parse(row.entry_json);
33
+ if (entry.id !== row.id || entry.tenantId !== row.tenant_id || entry.content !== row.content) {
34
+ return null;
35
+ }
36
+ return entry;
37
+ }
38
+ catch {
39
+ return null;
40
+ }
41
+ }
42
+ function rowToDormantMemory(row) {
43
+ const entry = parseSnapshot(row);
44
+ return {
45
+ id: row.id,
46
+ tenantId: row.tenant_id,
47
+ content: row.content,
48
+ tags: entry && Array.isArray(entry.tags) ? entry.tags.map(String) : [],
49
+ strength: row.strength,
50
+ reason: row.reason,
51
+ dormantAt: row.dormant_at,
52
+ };
53
+ }
54
+ /** A tenant's dormant memories, newest first, optionally filtered by search terms. */
55
+ export function listDormantRows(db, tenantId, opts = {}) {
56
+ const terms = (opts.query ?? '').trim().split(/\s+/).filter((t) => t.length > 0);
57
+ const limit = opts.limit !== undefined && Number.isFinite(opts.limit) && opts.limit >= 1
58
+ ? Math.floor(opts.limit)
59
+ : DEFAULT_LIST_LIMIT;
60
+ const termClauses = terms.map(() => ` AND content LIKE ? ESCAPE '\\'`).join('');
61
+ // SAFETY: rows' shape matches the seven columns named in the SELECT.
62
+ const rows = db.prepare(`SELECT tenant_id, id, content, entry_json, reason, strength, dormant_at
63
+ FROM dormant_memories
64
+ WHERE tenant_id = ?${termClauses}
65
+ ORDER BY dormant_at DESC, id ASC
66
+ LIMIT ?`).all(tenantId, ...terms.map((t) => `%${escapeLike(t)}%`), limit);
67
+ return rows.map(rowToDormantMemory);
68
+ }
69
+ /**
70
+ * The stored snapshot for a tenant's dormant memory, or null when the tenant
71
+ * has no dormant memory with that id (another tenant's id reads as absent).
72
+ */
73
+ export function readDormantSnapshot(db, tenantId, id) {
74
+ // SAFETY: row's shape matches the seven columns named in the SELECT.
75
+ const row = db.prepare(`SELECT tenant_id, id, content, entry_json, reason, strength, dormant_at
76
+ FROM dormant_memories WHERE tenant_id = ? AND id = ?`).get(tenantId, id);
77
+ const entry = row ? parseSnapshot(row) : null;
78
+ return row && entry ? { entry, reason: row.reason, strength: row.strength, dormantAt: row.dormant_at } : null;
79
+ }
80
+ /** Whether a tenant has a dormant memory with this id (snapshot readable or not). */
81
+ export function hasDormantRow(db, tenantId, id) {
82
+ return db.prepare(`SELECT 1 FROM dormant_memories WHERE tenant_id = ? AND id = ?`).get(tenantId, id) !== undefined;
83
+ }
84
+ /** Delete a tenant's dormant memory. Returns false when there was none. */
85
+ export function deleteDormantRow(db, tenantId, id) {
86
+ const result = db.prepare(`DELETE FROM dormant_memories WHERE tenant_id = ? AND id = ?`).run(tenantId, id);
87
+ return Number(result.changes ?? 0) > 0;
88
+ }
89
+ /**
90
+ * Delete every dormant memory in the tenant whose content has this rejection
91
+ * digest, so a rejected value cannot linger in dormant storage. Returns the
92
+ * ids removed. Same O(N) scan as the live-row sweep in reject-flow.ts.
93
+ */
94
+ export function purgeDormantByDigest(db, tenantId, digest) {
95
+ // SAFETY: rows' shape matches the two columns named in the SELECT.
96
+ const rows = db.prepare(`SELECT id, content FROM dormant_memories WHERE tenant_id = ?`)
97
+ .all(tenantId);
98
+ const removed = [];
99
+ for (const row of rows) {
100
+ if (rejectionDigest(row.content) !== digest)
101
+ continue;
102
+ deleteDormantRow(db, tenantId, row.id);
103
+ removed.push(row.id);
104
+ }
105
+ return removed;
106
+ }
107
+ /** How many dormant memories went dormant before `cutoffIso` (a dry-run count). */
108
+ export function countExpiredDormant(db, cutoffIso) {
109
+ // SAFETY: row's shape matches the single aliased COUNT column in the SELECT.
110
+ const row = db.prepare(`SELECT COUNT(*) AS n FROM dormant_memories WHERE dormant_at < ?`).get(cutoffIso);
111
+ return Number(row.n);
112
+ }
113
+ /**
114
+ * Delete every dormant memory (all tenants) that went dormant before
115
+ * `cutoffIso`: the `dormant.retentionDays` window. Returns how many went.
116
+ */
117
+ export function purgeExpiredDormant(db, cutoffIso) {
118
+ const result = db.prepare(`DELETE FROM dormant_memories WHERE dormant_at < ?`).run(cutoffIso);
119
+ return Number(result.changes ?? 0);
120
+ }
121
+ //# sourceMappingURL=dormant.js.map
@@ -31,6 +31,7 @@
31
31
  */
32
32
  import { getEmbedding, isEmbeddingAvailable, resolveEmbeddingModel, DEFAULT_EMBEDDING_MODEL, } from './embeddings.js';
33
33
  import { loadConfig } from './config.js';
34
+ import { redactSecrets } from './secret-detect.js';
34
35
  export const API_PROVIDER_KINDS = ['openai', 'voyage', 'cohere'];
35
36
  function isApiProviderKind(x) {
36
37
  return x === 'openai' || x === 'voyage' || x === 'cohere';
@@ -188,7 +189,7 @@ class ApiEmbeddingProvider {
188
189
  'content-type': 'application/json',
189
190
  authorization: `Bearer ${key}`,
190
191
  },
191
- body: JSON.stringify(spec.buildBody(this.model, chunk, role)),
192
+ body: JSON.stringify(spec.buildBody(this.model, chunk.map(redactSecrets), role)),
192
193
  signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
193
194
  });
194
195
  }
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import * as fs from 'fs';
7
7
  import * as path from 'path';
8
+ import { randomUUID } from 'crypto';
8
9
  import { createRequire } from 'module';
9
10
  import { loadAllEntries } from './store.js';
10
11
  import { openHippoDb, closeHippoDb, getMeta, setMeta } from './db.js';
@@ -244,13 +245,13 @@ export function saveStoredEmbeddingModel(hippoRoot, model) {
244
245
  closeHippoDb(db);
245
246
  }
246
247
  }
247
- export function resolveIndexedEmbeddingModel(hippoRoot, index = loadEmbeddingIndex(hippoRoot)) {
248
+ export function resolveIndexedEmbeddingModel(hippoRoot, index) {
248
249
  const stored = loadStoredEmbeddingModel(hippoRoot);
249
250
  if (stored)
250
251
  return stored;
251
- return Object.keys(index).length > 0 ? DEFAULT_EMBEDDING_MODEL : null;
252
+ return Object.keys(index ?? loadEmbeddingIndex(hippoRoot)).length > 0 ? DEFAULT_EMBEDDING_MODEL : null;
252
253
  }
253
- export function embeddingModelRequiresReindex(hippoRoot, model, index = loadEmbeddingIndex(hippoRoot)) {
254
+ export function embeddingModelRequiresReindex(hippoRoot, model, index) {
254
255
  const stored = resolveIndexedEmbeddingModel(hippoRoot, index);
255
256
  return stored !== null && stored !== embeddingIndexIdentity(model);
256
257
  }
@@ -374,16 +375,86 @@ export function saveEmbeddingIndex(hippoRoot, index) {
374
375
  throw err;
375
376
  }
376
377
  }
377
- // Mutex to serialize embedding writes and prevent read-modify-write races
378
+ const EMBED_LOCK_FILE = 'embeddings.lock';
379
+ const EMBED_LOCK_WAIT_MS = 10_000;
380
+ const EMBED_LOCK_OWNER = `${process.pid}:${randomUUID()}`;
381
+ // In-process mutex plus an O_EXCL "<pid>:<token>" lock file: our token is a lock we leaked; our PID with another token is a live worker thread, unless the lock predates this process (a reused PID).
378
382
  let _embedWriteLock = Promise.resolve();
379
- async function withEmbedLock(fn) {
383
+ function embedLockHolderAlive(lockPath) {
384
+ let raw;
385
+ try {
386
+ raw = fs.readFileSync(lockPath, 'utf8');
387
+ }
388
+ catch (err) {
389
+ return !(err instanceof Error && 'code' in err && err.code === 'ENOENT');
390
+ }
391
+ const mtimeMs = fs.statSync(lockPath, { throwIfNoEntry: false })?.mtimeMs ?? 0;
392
+ const pid = Number(raw.split(':')[0]);
393
+ // An empty lock is a holder between create and write; after 5 s it is a crashed one.
394
+ if (!Number.isInteger(pid) || pid <= 0)
395
+ return Date.now() - mtimeMs < 5_000;
396
+ if (raw === EMBED_LOCK_OWNER)
397
+ return false;
398
+ if (pid === process.pid)
399
+ return mtimeMs >= Date.now() - process.uptime() * 1000;
400
+ try {
401
+ process.kill(pid, 0);
402
+ return true;
403
+ }
404
+ catch (err) {
405
+ return err instanceof Error && 'code' in err && err.code === 'EPERM';
406
+ }
407
+ }
408
+ // After the double-break race below the file can be another writer's lock, so remove only our own.
409
+ function releaseEmbedFileLock(lockPath) {
410
+ let raw;
411
+ try {
412
+ raw = fs.readFileSync(lockPath, 'utf8');
413
+ }
414
+ catch (err) {
415
+ if (err instanceof Error && 'code' in err && err.code === 'ENOENT')
416
+ return;
417
+ throw err;
418
+ }
419
+ if (raw === EMBED_LOCK_OWNER)
420
+ fs.rmSync(lockPath, { force: true });
421
+ }
422
+ async function acquireEmbedFileLock(hippoRoot) {
423
+ const lockPath = path.join(hippoRoot, EMBED_LOCK_FILE);
424
+ const deadline = Date.now() + EMBED_LOCK_WAIT_MS;
425
+ for (;;) {
426
+ try {
427
+ fs.writeFileSync(lockPath, EMBED_LOCK_OWNER, { flag: 'wx' });
428
+ return () => releaseEmbedFileLock(lockPath);
429
+ }
430
+ catch (err) {
431
+ if (!(err instanceof Error && 'code' in err && err.code === 'EEXIST'))
432
+ throw err;
433
+ }
434
+ // SHORTCUT: two waiters can both break one dead holder's lock; a vector lost that way is backfilled by the next `hippo embed`.
435
+ if (!embedLockHolderAlive(lockPath)) {
436
+ fs.rmSync(lockPath, { force: true });
437
+ continue;
438
+ }
439
+ if (Date.now() >= deadline)
440
+ throw new Error(`embeddings.json is busy: another hippo process holds ${lockPath}`);
441
+ await new Promise((r) => setTimeout(r, 50));
442
+ }
443
+ }
444
+ async function withEmbedLock(hippoRoot, fn) {
380
445
  let resolve;
381
446
  const next = new Promise(r => { resolve = r; });
382
447
  const prev = _embedWriteLock;
383
448
  _embedWriteLock = next;
384
449
  await prev;
385
450
  try {
386
- return await fn();
451
+ const release = await acquireEmbedFileLock(hippoRoot);
452
+ try {
453
+ return await fn();
454
+ }
455
+ finally {
456
+ release();
457
+ }
387
458
  }
388
459
  finally {
389
460
  resolve();
@@ -396,7 +467,7 @@ export async function embedMemory(hippoRoot, entry, model) {
396
467
  const provider = resolveEmbeddingProvider(hippoRoot, { model });
397
468
  if (!provider.isAvailable())
398
469
  return;
399
- return withEmbedLock(async () => {
470
+ return withEmbedLock(hippoRoot, async () => {
400
471
  // embedMemory is best-effort: an embedding failure (API down / bad key / 5xx)
401
472
  // must not reject the caller's write — `getEmbedding` historically swallowed
402
473
  // failures and returned []. The explicit `hippo embed` / `embedAll` path is
@@ -445,6 +516,8 @@ export async function embedMemory(hippoRoot, entry, model) {
445
516
  catch {
446
517
  // Provider failure (API down / bad key). Best-effort: leave the index as-is.
447
518
  }
519
+ }).catch((err) => {
520
+ console.error(`hippo: skipped embedding ${entry.id} (${err instanceof Error ? err.message : String(err)}); run 'hippo embed' to backfill`);
448
521
  });
449
522
  }
450
523
  /**
@@ -468,7 +541,7 @@ export async function embedAll(hippoRoot, model) {
468
541
  }
469
542
  return 0;
470
543
  }
471
- return withEmbedLock(async () => {
544
+ return withEmbedLock(hippoRoot, async () => {
472
545
  const identity = provider.id;
473
546
  // L9: host-wide by design. embedAll backfills vectors for all tenants'
474
547
  // entries into the per-host embedding index. Per-tenant filtering would
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Statistics and cost accounting for the token-efficiency evals (ROADMAP
3
+ * Part IX, TE3-TE5).
4
+ *
5
+ * - Cost: price provider usage over four buckets (uncached input, cache
6
+ * write, cache read, output). Raw token counts overstate savings when most
7
+ * input is already cache reads, so every dollar claim goes through here.
8
+ * - Uncertainty: paired bootstrap over tasks, cluster bootstrap (tasks that
9
+ * share a repository are not independent), and a paired ratio bootstrap for
10
+ * dollars per resolved task.
11
+ *
12
+ * Deterministic: every resampling function takes a seed, so a published
13
+ * result can be reproduced exactly.
14
+ */
15
+ /** Token usage for one model call or one whole task, split by how it is billed. */
16
+ export interface Usage {
17
+ /** Input tokens billed at the base input price (not read from or written to a cache). */
18
+ inputTokens: number;
19
+ /** Input tokens written to a prompt cache. */
20
+ cacheWriteTokens: number;
21
+ /** Input tokens read from a prompt cache. */
22
+ cacheReadTokens: number;
23
+ /** Output tokens, including any reasoning tokens the provider bills as output. */
24
+ outputTokens: number;
25
+ }
26
+ /**
27
+ * Prices in dollars per million tokens. Take them from the provider's
28
+ * current price page for the exact model; this module has no built-in
29
+ * prices because they change.
30
+ */
31
+ export interface Prices {
32
+ inputPerMTok: number;
33
+ cacheWritePerMTok: number;
34
+ cacheReadPerMTok: number;
35
+ outputPerMTok: number;
36
+ }
37
+ /** Sum several usages bucket by bucket. */
38
+ export declare function addUsage(...usages: Usage[]): Usage;
39
+ /** Dollar cost of `usage` at `prices`. */
40
+ export declare function priceUsage(usage: Usage, prices: Prices): number;
41
+ /**
42
+ * Relative prices of the cache buckets against the base input price, for
43
+ * cost in "uncached-equivalent tokens" when no dollar prices are given.
44
+ * Defaults follow Anthropic's published ratios (5-minute cache write 1.25x,
45
+ * cache read 0.1x); pass the ratios for another provider when needed.
46
+ */
47
+ export interface CacheRatios {
48
+ write: number;
49
+ read: number;
50
+ }
51
+ /** Default cache price ratios (write 1.25x, read 0.1x of base input). */
52
+ export declare const DEFAULT_CACHE_RATIOS: Readonly<CacheRatios>;
53
+ /** Input cost of `usage` in uncached-equivalent tokens (output excluded). */
54
+ export declare function uncachedEquivalentInput(usage: Usage, ratios?: CacheRatios): number;
55
+ /**
56
+ * Mulberry32: a small seeded PRNG returning floats in [0, 1). Same seed,
57
+ * same stream, on every platform.
58
+ */
59
+ export declare function seededRandom(seed: number): () => number;
60
+ /** A point estimate with a percentile bootstrap confidence interval. */
61
+ export interface Estimate {
62
+ estimate: number;
63
+ low: number;
64
+ high: number;
65
+ /** Resamples drawn. */
66
+ iterations: number;
67
+ }
68
+ /** Options shared by the bootstrap functions. */
69
+ export interface BootstrapOpts {
70
+ /** Resamples. Default 5000. */
71
+ iterations?: number;
72
+ /** Two-sided level, e.g. 0.05 for a 95% interval. Default 0.05. */
73
+ alpha?: number;
74
+ /** PRNG seed. Default 1. */
75
+ seed?: number;
76
+ }
77
+ /**
78
+ * Paired bootstrap for the mean of per-task differences (treatment minus
79
+ * control on the same task). An interval that excludes zero is the bar for
80
+ * calling a difference real.
81
+ */
82
+ export declare function pairedBootstrap(diffs: number[], opts?: BootstrapOpts): Estimate;
83
+ /**
84
+ * Cluster bootstrap for the mean of per-task differences: resamples whole
85
+ * clusters (for example all tasks from one repository), because tasks in a
86
+ * cluster share causes and are not independent draws.
87
+ */
88
+ export declare function clusteredPairedBootstrap(diffsByCluster: ReadonlyMap<string, number[]>, opts?: BootstrapOpts): Estimate;
89
+ /** One task's outcome in one arm, for {@link costPerResolvedDelta}. */
90
+ export interface ArmOutcome {
91
+ /** Dollars (or uncached-equivalent tokens) spent on the task. */
92
+ cost: number;
93
+ /** Whether the task was resolved. */
94
+ resolved: boolean;
95
+ }
96
+ /** Result of {@link costPerResolvedDelta}. */
97
+ export interface CostPerResolvedDelta {
98
+ control: number;
99
+ treatment: number;
100
+ /** treatment minus control, with its interval. */
101
+ delta: Estimate;
102
+ /** (treatment minus control) / control, with its interval. Negative is a saving. */
103
+ relative: Estimate;
104
+ }
105
+ /**
106
+ * Cost per resolved task in two arms run on the same tasks, with a paired
107
+ * bootstrap over tasks (a task is resampled with both of its arm outcomes).
108
+ * `control[i]` and `treatment[i]` must be the same task. Resamples in which
109
+ * an arm resolves nothing are dropped; `iterations` reports how many were
110
+ * kept.
111
+ */
112
+ export declare function costPerResolvedDelta(control: ArmOutcome[], treatment: ArmOutcome[], opts?: BootstrapOpts): CostPerResolvedDelta;
113
+ /**
114
+ * pass@k: share of tasks with at least one success in their first k runs.
115
+ * NaN when no task has k runs (not measured, which is not the same as 0).
116
+ */
117
+ export declare function passAtK(runsByTask: boolean[][], k: number): number;
118
+ /**
119
+ * pass^k: share of tasks whose first k runs all succeed (consistency).
120
+ * NaN when no task has k runs.
121
+ */
122
+ export declare function passHatK(runsByTask: boolean[][], k: number): number;
123
+ //# sourceMappingURL=eval-stats.d.ts.map