hippo-memory 1.71.0 → 1.72.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 (555) hide show
  1. package/README.md +1 -1
  2. package/dist/agent-memories/apply.d.ts +0 -11
  3. package/dist/agent-memories/apply.js +6 -21
  4. package/dist/agent-memories/claude-code.js +1 -1
  5. package/dist/agent-memories/codex.js +1 -1
  6. package/dist/agent-memories/copilot.d.ts +1 -3
  7. package/dist/agent-memories/copilot.js +1 -17
  8. package/dist/agent-memories/project-folds.d.ts +10 -0
  9. package/dist/agent-memories/project-folds.js +34 -0
  10. package/dist/agent-memories/sync.js +8 -6
  11. package/dist/api/assemble.js +1 -1
  12. package/dist/api/audit.d.ts +29 -1
  13. package/dist/api/audit.js +44 -5
  14. package/dist/api/auth.d.ts +7 -4
  15. package/dist/api/auth.js +12 -8
  16. package/dist/api/auto-sleep.d.ts +5 -2
  17. package/dist/api/auto-sleep.js +7 -3
  18. package/dist/api/availability.js +2 -3
  19. package/dist/api/cards.d.ts +42 -0
  20. package/dist/api/cards.js +52 -0
  21. package/dist/api/conflicts.d.ts +28 -0
  22. package/dist/api/conflicts.js +61 -0
  23. package/dist/api/context-render.js +4 -3
  24. package/dist/api/context-select.js +9 -11
  25. package/dist/api/context.js +17 -8
  26. package/dist/api/continuity.d.ts +47 -0
  27. package/dist/api/continuity.js +66 -0
  28. package/dist/api/dormant.js +4 -2
  29. package/dist/api/drill-down.js +1 -1
  30. package/dist/api/embeddings.d.ts +17 -0
  31. package/dist/api/embeddings.js +28 -0
  32. package/dist/api/error-reply.d.ts +8 -0
  33. package/dist/api/error-reply.js +21 -0
  34. package/dist/api/forget.d.ts +6 -2
  35. package/dist/api/forget.js +18 -7
  36. package/dist/api/goals.d.ts +1 -1
  37. package/dist/api/goals.js +5 -9
  38. package/dist/api/index.d.ts +4 -2
  39. package/dist/api/index.js +4 -2
  40. package/dist/api/instruction-detect.js +5 -1
  41. package/dist/api/learn.d.ts +4 -0
  42. package/dist/api/learn.js +53 -27
  43. package/dist/api/ledger-db.d.ts +2 -6
  44. package/dist/api/ledger-db.js +4 -36
  45. package/dist/api/memories.d.ts +19 -1
  46. package/dist/api/memories.js +39 -0
  47. package/dist/api/objects.d.ts +1 -1
  48. package/dist/api/outcome.js +1 -1
  49. package/dist/api/pilot-arm.d.ts +1 -11
  50. package/dist/api/pilot-arm.js +5 -45
  51. package/dist/api/predictions.d.ts +3 -1
  52. package/dist/api/predictions.js +6 -0
  53. package/dist/api/projects.d.ts +21 -0
  54. package/dist/api/projects.js +24 -0
  55. package/dist/api/promote.js +1 -1
  56. package/dist/api/prompt-hook.d.ts +15 -2
  57. package/dist/api/prompt-hook.js +44 -4
  58. package/dist/api/recall-cli.d.ts +3 -0
  59. package/dist/api/recall-cli.js +13 -4
  60. package/dist/api/recall-core.js +3 -3
  61. package/dist/api/recall-pipeline.js +6 -7
  62. package/dist/api/recall-request.js +1 -1
  63. package/dist/api/recall.d.ts +0 -3
  64. package/dist/api/recall.js +19 -44
  65. package/dist/api/remember-local.js +1 -1
  66. package/dist/api/remember.d.ts +2 -1
  67. package/dist/api/remember.js +3 -2
  68. package/dist/api/session-end.d.ts +22 -0
  69. package/dist/api/session-end.js +101 -0
  70. package/dist/api/sleep-run.d.ts +1 -1
  71. package/dist/api/sleep-run.js +13 -9
  72. package/dist/api/status.d.ts +24 -0
  73. package/dist/api/status.js +40 -0
  74. package/dist/api/store-init.d.ts +4 -0
  75. package/dist/api/store-init.js +9 -0
  76. package/dist/api/tokens.js +1 -1
  77. package/dist/api/types.d.ts +2 -0
  78. package/dist/api/types.js +6 -1
  79. package/dist/capture/caller-session.d.ts +0 -3
  80. package/dist/capture/caller-session.js +1 -12
  81. package/dist/capture/capture-error.d.ts +2 -2
  82. package/dist/capture/capture-error.js +23 -18
  83. package/dist/capture/codex-patch.js +3 -1
  84. package/dist/capture/command.js +36 -95
  85. package/dist/capture/compact.js +10 -5
  86. package/dist/capture/compaction-items-caller.js +11 -20
  87. package/dist/capture/compaction-record.d.ts +7 -93
  88. package/dist/capture/compaction-record.js +29 -426
  89. package/dist/capture/compaction-spool.d.ts +4 -2
  90. package/dist/capture/compaction-spool.js +20 -6
  91. package/dist/capture/copilot-transcript.d.ts +2 -1
  92. package/dist/capture/copilot-transcript.js +2 -1
  93. package/dist/capture/extract.d.ts +5 -2
  94. package/dist/capture/extract.js +4 -3
  95. package/dist/capture/failure-caller.d.ts +1 -1
  96. package/dist/capture/failure-caller.js +21 -16
  97. package/dist/capture/failure-reading.d.ts +2 -1
  98. package/dist/capture/failure-reading.js +7 -9
  99. package/dist/capture/pre-compact-caller.js +5 -4
  100. package/dist/capture/session-digest.js +4 -3
  101. package/dist/capture/session-end-caller.js +2 -1
  102. package/dist/capture/session-worker.js +3 -4
  103. package/dist/capture/transcript.d.ts +2 -1
  104. package/dist/capture/transcript.js +6 -3
  105. package/dist/capture/working-state.d.ts +4 -2
  106. package/dist/capture/working-state.js +4 -2
  107. package/dist/cli/audit-prune.d.ts +0 -25
  108. package/dist/cli/audit-prune.js +1 -27
  109. package/dist/cli/audit.js +13 -13
  110. package/dist/cli/auth.d.ts +1 -1
  111. package/dist/cli/auth.js +12 -13
  112. package/dist/cli/briefs.d.ts +1 -4
  113. package/dist/cli/briefs.js +37 -292
  114. package/dist/cli/card.js +41 -33
  115. package/dist/cli/client.d.ts +5 -0
  116. package/dist/cli/client.js +24 -8
  117. package/dist/cli/compact-resume-payload.js +1 -1
  118. package/dist/cli/context.d.ts +1 -1
  119. package/dist/cli/context.js +12 -12
  120. package/dist/cli/continuity.d.ts +1 -1
  121. package/dist/cli/continuity.js +36 -39
  122. package/dist/cli/curate.d.ts +1 -1
  123. package/dist/cli/curate.js +23 -27
  124. package/dist/cli/dag.d.ts +1 -1
  125. package/dist/cli/dag.js +23 -8
  126. package/dist/cli/decisions.d.ts +0 -2
  127. package/dist/cli/decisions.js +4 -281
  128. package/dist/cli/eval.d.ts +1 -1
  129. package/dist/cli/eval.js +12 -13
  130. package/dist/cli/explain.d.ts +1 -1
  131. package/dist/cli/explain.js +21 -25
  132. package/dist/cli/flag-values.js +16 -6
  133. package/dist/cli/flags.d.ts +0 -289
  134. package/dist/cli/flags.js +3 -138
  135. package/dist/cli/graph.d.ts +3 -0
  136. package/dist/cli/graph.js +83 -0
  137. package/dist/cli/hook-runtime.d.ts +3 -5
  138. package/dist/cli/hook-runtime.js +7 -34
  139. package/dist/cli/incidents.d.ts +3 -0
  140. package/dist/cli/incidents.js +112 -0
  141. package/dist/cli/init.d.ts +1 -1
  142. package/dist/cli/init.js +28 -19
  143. package/dist/cli/install-steps.d.ts +2 -1
  144. package/dist/cli/install-steps.js +11 -3
  145. package/dist/cli/last-sleep.js +1 -1
  146. package/dist/cli/lenient-id.d.ts +2 -0
  147. package/dist/cli/lenient-id.js +13 -0
  148. package/dist/cli/maintenance.d.ts +3 -3
  149. package/dist/cli/maintenance.js +29 -30
  150. package/dist/cli/notes.d.ts +2 -0
  151. package/dist/cli/notes.js +41 -0
  152. package/dist/cli/open-browser.d.ts +14 -0
  153. package/dist/cli/open-browser.js +26 -0
  154. package/dist/cli/playbooks.d.ts +3 -4
  155. package/dist/cli/playbooks.js +126 -290
  156. package/dist/cli/predictions.d.ts +3 -0
  157. package/dist/cli/predictions.js +175 -0
  158. package/dist/cli/print.js +2 -1
  159. package/dist/cli/projects.js +30 -22
  160. package/dist/cli/quality-repair-once.d.ts +1 -1
  161. package/dist/cli/quality-repair-once.js +6 -5
  162. package/dist/cli/recall.js +13 -7
  163. package/dist/cli/refine-llm.js +17 -17
  164. package/dist/cli/remember.js +12 -12
  165. package/dist/cli/scheduler.js +2 -1
  166. package/dist/cli/serve.js +3 -3
  167. package/dist/cli/session-hooks.d.ts +1 -1
  168. package/dist/cli/session-hooks.js +45 -115
  169. package/dist/cli/setup.d.ts +1 -1
  170. package/dist/cli/setup.js +17 -10
  171. package/dist/cli/shared.d.ts +2 -6
  172. package/dist/cli/shared.js +9 -29
  173. package/dist/cli/sleep-render.js +6 -3
  174. package/dist/cli/sleep.js +6 -37
  175. package/dist/cli/status.d.ts +3 -3
  176. package/dist/cli/status.js +32 -35
  177. package/dist/cli/transfer.d.ts +1 -1
  178. package/dist/cli/transfer.js +33 -31
  179. package/dist/cli/usage.d.ts +0 -79
  180. package/dist/cli/usage.js +1 -695
  181. package/dist/cli/verb-row.d.ts +32 -0
  182. package/dist/cli/verb-row.js +6 -0
  183. package/dist/cli/verbs/health.d.ts +27 -0
  184. package/dist/cli/verbs/health.js +232 -0
  185. package/dist/cli/verbs/memory.d.ts +16 -0
  186. package/dist/cli/verbs/memory.js +244 -0
  187. package/dist/cli/verbs/objects.d.ts +20 -0
  188. package/dist/cli/verbs/objects.js +254 -0
  189. package/dist/cli/verbs/sessions.d.ts +31 -0
  190. package/dist/cli/verbs/sessions.js +312 -0
  191. package/dist/cli/verbs.d.ts +81 -0
  192. package/dist/cli/verbs.js +7 -0
  193. package/dist/cli/versioned-verbs.d.ts +51 -0
  194. package/dist/cli/versioned-verbs.js +79 -0
  195. package/dist/cli.d.ts +1 -272
  196. package/dist/cli.js +23 -313
  197. package/dist/connectors/dlq.d.ts +39 -3
  198. package/dist/connectors/dlq.js +37 -3
  199. package/dist/connectors/github/backfill.js +12 -3
  200. package/dist/connectors/github/dlq.js +31 -73
  201. package/dist/connectors/github/ingest.d.ts +2 -6
  202. package/dist/connectors/github/ingest.js +3 -28
  203. package/dist/connectors/github/webhook.d.ts +2 -1
  204. package/dist/connectors/github/webhook.js +33 -2
  205. package/dist/connectors/ingest.d.ts +10 -0
  206. package/dist/connectors/ingest.js +28 -0
  207. package/dist/connectors/slack/dlq.js +49 -71
  208. package/dist/connectors/slack/ingest.d.ts +2 -6
  209. package/dist/connectors/slack/ingest.js +2 -27
  210. package/dist/connectors/slack/webhook.d.ts +2 -1
  211. package/dist/connectors/slack/webhook.js +2 -1
  212. package/dist/consolidate/conflicts.js +1 -1
  213. package/dist/consolidate/dag.js +15 -9
  214. package/dist/consolidate/dedupe.d.ts +7 -0
  215. package/dist/consolidate/dedupe.js +5 -3
  216. package/dist/consolidate/llm-passes.js +45 -19
  217. package/dist/consolidate/memory-value.js +2 -1
  218. package/dist/consolidate/merge.js +2 -2
  219. package/dist/consolidate/physics-pass.d.ts +6 -1
  220. package/dist/consolidate/physics-pass.js +26 -6
  221. package/dist/consolidate/replay.js +11 -4
  222. package/dist/consolidate/sleep.js +8 -5
  223. package/dist/consolidate/traces.js +3 -3
  224. package/dist/core/ablation.d.ts +10 -0
  225. package/dist/core/ablation.js +12 -0
  226. package/dist/{sharing/scope.d.ts → core/active-scope.d.ts} +1 -1
  227. package/dist/{sharing/scope.js → core/active-scope.js} +1 -1
  228. package/dist/core/ambient.d.ts +4 -0
  229. package/dist/core/ambient.js +39 -18
  230. package/dist/core/api-errors.d.ts +16 -0
  231. package/dist/core/api-errors.js +20 -0
  232. package/dist/core/card.js +3 -1
  233. package/dist/core/compaction-timing.d.ts +7 -0
  234. package/dist/core/compaction-timing.js +9 -0
  235. package/dist/core/config.d.ts +1 -1
  236. package/dist/core/config.js +7 -2
  237. package/dist/core/cosine.d.ts +3 -0
  238. package/dist/core/cosine.js +19 -0
  239. package/dist/{store → core}/markdown.d.ts +1 -1
  240. package/dist/{store → core}/markdown.js +2 -2
  241. package/dist/core/memory-audit.d.ts +17 -0
  242. package/dist/core/memory-audit.js +54 -0
  243. package/dist/core/memory.d.ts +10 -4
  244. package/dist/core/memory.js +25 -18
  245. package/dist/{consolidate → core}/merged-row.d.ts +1 -1
  246. package/dist/{consolidate → core}/merged-row.js +1 -1
  247. package/dist/core/physics.js +6 -16
  248. package/dist/core/prediction.d.ts +3 -0
  249. package/dist/core/prediction.js +6 -0
  250. package/dist/core/project-identity.d.ts +3 -0
  251. package/dist/core/project-identity.js +10 -1
  252. package/dist/{store → core}/recall-scope.d.ts +1 -10
  253. package/dist/{store → core}/recall-scope.js +2 -19
  254. package/dist/db/busy.d.ts +2 -7
  255. package/dist/db/busy.js +21 -26
  256. package/dist/db/connect.d.ts +0 -1
  257. package/dist/db/connect.js +5 -6
  258. package/dist/db/index.d.ts +3 -3
  259. package/dist/db/index.js +3 -3
  260. package/dist/db/migrations/index.d.ts +1 -1
  261. package/dist/db/migrations/index.js +3 -1
  262. package/dist/db/migrations/v55.d.ts +3 -0
  263. package/dist/db/migrations/v55.js +17 -0
  264. package/dist/db/open.d.ts +0 -2
  265. package/dist/db/open.js +6 -10
  266. package/dist/db/physics-state.js +3 -3
  267. package/dist/db/tables.d.ts +2 -0
  268. package/dist/db/tables.js +6 -2
  269. package/dist/db/vector-store.js +17 -4
  270. package/dist/db/wal-checkpointer.js +2 -1
  271. package/dist/doctor.js +11 -8
  272. package/dist/embeddings/local.d.ts +62 -0
  273. package/dist/embeddings/local.js +146 -0
  274. package/dist/{store/embeddings → embeddings}/provider.d.ts +5 -2
  275. package/dist/{store/embeddings → embeddings}/provider.js +18 -15
  276. package/dist/embeddings/transformers.d.ts +26 -0
  277. package/dist/embeddings/transformers.js +89 -0
  278. package/dist/entry/session-text.d.ts +1 -1
  279. package/dist/entry/session-text.js +1 -1
  280. package/dist/eval/eval-suite.js +17 -11
  281. package/dist/eval/eval.js +1 -1
  282. package/dist/eval/judgment.js +11 -4
  283. package/dist/graph/extract.js +3 -3
  284. package/dist/graph/recall.js +1 -1
  285. package/dist/graph/view.js +13 -5
  286. package/dist/graph/write.d.ts +1 -1
  287. package/dist/graph/write.js +9 -9
  288. package/dist/hooks/codex-session.js +3 -2
  289. package/dist/hooks/codex-wrapper.js +2 -1
  290. package/dist/hooks/json-hooks.js +4 -2
  291. package/dist/hooks/opencode.js +8 -5
  292. package/dist/hooks/shared.d.ts +0 -6
  293. package/dist/hooks/shared.js +4 -15
  294. package/dist/importers/core.js +1 -1
  295. package/dist/importers/sources.js +5 -4
  296. package/dist/importers/vault.js +7 -5
  297. package/dist/index.d.ts +3 -2
  298. package/dist/index.js +3 -2
  299. package/dist/learn/autolearn.d.ts +10 -2
  300. package/dist/learn/autolearn.js +32 -12
  301. package/dist/learn/churn-git.js +13 -4
  302. package/dist/learn/extract.d.ts +3 -2
  303. package/dist/learn/extract.js +6 -4
  304. package/dist/learn/forward-claim-detector.js +4 -2
  305. package/dist/learn/invalidation.js +10 -6
  306. package/dist/mcp/admin-tools.d.ts +2 -2
  307. package/dist/mcp/admin-tools.js +27 -48
  308. package/dist/mcp/format.js +3 -2
  309. package/dist/mcp/framing.d.ts +1 -0
  310. package/dist/mcp/framing.js +1 -1
  311. package/dist/mcp/memory-tools.js +3 -1
  312. package/dist/mcp/protocol.d.ts +11 -7
  313. package/dist/mcp/protocol.js +25 -12
  314. package/dist/mcp/recall-tools.js +12 -9
  315. package/dist/mcp/request.js +2 -1
  316. package/dist/mcp/stdio.js +24 -8
  317. package/dist/mcp/tool-args.js +2 -1
  318. package/dist/mcp/tools.js +44 -21
  319. package/dist/objects/customer-notes.d.ts +2 -2
  320. package/dist/objects/decisions.d.ts +2 -2
  321. package/dist/objects/descriptor.d.ts +1 -1
  322. package/dist/objects/incidents.d.ts +2 -2
  323. package/dist/objects/lifecycle.d.ts +1 -1
  324. package/dist/objects/lifecycle.js +2 -1
  325. package/dist/objects/policies.d.ts +2 -2
  326. package/dist/objects/policies.js +2 -1
  327. package/dist/objects/processes.d.ts +2 -2
  328. package/dist/objects/project-briefs.d.ts +2 -2
  329. package/dist/objects/project-briefs.js +2 -3
  330. package/dist/objects/skills.d.ts +2 -2
  331. package/dist/postinstall.js +1 -1
  332. package/dist/rerankers/clef.js +3 -6
  333. package/dist/rerankers/cross-encoder.d.ts +31 -2
  334. package/dist/rerankers/cross-encoder.js +63 -97
  335. package/dist/rerankers/index.js +5 -4
  336. package/dist/rerankers/jev.js +2 -4
  337. package/dist/rerankers/outage-warning.d.ts +3 -1
  338. package/dist/rerankers/outage-warning.js +5 -3
  339. package/dist/search/bm25-search.js +1 -1
  340. package/dist/search/boosts.js +1 -1
  341. package/dist/search/embed-memories.d.ts +9 -0
  342. package/dist/search/embed-memories.js +377 -0
  343. package/dist/search/goal-boost.d.ts +1 -1
  344. package/dist/search/goal-boost.js +6 -3
  345. package/dist/search/hybrid.d.ts +9 -2
  346. package/dist/search/hybrid.js +9 -4
  347. package/dist/search/physics-search.d.ts +6 -3
  348. package/dist/search/physics-search.js +22 -15
  349. package/dist/search/rerank.js +1 -1
  350. package/dist/search/vector.d.ts +8 -6
  351. package/dist/search/vector.js +10 -13
  352. package/dist/server/auth.d.ts +2 -0
  353. package/dist/server/auth.js +17 -7
  354. package/dist/server/boot.js +7 -66
  355. package/dist/server/client-ip.d.ts +0 -2
  356. package/dist/server/client-ip.js +3 -2
  357. package/dist/server/deadline.d.ts +0 -2
  358. package/dist/server/deadline.js +1 -7
  359. package/dist/server/defaults.d.ts +1 -0
  360. package/dist/server/defaults.js +1 -0
  361. package/dist/server/mcp-http.js +16 -11
  362. package/dist/server/request.js +7 -2
  363. package/dist/server/route-checks.d.ts +7 -0
  364. package/dist/server/route-checks.js +42 -0
  365. package/dist/server/route-table.d.ts +9 -8
  366. package/dist/server/route-table.js +127 -132
  367. package/dist/server/routes/admin.d.ts +8 -8
  368. package/dist/server/routes/admin.js +13 -21
  369. package/dist/server/routes/customer-notes.d.ts +6 -6
  370. package/dist/server/routes/customer-notes.js +1 -2
  371. package/dist/server/routes/decisions.d.ts +6 -6
  372. package/dist/server/routes/decisions.js +2 -4
  373. package/dist/server/routes/incidents.d.ts +6 -6
  374. package/dist/server/routes/incidents.js +2 -5
  375. package/dist/server/routes/memories.d.ts +9 -9
  376. package/dist/server/routes/memories.js +15 -38
  377. package/dist/server/routes/object-routes.d.ts +6 -6
  378. package/dist/server/routes/object-routes.js +4 -7
  379. package/dist/server/routes/policies.d.ts +7 -7
  380. package/dist/server/routes/policies.js +2 -4
  381. package/dist/server/routes/predictions.d.ts +6 -6
  382. package/dist/server/routes/predictions.js +9 -13
  383. package/dist/server/routes/processes.d.ts +6 -6
  384. package/dist/server/routes/processes.js +1 -2
  385. package/dist/server/routes/project-briefs.d.ts +7 -7
  386. package/dist/server/routes/project-briefs.js +2 -4
  387. package/dist/server/routes/recall.d.ts +5 -5
  388. package/dist/server/routes/recall.js +6 -10
  389. package/dist/server/routes/skills.d.ts +7 -7
  390. package/dist/server/routes/skills.js +2 -4
  391. package/dist/server/server-detect.d.ts +7 -1
  392. package/dist/server/server-detect.js +36 -11
  393. package/dist/server/sleep-child.js +26 -7
  394. package/dist/server/sleep-offload.d.ts +11 -5
  395. package/dist/server/sleep-offload.js +17 -11
  396. package/dist/server/types.d.ts +22 -10
  397. package/dist/server/validation.d.ts +1 -2
  398. package/dist/server/validation.js +6 -11
  399. package/dist/server.d.ts +5 -4
  400. package/dist/server.js +5 -4
  401. package/dist/sharing/global-store.js +2 -2
  402. package/dist/sharing/global-sync.js +38 -45
  403. package/dist/sharing/project-merge.d.ts +7 -14
  404. package/dist/sharing/project-merge.js +57 -121
  405. package/dist/sharing/search-both.js +1 -1
  406. package/dist/sharing/share.d.ts +2 -0
  407. package/dist/sharing/share.js +37 -34
  408. package/dist/store/ambient.js +5 -6
  409. package/dist/store/audit-event.d.ts +1 -1
  410. package/dist/store/audit.d.ts +0 -16
  411. package/dist/store/audit.js +4 -55
  412. package/dist/store/auth.d.ts +4 -2
  413. package/dist/store/auth.js +7 -3
  414. package/dist/store/candidates.d.ts +3 -2
  415. package/dist/store/candidates.js +42 -23
  416. package/dist/store/capture-write.d.ts +17 -0
  417. package/dist/store/capture-write.js +35 -0
  418. package/dist/store/cards.js +1 -1
  419. package/dist/store/compaction-caller.d.ts +18 -0
  420. package/dist/store/compaction-caller.js +29 -0
  421. package/dist/store/compactions-record.d.ts +115 -0
  422. package/dist/store/compactions-record.js +417 -0
  423. package/dist/store/compactions.js +6 -4
  424. package/dist/store/conflicts.js +7 -4
  425. package/dist/store/connectors/dlq.d.ts +10 -0
  426. package/dist/store/connectors/dlq.js +32 -0
  427. package/dist/store/connectors/github.d.ts +7 -9
  428. package/dist/store/connectors/github.js +30 -53
  429. package/dist/store/connectors/slack.d.ts +2 -11
  430. package/dist/store/connectors/slack.js +18 -47
  431. package/dist/store/dashboard-reads.js +7 -6
  432. package/dist/store/delete-and-batch.d.ts +6 -0
  433. package/dist/store/delete-and-batch.js +36 -3
  434. package/dist/store/delivery-recorder.d.ts +10 -3
  435. package/dist/store/delivery-recorder.js +12 -5
  436. package/dist/store/descendant-page.js +6 -3
  437. package/dist/store/dormant.d.ts +1 -1
  438. package/dist/store/dormant.js +3 -1
  439. package/dist/store/embeddings/index.d.ts +2 -12
  440. package/dist/store/embeddings/index.js +5 -374
  441. package/dist/store/entry-reads.d.ts +13 -4
  442. package/dist/store/entry-reads.js +47 -11
  443. package/dist/store/entry-writes.d.ts +5 -5
  444. package/dist/store/entry-writes.js +32 -12
  445. package/dist/store/failure-log-at.d.ts +8 -0
  446. package/dist/store/failure-log-at.js +16 -0
  447. package/dist/store/failure-log.d.ts +2 -2
  448. package/dist/store/failure-log.js +5 -3
  449. package/dist/{trust → store}/gated-write.d.ts +3 -1
  450. package/dist/{trust → store}/gated-write.js +7 -5
  451. package/dist/store/goals.js +20 -18
  452. package/dist/store/graph-reads.js +4 -2
  453. package/dist/store/graph-writes.d.ts +6 -6
  454. package/dist/store/graph-writes.js +48 -71
  455. package/dist/store/handoffs.d.ts +1 -1
  456. package/dist/store/handoffs.js +6 -6
  457. package/dist/store/index-and-stats.js +2 -2
  458. package/dist/store/key-writes.js +1 -1
  459. package/dist/store/ledger-turn.d.ts +9 -0
  460. package/dist/store/ledger-turn.js +38 -0
  461. package/dist/store/mirrors.js +10 -6
  462. package/dist/store/open.d.ts +0 -4
  463. package/dist/store/open.js +40 -53
  464. package/dist/store/pilot-arm.d.ts +12 -0
  465. package/dist/store/pilot-arm.js +42 -0
  466. package/dist/store/port.d.ts +9 -3
  467. package/dist/store/port.js +8 -0
  468. package/dist/store/predictions.d.ts +1 -2
  469. package/dist/store/predictions.js +3 -6
  470. package/dist/store/project-tags.d.ts +62 -0
  471. package/dist/store/project-tags.js +67 -0
  472. package/dist/store/quarantine.js +2 -1
  473. package/dist/store/recall-trace.d.ts +2 -0
  474. package/dist/store/recall-trace.js +18 -2
  475. package/dist/store/rejected-values.js +2 -1
  476. package/dist/store/rejection-probe.d.ts +4 -0
  477. package/dist/store/rejection-probe.js +19 -0
  478. package/dist/store/rejection.d.ts +0 -17
  479. package/dist/store/rejection.js +1 -21
  480. package/dist/store/rule-sql.d.ts +9 -0
  481. package/dist/store/rule-sql.js +21 -2
  482. package/dist/store/search-rows.js +9 -4
  483. package/dist/store/sessions.js +4 -2
  484. package/dist/store/set-aside.d.ts +14 -0
  485. package/dist/store/set-aside.js +23 -0
  486. package/dist/store/sqlite/busy.d.ts +3 -0
  487. package/dist/store/sqlite/busy.js +8 -0
  488. package/dist/store/sqlite/connector-events-group.js +4 -7
  489. package/dist/store/sqlite/connector-writes-group.js +3 -3
  490. package/dist/store/sqlite/entry-writes-group.js +2 -2
  491. package/dist/store/sqlite/error-codec.js +4 -3
  492. package/dist/store/sqlite/executor.js +10 -4
  493. package/dist/store/sqlite/graph-reads-group.js +1 -1
  494. package/dist/store/sqlite/held-connection.d.ts +9 -0
  495. package/dist/store/sqlite/held-connection.js +41 -0
  496. package/dist/store/sqlite/object-rows.d.ts +1 -1
  497. package/dist/store/sqlite/objects-group.d.ts +1 -1
  498. package/dist/store/sqlite/objects-group.js +1 -1
  499. package/dist/store/sqlite/store.js +14 -12
  500. package/dist/store/summaries.d.ts +3 -3
  501. package/dist/store/summaries.js +5 -4
  502. package/dist/store/token-ledger.d.ts +0 -7
  503. package/dist/store/token-ledger.js +0 -35
  504. package/dist/store/vector-index.js +3 -2
  505. package/dist/support-bundle.js +2 -3
  506. package/dist/trust/reject-flow.js +2 -2
  507. package/dist/util/agent-homes.d.ts +15 -0
  508. package/dist/util/agent-homes.js +34 -0
  509. package/dist/util/anthropic-messages.d.ts +3 -0
  510. package/dist/util/anthropic-messages.js +22 -5
  511. package/dist/util/chunked.d.ts +3 -0
  512. package/dist/util/chunked.js +10 -0
  513. package/dist/util/ellipsize.d.ts +3 -0
  514. package/dist/util/ellipsize.js +5 -0
  515. package/dist/util/env.d.ts +2 -1
  516. package/dist/util/env.js +2 -1
  517. package/dist/util/format.d.ts +3 -0
  518. package/dist/util/format.js +6 -0
  519. package/dist/util/hook-payload.d.ts +8 -0
  520. package/dist/util/hook-payload.js +37 -0
  521. package/dist/util/http-retry.d.ts +6 -0
  522. package/dist/util/http-retry.js +43 -5
  523. package/dist/util/http-util.d.ts +0 -8
  524. package/dist/util/http-util.js +10 -21
  525. package/dist/util/limits.d.ts +7 -0
  526. package/dist/util/limits.js +14 -0
  527. package/dist/util/log.d.ts +4 -0
  528. package/dist/util/log.js +9 -0
  529. package/dist/util/request-scope.d.ts +3 -1
  530. package/dist/util/request-scope.js +11 -6
  531. package/dist/util/secret-detect.js +6 -1
  532. package/dist/util/sqlite-blocked.d.ts +2 -0
  533. package/dist/util/sqlite-blocked.js +5 -0
  534. package/dist/util/stream-tee.d.ts +3 -0
  535. package/dist/util/stream-tee.js +35 -0
  536. package/dist/util/time.d.ts +4 -0
  537. package/dist/util/time.js +4 -0
  538. package/dist/util/version.d.ts +1 -1
  539. package/dist/util/version.js +1 -1
  540. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  541. package/extensions/openclaw-plugin/package.json +1 -1
  542. package/openclaw.plugin.json +1 -1
  543. package/package.json +2 -2
  544. package/dist/store/embeddings/local.d.ts +0 -15
  545. package/dist/store/embeddings/local.js +0 -175
  546. /package/dist/{cli → api}/correction-latency.d.ts +0 -0
  547. /package/dist/{cli → api}/correction-latency.js +0 -0
  548. /package/dist/{cli → api}/provenance-coverage.d.ts +0 -0
  549. /package/dist/{cli → api}/provenance-coverage.js +0 -0
  550. /package/dist/{store → core}/object-types.d.ts +0 -0
  551. /package/dist/{store → core}/object-types.js +0 -0
  552. /package/dist/{capture → util}/compaction-items.d.ts +0 -0
  553. /package/dist/{capture → util}/compaction-items.js +0 -0
  554. /package/dist/{store → util}/yaml.d.ts +0 -0
  555. /package/dist/{store → util}/yaml.js +0 -0
@@ -1,6 +1,7 @@
1
1
  import { existsSync, readFileSync, writeFileSync, unlinkSync, renameSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import { envHealthProbeMs } from '../util/env.js';
4
+ import { errorCode, errorFields, errorMessage, log } from '../util/log.js';
4
5
  // Pidfile sits directly inside hippoRoot (the `.hippo` directory itself, as for openHippoDb), i.e. `${hippoRoot}/server.pid`.
5
6
  const PIDFILE = 'server.pid';
6
7
  /** How long detectServer waits for the `/health` probe before treating the pidfile as stale; short because it fires only when a pidfile exists with a live
@@ -11,6 +12,15 @@ const HEALTH_PROBE_TIMEOUT_MS = 300;
11
12
  const HEALTH_BODY_MAX_BYTES = 64 * 1024;
12
13
  /** Loopback hosts a recorded pidfile url may point at (serve() only binds these); any other host is malformed or forged and is not probed. */
13
14
  const PIDFILE_LOOPBACK_HOSTS = new Set(['127.0.0.1', '::1', 'localhost']);
15
+ /** The pidfile names a live process on loopback that did not answer /health in time: most likely a busy server, so a caller must neither
16
+ * bypass it with a second writer nor start another server beside it. */
17
+ export class ServerUnresponsiveError extends Error {
18
+ constructor(info, probeMs, options) {
19
+ super(`a hippo server (pid ${info.pid}) is recorded at ${info.url} but did not answer /health within ${probeMs} ms; it may be busy. ` +
20
+ 'Retry shortly, raise HIPPO_HEALTH_PROBE_MS, or stop that server.', options);
21
+ this.name = 'ServerUnresponsiveError';
22
+ }
23
+ }
14
24
  /** False when the pidfile's pid is dead or its url could not be one serve() wrote. */
15
25
  function isLiveLoopbackTarget(info) {
16
26
  // Signal 0 throws if the pid is dead or owned by another user we cannot signal; either way, treat as stale.
@@ -56,14 +66,23 @@ async function readCappedBody(body) {
56
66
  raw += decoder.decode();
57
67
  return raw;
58
68
  }
59
- /** True when /health on info.url reports the pidfile's started_at; unlinks the pidfile on any definitive mismatch. */
69
+ /** True when fetch failed because nothing listens on the port (the error or its cause, or any address tried, is ECONNREFUSED). */
70
+ function isConnectionRefused(err) {
71
+ if (errorCode(err) === 'ECONNREFUSED')
72
+ return true;
73
+ const cause = err instanceof Error ? err.cause : undefined;
74
+ if (errorCode(cause) === 'ECONNREFUSED')
75
+ return true;
76
+ return cause instanceof AggregateError && cause.errors.length > 0 && cause.errors.every((e) => errorCode(e) === 'ECONNREFUSED');
77
+ }
78
+ /** True when /health on info.url reports the pidfile's started_at; unlinks the pidfile on any definitive mismatch and throws ServerUnresponsiveError on a
79
+ * probe timeout. */
60
80
  async function healthMatchesPidfile(hippoRoot, info) {
61
- // Confirm the answering process is this server by matching /health `started_at` against the pidfile; refusal, non-200 or a malformed body unlink the
62
- // pidfile as stale. A probe timeout is ambiguous (a live but busy server can miss the 300ms window), so it returns null WITHOUT unlinking.
81
+ // Refusal, non-200 or a malformed body unlink the pidfile as stale. A timeout proves neither a dead server nor this one, so it keeps the pidfile and throws.
82
+ // Any other error keeps it and warns.
83
+ const probeMs = envHealthProbeMs() ?? HEALTH_PROBE_TIMEOUT_MS;
63
84
  try {
64
- const res = await fetch(`${info.url}/health`, {
65
- signal: AbortSignal.timeout(envHealthProbeMs() ?? HEALTH_PROBE_TIMEOUT_MS),
66
- });
85
+ const res = await fetch(`${info.url}/health`, { signal: AbortSignal.timeout(probeMs) });
67
86
  if (!res.ok || !res.body) {
68
87
  removePidfile(hippoRoot);
69
88
  return false;
@@ -81,16 +100,21 @@ async function healthMatchesPidfile(hippoRoot, info) {
81
100
  return true;
82
101
  }
83
102
  catch (err) {
84
- // A timeout is ambiguous (the server may be busy), so keep the pidfile; any other failure (refused, malformed body) is definitive: unlink as stale.
85
- // SAFETY: err's shape is unknown (catch clause); reading an optional .name property structurally is safe regardless of the actual type.
86
- if (err?.name !== 'TimeoutError') {
103
+ if (err instanceof Error && err.name === 'TimeoutError')
104
+ throw new ServerUnresponsiveError(info, probeMs, { cause: err });
105
+ // A refusal or a non-JSON body proves no hippo server answers there; any other failure may be a live server, so the file stays.
106
+ if (isConnectionRefused(err) || err instanceof SyntaxError) {
87
107
  removePidfile(hippoRoot);
88
108
  }
109
+ else {
110
+ log.warn(`server pidfile ${join(hippoRoot, PIDFILE)} kept: the /health probe failed (${errorMessage(err)})`, errorFields(err));
111
+ }
89
112
  return false;
90
113
  }
91
114
  }
92
115
  /** Returns the pidfile's ServerInfo if a live hippo server answers on the recorded url, else null (best-effort unlinking of missing/stale/malformed pidfiles).
93
- * `process.kill(pid, 0)` rules out dead pids; GET /health must then return the pidfile's `started_at` (pids get reused). Probes only if the pid is live. */
116
+ * `process.kill(pid, 0)` rules out dead pids; GET /health must then return the pidfile's `started_at` (pids get reused). Probes only if the pid is live.
117
+ * Throws ServerUnresponsiveError when that probe times out. */
94
118
  export async function detectServer(hippoRoot) {
95
119
  const path = join(hippoRoot, PIDFILE);
96
120
  if (!existsSync(path))
@@ -99,7 +123,8 @@ export async function detectServer(hippoRoot) {
99
123
  try {
100
124
  info = JSON.parse(readFileSync(path, 'utf8'));
101
125
  }
102
- catch {
126
+ catch (err) {
127
+ log.warn(`server pidfile ${path} is unreadable (${errorMessage(err)}); removing it`);
103
128
  removePidfile(hippoRoot);
104
129
  return null;
105
130
  }
@@ -1,19 +1,38 @@
1
- // Entry of the process that runs one POST /v1/sleep; sleep-offload.ts starts it and nothing imports it.
2
- // The sleep module alone: the api barrel loads far more than one sleep needs, and every sleep pays for the start.
1
+ // Entry of the process that runs one POST /v1/sleep or MCP auto-sleep; sleep-offload.ts starts it and nothing imports it.
2
+ // The sleep modules alone: the api barrel loads far more than one sleep needs, and every sleep pays for the start.
3
3
  import { sleep } from '../api/sleep.js';
4
- import { isStoreBusy, runWithRequestStores, SERVER_DB_WAIT_MS } from '../db/index.js';
5
- import { errorMessage } from '../util/log.js';
4
+ import { consolidate } from '../consolidate/sleep.js';
5
+ import { runWithRequestStores, SERVER_DB_WAIT_MS } from '../db/index.js';
6
+ import { isStoreBusy } from '../store/sqlite/busy.js';
7
+ import { errorFields, errorMessage, log } from '../util/log.js';
6
8
  function failed(err) {
7
9
  return { ok: false, busy: isStoreBusy(err), message: errorMessage(err), stack: err instanceof Error ? err.stack : undefined };
8
10
  }
11
+ /** Resolves to the exit code once the channel has taken the reply, or failed to. */
12
+ function sendReply(reply) {
13
+ return new Promise((resolve) => {
14
+ process.send?.(reply, (sendErr) => {
15
+ if (sendErr)
16
+ log.error(`sleep child: sending the reply failed: ${errorMessage(sendErr)}`, errorFields(sendErr));
17
+ resolve(sendErr ? 1 : 0);
18
+ });
19
+ });
20
+ }
9
21
  process.once('message', (message) => {
10
22
  // SAFETY: sleep-offload.ts is the only writer on this channel and sends exactly one SleepJob.
11
23
  const job = message;
12
- const ctx = { hippoRoot: job.hippoRoot, tenantId: job.tenantId, actor: job.actor };
24
+ const work = () => job.kind === 'consolidate'
25
+ ? consolidate(job.hippoRoot)
26
+ : sleep({ hippoRoot: job.hippoRoot, tenantId: job.tenantId, actor: job.actor }, job.opts);
13
27
  // The server's own request scope and lock wait, so a busy store answers as it did when sleep ran in the server.
14
- runWithRequestStores(() => sleep(ctx, job.opts), { busyWaitMs: SERVER_DB_WAIT_MS })
28
+ runWithRequestStores(work, { busyWaitMs: SERVER_DB_WAIT_MS })
15
29
  .then((result) => ({ ok: true, result }), failed)
16
30
  // Exit only once the reply is written, or the parent could see the process end first.
17
- .then((reply) => process.send?.(reply, () => process.exit(0)));
31
+ .then(sendReply)
32
+ .catch((err) => {
33
+ log.error(`sleep child: the reply could not be sent: ${errorMessage(err)}`, errorFields(err));
34
+ return 1;
35
+ })
36
+ .then((code) => process.exit(code));
18
37
  });
19
38
  //# sourceMappingURL=sleep-child.js.map
@@ -1,14 +1,18 @@
1
1
  import { type Actor, type Context, type SleepOpts, type SleepResult } from '../api/index.js';
2
- /** What the child needs to rebuild the request's context; the store handle itself cannot cross a process boundary. */
3
- export interface SleepJob {
2
+ /** What the child needs to rebuild the request's context (the store handle itself cannot cross a process boundary), or the store an auto-sleep consolidates. */
3
+ export type SleepJob = {
4
+ readonly kind: 'sleep';
4
5
  readonly hippoRoot: string;
5
6
  readonly tenantId: string;
6
7
  readonly actor: Actor;
7
8
  readonly opts: SleepOpts;
8
- }
9
- export type SleepReply = {
9
+ } | {
10
+ readonly kind: 'consolidate';
11
+ readonly hippoRoot: string;
12
+ };
13
+ export type SleepReply<R = SleepResult> = {
10
14
  readonly ok: true;
11
- readonly result: SleepResult;
15
+ readonly result: R;
12
16
  } | {
13
17
  readonly ok: false;
14
18
  readonly busy: boolean;
@@ -17,4 +21,6 @@ export type SleepReply = {
17
21
  };
18
22
  /** `sleep` for the HTTP route: same result and errors, run outside the serving process and stopped at the deadline (10 minutes, or HIPPO_SLEEP_TIMEOUT_MS). */
19
23
  export declare function sleepInChild(ctx: Context, opts: SleepOpts): Promise<SleepResult>;
24
+ /** The MCP auto-sleep's consolidation, in the same queue and child as POST /v1/sleep; auto-sleep only starts on a hippo.db store. */
25
+ export declare function consolidateInChild(hippoRoot: string): Promise<void>;
20
26
  //# sourceMappingURL=sleep-offload.d.ts.map
@@ -1,8 +1,8 @@
1
- // POST /v1/sleep runs its consolidation in a child process, so the server keeps answering and a stuck run can be stopped.
1
+ // POST /v1/sleep and the MCP auto-sleep run their consolidation in a child process, so the server keeps answering and a stuck run can be stopped.
2
2
  import { spawn } from 'node:child_process';
3
3
  import { fileURLToPath } from 'node:url';
4
4
  import { sleep } from '../api/index.js';
5
- import { StoreBusyError } from '../db/index.js';
5
+ import { StoreBusyError } from '../store/port.js';
6
6
  import { envSleepTimeoutMs } from '../util/env.js';
7
7
  import { HttpError } from '../util/http-util.js';
8
8
  const DEFAULT_SLEEP_DEADLINE_MS = 600_000;
@@ -32,7 +32,7 @@ function runInChild(job) {
32
32
  // SIGKILL because the child is inside synchronous SQLite work and cannot run a handler; the OS drops its write lock.
33
33
  const timer = setTimeout(() => { timedOut = true; child.kill('SIGKILL'); }, deadlineMs);
34
34
  child.once('message', (message) => {
35
- // SAFETY: sleep-child.ts is the only writer on this channel and sends exactly one SleepReply.
35
+ // SAFETY: sleep-child.ts is the only writer on this channel and sends exactly one SleepReply for the job it was given.
36
36
  reply = message;
37
37
  });
38
38
  child.once('error', (err) => { clearTimeout(timer); reject(err); });
@@ -54,20 +54,26 @@ let turn = Promise.resolve();
54
54
  const MAX_SLEEPS_IN_LINE = 2;
55
55
  const SLEEP_RETRY_AFTER_SEC = 30;
56
56
  let inLine = 0;
57
- /** `sleep` for the HTTP route: same result and errors, run outside the serving process and stopped at the deadline (10 minutes, or HIPPO_SLEEP_TIMEOUT_MS). */
58
- export function sleepInChild(ctx, opts) {
59
- // The child reopens the store by path, which only SQLite has; any other store keeps sleep's own refusal.
60
- if (ctx.store && ctx.store.kind !== 'sqlite')
61
- return sleep(ctx, opts);
57
+ function inTurn(job) {
62
58
  if (inLine >= MAX_SLEEPS_IN_LINE) {
63
59
  return Promise.reject(new HttpError(503, 'a sleep is already running and another is waiting; retry when one has finished', SLEEP_RETRY_AFTER_SEC));
64
60
  }
65
61
  inLine += 1;
66
- const job = { hippoRoot: ctx.hippoRoot, tenantId: ctx.tenantId, actor: ctx.actor, opts };
67
- // One sleep at a time, as on the server's single thread: a second request waits its turn and does not fight the first for the write lock.
62
+ // One sleep at a time, as on the server's single thread: a second one waits its turn and does not fight the first for the write lock.
68
63
  const run = turn.then(() => runInChild(job));
69
- // A failed sleep reaches its own request through `run`; the queue only needs to know the turn is over.
64
+ // A failed sleep reaches its own caller through `run`; the queue only needs to know the turn is over.
70
65
  turn = run.then(() => undefined, () => undefined).finally(() => { inLine -= 1; });
71
66
  return run;
72
67
  }
68
+ /** `sleep` for the HTTP route: same result and errors, run outside the serving process and stopped at the deadline (10 minutes, or HIPPO_SLEEP_TIMEOUT_MS). */
69
+ export function sleepInChild(ctx, opts) {
70
+ // The child reopens the store by path, which only SQLite has; any other store keeps sleep's own refusal.
71
+ if (ctx.store && ctx.store.kind !== 'sqlite')
72
+ return sleep(ctx, opts);
73
+ return inTurn({ kind: 'sleep', hippoRoot: ctx.hippoRoot, tenantId: ctx.tenantId, actor: ctx.actor, opts });
74
+ }
75
+ /** The MCP auto-sleep's consolidation, in the same queue and child as POST /v1/sleep; auto-sleep only starts on a hippo.db store. */
76
+ export async function consolidateInChild(hippoRoot) {
77
+ await inTurn({ kind: 'consolidate', hippoRoot });
78
+ }
73
79
  //# sourceMappingURL=sleep-offload.js.map
@@ -88,6 +88,10 @@ export interface RouteRequest {
88
88
  opts: ResolvedServeOpts;
89
89
  query: URLSearchParams;
90
90
  }
91
+ /** A request past the dispatch gate, carrying the caller the gate authenticated. */
92
+ export interface AuthedRouteRequest extends RouteRequest {
93
+ ctx: Context;
94
+ }
91
95
  /** A route's store status: a `storeReady` group, a `sqliteOnly` reason, or neither while it waits for a group; never both. */
92
96
  type StoreStatus = {
93
97
  storeReady?: StoreGroup;
@@ -96,20 +100,28 @@ type StoreStatus = {
96
100
  sqliteOnly: string;
97
101
  storeReady?: never;
98
102
  };
99
- /** One /v1 route: an exact path, a matchPath pattern, or a regex, each paired with one method's handler. Under another store it runs only with its
100
- * store's `storeReady` group; `loop: 'off'` runs its SQLite work on a worker thread, so the handler opens no hippo.db on the server thread. */
101
- export type Route = {
102
- method: string;
103
- loop?: 'off';
104
- } & StoreStatus & ({
103
+ /** What the dispatch gate proves before a handler runs: any caller, an admin, a host admin on loopback, or nothing, for a route
104
+ * whose handler checks the sender's signature itself. */
105
+ export type RouteAuth = 'caller' | 'admin' | 'host-admin-local' | 'webhook-signature';
106
+ export type RouteEndpoint<R> = {
105
107
  path: string;
106
- handler: (r: RouteRequest) => Promise<void>;
108
+ handler: (r: R) => Promise<void>;
107
109
  } | {
108
110
  pattern: string;
109
- handler: (r: RouteRequest, params: Record<string, string>) => Promise<void>;
111
+ handler: (r: R, params: Record<string, string>) => Promise<void>;
110
112
  } | {
111
113
  regex: RegExp;
112
- handler: (r: RouteRequest, match: RegExpMatchArray) => Promise<void>;
113
- });
114
+ handler: (r: R, match: RegExpMatchArray) => Promise<void>;
115
+ };
116
+ /** One /v1 route: an exact path, a matchPath pattern, or a regex, each paired with one method's handler. Under another store it runs only with its
117
+ * store's `storeReady` group; `loop: 'off'` runs its SQLite work on a worker thread, so the handler opens no hippo.db on the server thread. */
118
+ export type Route = {
119
+ method: string;
120
+ loop?: 'off';
121
+ } & StoreStatus & (({
122
+ auth: Exclude<RouteAuth, 'webhook-signature'>;
123
+ } & RouteEndpoint<AuthedRouteRequest>) | ({
124
+ auth: 'webhook-signature';
125
+ } & RouteEndpoint<RouteRequest>));
114
126
  export {};
115
127
  //# sourceMappingURL=types.d.ts.map
@@ -3,10 +3,9 @@ import type { Context, RememberOpts } from '../api/index.js';
3
3
  import { type JsonValue } from '../util/json.js';
4
4
  export declare function isSetMember<T extends string>(set: ReadonlySet<T>, value: string): value is T;
5
5
  export declare const MAX_SHORT_FIELD_LEN = 4096;
6
- export declare const MAX_LIST_LIMIT = 1000;
7
6
  export declare function parseListLimit(limitRaw: string | null, defaultLimit?: number, maxLimit?: number): number;
8
7
  /** `_authed` is proof the caller passed auth, so a full-size body is read only for
9
- * an authenticated caller; the key mint reads first under its own small cap. */
8
+ * an authenticated caller; the key mint reads under its own small cap. */
10
9
  export declare function parseJsonBody(req: IncomingMessage, _authed: Context): Promise<Record<string, JsonValue>>;
11
10
  export declare function parseJsonObjectText(raw: string): Record<string, JsonValue>;
12
11
  export declare function getString(obj: Record<string, JsonValue>, key: string): string | undefined;
@@ -1,4 +1,5 @@
1
- import { HttpError, MAX_ID_LEN, readBody } from '../util/http-util.js';
1
+ import { HttpError, readBody } from '../util/http-util.js';
2
+ import { DEFAULT_LIST_LIMIT, MAX_ID_LEN, MAX_LIST_LIMIT, resolveListLimit } from '../util/limits.js';
2
3
  import { isJsonString, isJsonObject } from '../util/json.js';
3
4
  // Runtime membership check for a `ReadonlySet<T>` of string-literal members: Set<T>.has gives no narrowing, so this is the one place the `as T` assertion lives
4
5
  // and callers narrow via the `value is T` return.
@@ -8,20 +9,14 @@ export function isSetMember(set, value) {
8
9
  }
9
10
  // Cap for short free-text HTTP fields (names, text, context, change summaries) on the object routes.
10
11
  export const MAX_SHORT_FIELD_LEN = 4096;
11
- // Number.isInteger, not isFinite: SQLite `LIMIT ?` rejects "1.5" with a 500.
12
- // Shared by every first-class-object list route so the guard cannot drift.
13
- export const MAX_LIST_LIMIT = 1000;
14
- export function parseListLimit(limitRaw, defaultLimit = 100, maxLimit = MAX_LIST_LIMIT) {
15
- if (limitRaw === null)
16
- return defaultLimit;
17
- const limit = Number(limitRaw);
18
- if (!Number.isInteger(limit) || limit <= 0 || limit > maxLimit) {
12
+ export function parseListLimit(limitRaw, defaultLimit = DEFAULT_LIST_LIMIT, maxLimit = MAX_LIST_LIMIT) {
13
+ const limit = resolveListLimit(limitRaw === null ? undefined : Number(limitRaw), defaultLimit, maxLimit);
14
+ if (limit === undefined)
19
15
  throw new HttpError(400, `limit must be a positive integer <= ${maxLimit}`);
20
- }
21
16
  return limit;
22
17
  }
23
18
  /** `_authed` is proof the caller passed auth, so a full-size body is read only for
24
- * an authenticated caller; the key mint reads first under its own small cap. */
19
+ * an authenticated caller; the key mint reads under its own small cap. */
25
20
  export async function parseJsonBody(req, _authed) {
26
21
  return parseJsonObjectText(await readBody(req));
27
22
  }
package/dist/server.d.ts CHANGED
@@ -13,8 +13,9 @@ export type { JsonValue } from './util/json.js';
13
13
  export { captureSessionTexts, type SessionCaptureRequest, type SessionCaptureResult } from './capture/session-texts.js';
14
14
  export { hasGroup, sqliteStore, type AmbientCandidateRequest, type ContextReads, type EntryRemoval, type EntryTarget, type EntryWrite, type EntryWrites, type HippoStore, type KeyAudit, type KeyListQuery, type KeyMint, type KeyRevoke, type KeyWrites, type OutcomeWrite, type RawArchive, type RecallSearchArgs, type RecallWrites, type SelfKeyMint, type StoreGroup, type StoreGroups, type SupersedeWrite, type VectorReads, type VectorBackfillQuery, type VectorRowWrite, type VectorWrite, type VectorWriteResult, type VectorWrites, } from './store/index.js';
15
15
  export { entryAfterOutcome } from './core/memory.js';
16
- export { rejectionDigest, RejectedValueError } from './store/rejection.js';
17
- export { ownScopeTouches } from './store/recall-scope.js';
16
+ export { rejectionDigest } from './store/rejection.js';
17
+ export { RejectedValueError } from './core/api-errors.js';
18
+ export { ownScopeTouches } from './core/recall-scope.js';
18
19
  export { BadRequestError, ConflictError } from './core/api-errors.js';
19
20
  export type { HippoDbContext, StoreReply } from './api/types.js';
20
21
  export type { ApiKeyListItem, ApiKeyListRow, ApiKeyRecord, ListApiKeysOpts, NewApiKey } from './store/auth.js';
@@ -37,11 +38,11 @@ export type { AmbientTallies } from './core/ambient.js';
37
38
  export type { TokenUse } from './store/token-ledger.js';
38
39
  export type { EmbeddingIndexState } from './store/vector-index.js';
39
40
  export type { PhysicsParticle } from './core/physics.js';
40
- export { StoreBusyError } from './db/index.js';
41
+ export { StoreBusyError } from './store/port.js';
41
42
  export { decodeVector, EMBEDDING_MODEL_META_KEY, encodeVector, rankVectorRows, type VectorMatch, type VectorRow } from './db/vector-store.js';
42
43
  export { bufferToFloat32, float32ToBuffer } from './db/physics-state.js';
43
44
  export { replacesIndex } from './store/vector-index.js';
44
- export { passesScopeFilterForRecall, RECALL_DEFAULT_DENY_SCOPES } from './store/recall-scope.js';
45
+ export { passesScopeFilterForRecall, RECALL_DEFAULT_DENY_SCOPES } from './core/recall-scope.js';
45
46
  export { SECRET_TAGS } from './util/secret-detect.js';
46
47
  export { tallyAmbientEntries } from './core/ambient.js';
47
48
  export { ftsTermParts, rarestFtsQuery } from './core/prompt-recall.js';
package/dist/server.js CHANGED
@@ -19,17 +19,18 @@ export { captureSessionTexts } from './capture/session-texts.js';
19
19
  export { hasGroup, sqliteStore, } from './store/index.js';
20
20
  // An add-on store's entry writes apply an outcome, guard tombstones and check reach exactly as hippo.db does.
21
21
  export { entryAfterOutcome } from './core/memory.js';
22
- export { rejectionDigest, RejectedValueError } from './store/rejection.js';
23
- export { ownScopeTouches } from './store/recall-scope.js';
22
+ export { rejectionDigest } from './store/rejection.js';
23
+ export { RejectedValueError } from './core/api-errors.js';
24
+ export { ownScopeTouches } from './core/recall-scope.js';
24
25
  export { BadRequestError, ConflictError } from './core/api-errors.js';
25
- export { StoreBusyError } from './db/index.js';
26
+ export { StoreBusyError } from './store/port.js';
26
27
  // An add-on store encodes, decodes and ranks vectors and particles with hippo.db's own code, and drops the index by its rule,
27
28
  // so both stores keep the same bytes and return the same ids in the same order.
28
29
  export { decodeVector, EMBEDDING_MODEL_META_KEY, encodeVector, rankVectorRows } from './db/vector-store.js';
29
30
  export { bufferToFloat32, float32ToBuffer } from './db/physics-state.js';
30
31
  export { replacesIndex } from './store/vector-index.js';
31
32
  // An add-on's ContextReads applies hippo.db's scope, secret, tally and rarest-term rules with the same code.
32
- export { passesScopeFilterForRecall, RECALL_DEFAULT_DENY_SCOPES } from './store/recall-scope.js';
33
+ export { passesScopeFilterForRecall, RECALL_DEFAULT_DENY_SCOPES } from './core/recall-scope.js';
33
34
  export { SECRET_TAGS } from './util/secret-detect.js';
34
35
  export { tallyAmbientEntries } from './core/ambient.js';
35
36
  export { ftsTermParts, rarestFtsQuery } from './core/prompt-recall.js';
@@ -5,12 +5,12 @@ import { generateId } from '../core/memory.js';
5
5
  import { initStore } from '../store/open.js';
6
6
  import { writeEntry } from '../store/entry-writes.js';
7
7
  import { readEntry } from '../store/entry-reads.js';
8
- import { isPersonalScope } from '../store/recall-scope.js';
8
+ import { isPersonalScope } from '../core/recall-scope.js';
9
9
  import { fallbackOrigin, resolveGlobalRootDir } from '../core/project-identity.js';
10
10
  import { isSharedStore } from '../core/config.js';
11
11
  import { detectSecret } from '../util/secret-detect.js';
12
12
  import { isQuarantineScope } from '../trust/quarantine.js';
13
- import { embedMemory } from '../store/embeddings/index.js';
13
+ import { embedMemory } from '../search/embed-memories.js';
14
14
  import { appendAuditEvent } from '../store/audit.js';
15
15
  /** Returns the path to the global Hippo store.
16
16
  * Resolution order: $HIPPO_HOME > $XDG_DATA_HOME/hippo > ~/.hippo/ */
@@ -3,70 +3,63 @@ import { BadRequestError } from '../core/api-errors.js';
3
3
  import * as fs from 'fs';
4
4
  import * as path from 'path';
5
5
  import { AGENT_MEMORY_SOURCE_PREFIX } from '../core/agent-memory-tools.js';
6
- import { writeEntry } from '../store/entry-writes.js';
7
- import { loadAllEntries } from '../store/entry-reads.js';
6
+ import { writeEntriesSkippingRejected } from '../store/entry-writes.js';
7
+ import { loadEntriesByIds, loadEntryTextKeys } from '../store/entry-reads.js';
8
+ import { chunked } from '../util/chunked.js';
9
+ import { withRequestStoresSync } from '../db/request-stores.js';
8
10
  import { classifyOriginProject, resolveProjectIdentity } from '../core/project-identity.js';
9
11
  import { isSharedStore } from '../core/config.js';
10
12
  import { detectSecret } from '../util/secret-detect.js';
11
- import { RejectedValueError } from '../store/rejection.js';
12
- import { embedAll } from '../store/embeddings/index.js';
13
+ import { embedAll } from '../search/embed-memories.js';
13
14
  import { log } from '../util/log.js';
14
15
  import { logEmbedAllFailure } from './search-both.js';
15
16
  /** Copy all global memories into the local store, skipping entries that already exist locally by ID or text (promote and share copy under a new ID).
16
17
  * Returns the count of newly copied entries. */
17
18
  export function syncGlobalToLocal(localRoot, globalRoot, opts = {}) {
18
19
  if (isSharedStore(localRoot)) {
19
- throw new BadRequestError(`Refusing to sync into ${localRoot}: a shared store takes no copies of a personal global store, whose rows would reach every member.`);
20
+ throw new BadRequestError(`Refusing to sync into ${localRoot}: a shared store takes no copies of a personal global store, ` +
21
+ `whose rows would reach every member.`);
20
22
  }
21
23
  if (!fs.existsSync(globalRoot))
22
24
  return 0;
23
- // Host-wide read: the global union is copied into a tenant-scoped local store, and writeEntry carries the tenant if the local-root context has one.
24
- const globalEntries = loadAllEntries(globalRoot);
25
- const textKey = (e) => `${e.tenantId}\n${e.content}`;
26
- const localEntries = loadAllEntries(localRoot);
27
- const localIds = new Set(localEntries.map((e) => e.id));
28
- const localText = new Set(localEntries.map(textKey));
25
+ return withRequestStoresSync(() => copyMissingRows(localRoot, globalRoot, opts.includeCrossProject === true));
26
+ }
27
+ const textKey = (e) => `${e.tenantId}\n${e.content}`;
28
+ /** One open per store and one transaction: id, tenant and text decide which rows to read whole, and the copies commit together. */
29
+ function copyMissingRows(localRoot, globalRoot, includeCrossProject) {
30
+ // Host-wide read: the global union is copied into a tenant-scoped local store, and each copy keeps its own tenant.
31
+ const localKeys = loadEntryTextKeys(localRoot);
32
+ const localIds = new Set(localKeys.map((k) => k.id));
33
+ const localText = new Set(localKeys.map(textKey));
34
+ // Only the global store's user pass sets an imported note's row aside, so a copy would outlive the note.
35
+ const candidates = loadEntryTextKeys(globalRoot).filter((k) => !localIds.has(k.id) && !k.source.startsWith(AGENT_MEMORY_SOURCE_PREFIX) && !localText.has(textKey(k)));
36
+ if (candidates.length === 0)
37
+ return 0;
38
+ const byId = new Map(chunked(candidates.map((k) => k.id)).flatMap((ids) => loadEntriesByIds(globalRoot, ids)).map((e) => [e.id, e]));
29
39
  // Syncing down must not re-import what ambient context excludes: other-project rows are skipped by default and secret rows never copied.
30
- // origin_project is preserved on the copy (writeEntry stamps it only when missing).
40
+ // origin_project is preserved on the copy (the write stamps it only when missing).
31
41
  const currentProject = resolveProjectIdentity(path.dirname(path.resolve(localRoot)));
32
- let count = 0;
33
- // A locally rejected value must not come back through sync down: caught per item, printed as one line.
42
+ // A locally rejected value must not come back through sync down: skipped per item, printed as one line.
34
43
  let rejected = 0;
35
- for (const entry of globalEntries) {
36
- // Skip if already present by ID
37
- if (localIds.has(entry.id))
38
- continue;
39
- // Only the global store's user pass sets an imported note's row aside, so a copy would outlive the note.
40
- if (entry.source.startsWith(AGENT_MEMORY_SOURCE_PREFIX))
41
- continue;
42
- if (localText.has(textKey(entry)))
43
- continue;
44
- if (detectSecret(entry).flagged)
45
- continue;
46
- if (!opts.includeCrossProject && classifyOriginProject(entry.origin_project, currentProject) === 'cross-project')
47
- continue;
48
- if (!writeUnlessRejected(localRoot, entry)) {
49
- rejected++;
50
- continue;
44
+ const count = writeEntriesSkippingRejected(localRoot, (put) => {
45
+ for (const { id } of candidates) {
46
+ const entry = byId.get(id);
47
+ // A row the global store dropped between the two reads, or a text an earlier copy in this batch already brought down.
48
+ if (!entry || localText.has(textKey(entry)))
49
+ continue;
50
+ if (detectSecret(entry).flagged)
51
+ continue;
52
+ if (!includeCrossProject && classifyOriginProject(entry.origin_project, currentProject) === 'cross-project')
53
+ continue;
54
+ if (put(entry))
55
+ localText.add(textKey(entry));
56
+ else
57
+ rejected++;
51
58
  }
52
- localText.add(textKey(entry));
53
- count++;
54
- }
59
+ });
55
60
  finishSyncDown(localRoot, count, rejected);
56
61
  return count;
57
62
  }
58
- /** False when the local store rejects the value; any other failure still throws. */
59
- function writeUnlessRejected(localRoot, entry) {
60
- try {
61
- writeEntry(localRoot, entry);
62
- return true;
63
- }
64
- catch (err) {
65
- if (err instanceof RejectedValueError)
66
- return false;
67
- throw err;
68
- }
69
- }
70
63
  function finishSyncDown(localRoot, count, rejected) {
71
64
  if (rejected > 0) {
72
65
  log.warn(`syncGlobalToLocal: skipped ${rejected} rejected value(s) (run \`hippo unreject\` on the local store to allow).`);
@@ -1,4 +1,5 @@
1
- import { type DatabaseSyncLike } from '../db/index.js';
1
+ import { type ProjectFold } from '../agent-memories/project-folds.js';
2
+ import type { ProjectTagReads, ProjectTagStore } from '../store/project-tags.js';
2
3
  export interface ProjectSummary {
3
4
  /** '' is user-global, null is unknown; neither can be merged. */
4
5
  readonly origin: string | null;
@@ -18,10 +19,6 @@ export interface MergeResult {
18
19
  readonly compactions: number;
19
20
  readonly backup: string | null;
20
21
  }
21
- export interface ProjectFold {
22
- readonly from: string;
23
- readonly into: string;
24
- }
25
22
  /** An old name whose session folders now resolve to several projects: no fold can say whose rows are whose. */
26
23
  export interface ProjectCollision {
27
24
  readonly name: string;
@@ -45,28 +42,24 @@ export interface RepairResult {
45
42
  readonly backup: string | null;
46
43
  }
47
44
  /** Live rows per project name, newest write first, with how many of its imported notes are copies held elsewhere. */
48
- export declare function listProjects(db: DatabaseSyncLike, tenantId: string): ProjectSummary[];
45
+ export declare function listProjects(store: ProjectTagReads): ProjectSummary[];
49
46
  /** Refuses user-global and unknown: they are not projects, and folding them would leak or hide every row. */
50
47
  export declare function validateMergeNames(from: string, into: string): string | null;
51
48
  /** Folds project `from` into `into` for one tenant in one transaction; a dry run rolls back and writes nothing, mirrors included. */
52
- export declare function mergeProjects(db: DatabaseSyncLike, hippoRoot: string, opts: {
53
- tenantId: string;
49
+ export declare function mergeProjects(store: ProjectTagStore, opts: {
54
50
  from: string;
55
51
  into: string;
56
52
  dryRun: boolean;
57
53
  }): MergeResult;
58
- /** Names folded, directly or through others, into one of `names`; the sync moves imports still filed under them. */
59
- export declare function namesFoldedInto(db: DatabaseSyncLike, tenantId: string, names: readonly string[]): string[];
60
54
  /** Reads only, so doctor and a dry run take no write lock; merged rows are planned before any fold, so a few may re-tag differently once folds apply. */
61
- export declare function planProjectRepair(db: DatabaseSyncLike, hippoRoot: string, tenantId: string, globalFolds?: boolean): Omit<RepairResult, 'backup'>;
55
+ export declare function planProjectRepair(store: ProjectTagReads, hippoRoot: string, globalFolds?: boolean): Omit<RepairResult, 'backup'>;
62
56
  /** Sets aside stray imports, folds the names the resolver now maps elsewhere, then
63
57
  * re-tags sleep's user-global merges by their parents; a dry run only plans. */
64
- export declare function repairProjects(db: DatabaseSyncLike, hippoRoot: string, opts: {
65
- tenantId: string;
58
+ export declare function repairProjects(store: ProjectTagStore, opts: {
66
59
  dryRun: boolean;
67
60
  globalFolds?: boolean;
68
61
  }): RepairResult;
69
62
  /** Sleep runs repair once per store, so an upgrade needs no command. Global-store folds stay
70
63
  * with `hippo projects repair`: their evidence is compaction folders, blind to a same-named repo that never compacted. */
71
- export declare function repairOnceOnSleep(db: DatabaseSyncLike, hippoRoot: string, tenantId: string): RepairResult | null;
64
+ export declare function repairOnceOnSleep(store: ProjectTagStore): RepairResult | null;
72
65
  //# sourceMappingURL=project-merge.d.ts.map