hippo-memory 1.71.0 → 2.0.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 (625) hide show
  1. package/README.md +7 -5
  2. package/dist/agent-memories/apply.d.ts +0 -11
  3. package/dist/agent-memories/apply.js +11 -26
  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 +3 -2
  12. package/dist/api/audit.d.ts +30 -2
  13. package/dist/api/audit.js +48 -7
  14. package/dist/api/auth.d.ts +11 -9
  15. package/dist/api/auth.js +39 -40
  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-auto.js +4 -2
  24. package/dist/api/context-render.js +4 -3
  25. package/dist/api/context-select.js +15 -29
  26. package/dist/api/context.js +29 -18
  27. package/dist/api/continuity.d.ts +47 -0
  28. package/dist/api/continuity.js +66 -0
  29. package/dist/api/dormant.js +4 -2
  30. package/dist/api/drill-down.js +3 -2
  31. package/dist/api/embeddings.d.ts +17 -0
  32. package/dist/api/embeddings.js +28 -0
  33. package/dist/api/error-reply.d.ts +8 -0
  34. package/dist/api/error-reply.js +21 -0
  35. package/dist/api/forget.d.ts +7 -3
  36. package/dist/api/forget.js +24 -14
  37. package/dist/api/goals.d.ts +1 -1
  38. package/dist/api/goals.js +5 -9
  39. package/dist/api/graph.js +2 -1
  40. package/dist/api/index.d.ts +4 -2
  41. package/dist/api/index.js +4 -2
  42. package/dist/api/instruction-detect.js +5 -1
  43. package/dist/api/learn.d.ts +5 -1
  44. package/dist/api/learn.js +71 -44
  45. package/dist/api/ledger-db.d.ts +2 -6
  46. package/dist/api/ledger-db.js +4 -36
  47. package/dist/api/memories.d.ts +21 -1
  48. package/dist/api/memories.js +51 -1
  49. package/dist/api/objects.d.ts +1 -1
  50. package/dist/api/objects.js +2 -1
  51. package/dist/api/outcome.d.ts +5 -5
  52. package/dist/api/outcome.js +17 -16
  53. package/dist/api/pilot-arm.d.ts +1 -11
  54. package/dist/api/pilot-arm.js +5 -45
  55. package/dist/api/predictions.d.ts +3 -1
  56. package/dist/api/predictions.js +8 -1
  57. package/dist/api/projects.d.ts +21 -0
  58. package/dist/api/projects.js +24 -0
  59. package/dist/api/promote.d.ts +3 -3
  60. package/dist/api/promote.js +26 -28
  61. package/dist/api/prompt-hook.d.ts +17 -2
  62. package/dist/api/prompt-hook.js +45 -4
  63. package/dist/api/quarantine.js +2 -1
  64. package/dist/api/recall-cli.d.ts +3 -0
  65. package/dist/api/recall-cli.js +13 -4
  66. package/dist/api/recall-core.js +10 -5
  67. package/dist/api/recall-pipeline.js +23 -24
  68. package/dist/api/recall-request.js +1 -1
  69. package/dist/api/recall-types.d.ts +3 -1
  70. package/dist/api/recall.d.ts +0 -3
  71. package/dist/api/recall.js +51 -73
  72. package/dist/api/remember-local.d.ts +5 -2
  73. package/dist/api/remember-local.js +15 -7
  74. package/dist/api/remember.d.ts +7 -3
  75. package/dist/api/remember.js +19 -16
  76. package/dist/api/session-end.d.ts +46 -0
  77. package/dist/api/session-end.js +131 -0
  78. package/dist/api/sleep-run.d.ts +1 -1
  79. package/dist/api/sleep-run.js +16 -11
  80. package/dist/api/sleep.js +4 -3
  81. package/dist/api/status.d.ts +24 -0
  82. package/dist/api/status.js +40 -0
  83. package/dist/api/store-init.d.ts +4 -0
  84. package/dist/api/store-init.js +9 -0
  85. package/dist/api/tokens.js +2 -2
  86. package/dist/api/types.d.ts +3 -7
  87. package/dist/api/types.js +6 -1
  88. package/dist/capture/caller-session.d.ts +0 -3
  89. package/dist/capture/caller-session.js +1 -12
  90. package/dist/capture/capture-error.d.ts +2 -2
  91. package/dist/capture/capture-error.js +23 -18
  92. package/dist/capture/codex-patch.js +3 -1
  93. package/dist/capture/command.js +36 -95
  94. package/dist/capture/compact.js +10 -5
  95. package/dist/capture/compaction-items-caller.js +11 -20
  96. package/dist/capture/compaction-record.d.ts +7 -93
  97. package/dist/capture/compaction-record.js +29 -426
  98. package/dist/capture/compaction-spool.d.ts +7 -7
  99. package/dist/capture/compaction-spool.js +60 -51
  100. package/dist/capture/copilot-transcript.d.ts +2 -1
  101. package/dist/capture/copilot-transcript.js +2 -1
  102. package/dist/capture/extract.d.ts +5 -2
  103. package/dist/capture/extract.js +4 -3
  104. package/dist/capture/failure-caller.d.ts +1 -1
  105. package/dist/capture/failure-caller.js +21 -16
  106. package/dist/capture/failure-reading.d.ts +2 -1
  107. package/dist/capture/failure-reading.js +7 -9
  108. package/dist/capture/pre-compact-caller.js +5 -4
  109. package/dist/capture/session-digest.js +4 -3
  110. package/dist/capture/session-end-caller.js +3 -2
  111. package/dist/capture/session-worker.js +22 -10
  112. package/dist/capture/transcript.d.ts +2 -1
  113. package/dist/capture/transcript.js +6 -3
  114. package/dist/capture/working-state.d.ts +4 -2
  115. package/dist/capture/working-state.js +4 -2
  116. package/dist/cli/audit-prune.d.ts +0 -25
  117. package/dist/cli/audit-prune.js +1 -27
  118. package/dist/cli/audit.js +20 -20
  119. package/dist/cli/auth.d.ts +1 -1
  120. package/dist/cli/auth.js +16 -17
  121. package/dist/cli/briefs.d.ts +1 -4
  122. package/dist/cli/briefs.js +37 -292
  123. package/dist/cli/card.js +41 -33
  124. package/dist/cli/client.d.ts +6 -2
  125. package/dist/cli/client.js +37 -21
  126. package/dist/cli/compact-resume-payload.js +1 -1
  127. package/dist/cli/context.d.ts +1 -1
  128. package/dist/cli/context.js +13 -13
  129. package/dist/cli/continuity.d.ts +1 -1
  130. package/dist/cli/continuity.js +36 -39
  131. package/dist/cli/curate.d.ts +2 -2
  132. package/dist/cli/curate.js +32 -36
  133. package/dist/cli/dag.d.ts +1 -1
  134. package/dist/cli/dag.js +23 -8
  135. package/dist/cli/decisions.d.ts +0 -2
  136. package/dist/cli/decisions.js +7 -285
  137. package/dist/cli/eval.d.ts +1 -1
  138. package/dist/cli/eval.js +12 -13
  139. package/dist/cli/explain.d.ts +1 -1
  140. package/dist/cli/explain.js +21 -25
  141. package/dist/cli/flag-values.js +16 -6
  142. package/dist/cli/flags.d.ts +0 -289
  143. package/dist/cli/flags.js +3 -138
  144. package/dist/cli/graph.d.ts +3 -0
  145. package/dist/cli/graph.js +83 -0
  146. package/dist/cli/hook-runtime.d.ts +6 -6
  147. package/dist/cli/hook-runtime.js +9 -36
  148. package/dist/cli/incidents.d.ts +3 -0
  149. package/dist/cli/incidents.js +112 -0
  150. package/dist/cli/init.d.ts +1 -1
  151. package/dist/cli/init.js +28 -19
  152. package/dist/cli/install-steps.d.ts +2 -1
  153. package/dist/cli/install-steps.js +11 -3
  154. package/dist/cli/last-sleep.js +1 -1
  155. package/dist/cli/maintenance.d.ts +3 -3
  156. package/dist/cli/maintenance.js +29 -30
  157. package/dist/cli/notes.d.ts +2 -0
  158. package/dist/cli/notes.js +41 -0
  159. package/dist/cli/object-verbs.d.ts +2 -2
  160. package/dist/cli/object-verbs.js +4 -4
  161. package/dist/cli/open-browser.d.ts +14 -0
  162. package/dist/cli/open-browser.js +26 -0
  163. package/dist/cli/playbooks.d.ts +3 -4
  164. package/dist/cli/playbooks.js +126 -290
  165. package/dist/cli/predictions.d.ts +3 -0
  166. package/dist/cli/predictions.js +174 -0
  167. package/dist/cli/print.js +2 -1
  168. package/dist/cli/projects.js +30 -22
  169. package/dist/cli/quality-repair-once.d.ts +1 -1
  170. package/dist/cli/quality-repair-once.js +6 -5
  171. package/dist/cli/recall.js +13 -7
  172. package/dist/cli/refine-llm.js +18 -17
  173. package/dist/cli/remember.js +17 -17
  174. package/dist/cli/scheduler.js +2 -1
  175. package/dist/cli/serve.js +11 -6
  176. package/dist/cli/session-hooks.d.ts +1 -5
  177. package/dist/cli/session-hooks.js +89 -168
  178. package/dist/cli/setup.d.ts +1 -1
  179. package/dist/cli/setup.js +17 -10
  180. package/dist/cli/shared.d.ts +2 -6
  181. package/dist/cli/shared.js +9 -29
  182. package/dist/cli/sleep-render.js +6 -3
  183. package/dist/cli/sleep.js +6 -37
  184. package/dist/cli/status.d.ts +3 -3
  185. package/dist/cli/status.js +32 -35
  186. package/dist/cli/transfer.d.ts +3 -3
  187. package/dist/cli/transfer.js +64 -43
  188. package/dist/cli/usage.d.ts +1 -80
  189. package/dist/cli/usage.js +2 -696
  190. package/dist/cli/verb-row.d.ts +34 -0
  191. package/dist/cli/verb-row.js +6 -0
  192. package/dist/cli/verbs/health.d.ts +27 -0
  193. package/dist/cli/verbs/health.js +234 -0
  194. package/dist/cli/verbs/memory.d.ts +16 -0
  195. package/dist/cli/verbs/memory.js +236 -0
  196. package/dist/cli/verbs/objects.d.ts +20 -0
  197. package/dist/cli/verbs/objects.js +257 -0
  198. package/dist/cli/verbs/sessions.d.ts +31 -0
  199. package/dist/cli/verbs/sessions.js +314 -0
  200. package/dist/cli/verbs.d.ts +81 -0
  201. package/dist/cli/verbs.js +7 -0
  202. package/dist/cli/versioned-verbs.d.ts +51 -0
  203. package/dist/cli/versioned-verbs.js +79 -0
  204. package/dist/cli.d.ts +1 -272
  205. package/dist/cli.js +24 -315
  206. package/dist/connectors/dlq.d.ts +39 -3
  207. package/dist/connectors/dlq.js +39 -4
  208. package/dist/connectors/github/backfill.js +12 -3
  209. package/dist/connectors/github/deletion.js +2 -1
  210. package/dist/connectors/github/dlq.js +31 -73
  211. package/dist/connectors/github/ingest.d.ts +2 -6
  212. package/dist/connectors/github/ingest.js +5 -29
  213. package/dist/connectors/github/tenant-routing.js +2 -1
  214. package/dist/connectors/github/webhook.d.ts +2 -1
  215. package/dist/connectors/github/webhook.js +35 -2
  216. package/dist/connectors/ingest.d.ts +10 -0
  217. package/dist/connectors/ingest.js +29 -0
  218. package/dist/connectors/slack/deletion.js +2 -1
  219. package/dist/connectors/slack/dlq.js +49 -71
  220. package/dist/connectors/slack/ingest.d.ts +2 -6
  221. package/dist/connectors/slack/ingest.js +4 -28
  222. package/dist/connectors/slack/tenant-routing.js +2 -1
  223. package/dist/connectors/slack/webhook.d.ts +2 -1
  224. package/dist/connectors/slack/webhook.js +2 -1
  225. package/dist/consolidate/conflicts.js +2 -2
  226. package/dist/consolidate/dag.js +29 -18
  227. package/dist/consolidate/dedupe.d.ts +7 -0
  228. package/dist/consolidate/dedupe.js +6 -4
  229. package/dist/consolidate/llm-passes.js +45 -19
  230. package/dist/consolidate/memory-value.js +3 -2
  231. package/dist/consolidate/merge.js +8 -8
  232. package/dist/consolidate/physics-pass.d.ts +6 -1
  233. package/dist/consolidate/physics-pass.js +26 -6
  234. package/dist/consolidate/replay.js +11 -4
  235. package/dist/consolidate/sleep.js +9 -6
  236. package/dist/consolidate/traces.js +5 -5
  237. package/dist/core/ablation.d.ts +10 -0
  238. package/dist/core/ablation.js +12 -0
  239. package/dist/{sharing/scope.d.ts → core/active-scope.d.ts} +1 -1
  240. package/dist/{sharing/scope.js → core/active-scope.js} +1 -1
  241. package/dist/core/ambient.d.ts +4 -0
  242. package/dist/core/ambient.js +39 -18
  243. package/dist/core/api-errors.d.ts +16 -0
  244. package/dist/core/api-errors.js +20 -0
  245. package/dist/core/card.js +3 -1
  246. package/dist/core/compaction-timing.d.ts +7 -0
  247. package/dist/core/compaction-timing.js +9 -0
  248. package/dist/core/config.d.ts +1 -1
  249. package/dist/core/config.js +22 -18
  250. package/dist/core/cosine.d.ts +3 -0
  251. package/dist/core/cosine.js +19 -0
  252. package/dist/{store → core}/markdown.d.ts +1 -1
  253. package/dist/{store → core}/markdown.js +4 -4
  254. package/dist/core/memory-audit.d.ts +17 -0
  255. package/dist/core/memory-audit.js +54 -0
  256. package/dist/core/memory.d.ts +14 -8
  257. package/dist/core/memory.js +35 -23
  258. package/dist/{consolidate → core}/merged-row.d.ts +1 -1
  259. package/dist/{consolidate → core}/merged-row.js +1 -1
  260. package/dist/core/physics.d.ts +3 -1
  261. package/dist/core/physics.js +23 -18
  262. package/dist/core/prediction.d.ts +3 -0
  263. package/dist/core/prediction.js +6 -0
  264. package/dist/core/project-identity.d.ts +3 -0
  265. package/dist/core/project-identity.js +12 -2
  266. package/dist/{store → core}/recall-scope.d.ts +1 -10
  267. package/dist/{store → core}/recall-scope.js +2 -19
  268. package/dist/core/search-types.d.ts +1 -1
  269. package/dist/dashboard/dashboard-actions.d.ts +2 -2
  270. package/dist/dashboard/dashboard-actions.js +5 -5
  271. package/dist/dashboard/dashboard-queries.js +2 -7
  272. package/dist/dashboard/dashboard-snapshot.js +1 -3
  273. package/dist/dashboard/dashboard.js +16 -5
  274. package/dist/db/busy.d.ts +2 -7
  275. package/dist/db/busy.js +21 -26
  276. package/dist/db/connect.d.ts +2 -2
  277. package/dist/db/connect.js +7 -7
  278. package/dist/db/index.d.ts +3 -3
  279. package/dist/db/index.js +3 -3
  280. package/dist/db/migrate.js +14 -7
  281. package/dist/db/migrations/index.d.ts +1 -1
  282. package/dist/db/migrations/index.js +3 -1
  283. package/dist/db/migrations/v11.js +1 -0
  284. package/dist/db/migrations/v14.js +1 -0
  285. package/dist/db/migrations/v55.d.ts +3 -0
  286. package/dist/db/migrations/v55.js +17 -0
  287. package/dist/db/open.d.ts +0 -2
  288. package/dist/db/open.js +6 -10
  289. package/dist/db/physics-state.d.ts +0 -4
  290. package/dist/db/physics-state.js +7 -33
  291. package/dist/db/request-stores.d.ts +1 -0
  292. package/dist/db/request-stores.js +2 -1
  293. package/dist/db/tables.d.ts +2 -0
  294. package/dist/db/tables.js +6 -2
  295. package/dist/db/vector-store.js +19 -5
  296. package/dist/db/wal-checkpointer.js +2 -1
  297. package/dist/doctor.d.ts +3 -0
  298. package/dist/doctor.js +18 -15
  299. package/dist/embeddings/local.d.ts +62 -0
  300. package/dist/embeddings/local.js +146 -0
  301. package/dist/{store/embeddings → embeddings}/provider.d.ts +5 -2
  302. package/dist/{store/embeddings → embeddings}/provider.js +19 -25
  303. package/dist/embeddings/transformers.d.ts +26 -0
  304. package/dist/embeddings/transformers.js +89 -0
  305. package/dist/entry/session-text.d.ts +1 -1
  306. package/dist/entry/session-text.js +1 -1
  307. package/dist/entry/store-kit.d.ts +37 -0
  308. package/dist/entry/store-kit.js +25 -0
  309. package/dist/entry/testing.d.ts +6 -0
  310. package/dist/entry/testing.js +7 -0
  311. package/dist/eval/eval-suite.js +17 -11
  312. package/dist/eval/eval.js +1 -1
  313. package/dist/eval/judgment.js +12 -5
  314. package/dist/graph/extract.js +3 -3
  315. package/dist/graph/recall.js +1 -1
  316. package/dist/graph/view.js +13 -5
  317. package/dist/graph/write.d.ts +1 -1
  318. package/dist/graph/write.js +9 -9
  319. package/dist/hooks/codex-session.js +3 -2
  320. package/dist/hooks/codex-wrapper.js +2 -1
  321. package/dist/hooks/json-hooks.js +10 -4
  322. package/dist/hooks/opencode.js +8 -5
  323. package/dist/hooks/shared.d.ts +0 -6
  324. package/dist/hooks/shared.js +4 -15
  325. package/dist/importers/core.js +4 -4
  326. package/dist/importers/sources.js +5 -4
  327. package/dist/importers/vault.d.ts +1 -1
  328. package/dist/importers/vault.js +25 -23
  329. package/dist/index.d.ts +5 -4
  330. package/dist/index.js +4 -3
  331. package/dist/learn/autolearn.d.ts +15 -3
  332. package/dist/learn/autolearn.js +38 -16
  333. package/dist/learn/churn-git.js +13 -4
  334. package/dist/learn/extract.d.ts +3 -2
  335. package/dist/learn/extract.js +7 -5
  336. package/dist/learn/forward-claim-detector.js +4 -2
  337. package/dist/learn/invalidation.d.ts +2 -1
  338. package/dist/learn/invalidation.js +18 -9
  339. package/dist/mcp/admin-tools.d.ts +2 -2
  340. package/dist/mcp/admin-tools.js +27 -48
  341. package/dist/mcp/format.js +3 -2
  342. package/dist/mcp/framing.d.ts +1 -0
  343. package/dist/mcp/framing.js +1 -1
  344. package/dist/mcp/memory-tools.d.ts +1 -1
  345. package/dist/mcp/memory-tools.js +8 -9
  346. package/dist/mcp/protocol.d.ts +11 -7
  347. package/dist/mcp/protocol.js +25 -12
  348. package/dist/mcp/recall-tools.js +12 -9
  349. package/dist/mcp/request.js +22 -20
  350. package/dist/mcp/stdio.js +37 -16
  351. package/dist/mcp/tool-args.js +2 -1
  352. package/dist/mcp/tools.js +44 -21
  353. package/dist/objects/customer-notes.d.ts +2 -2
  354. package/dist/objects/decisions.d.ts +2 -2
  355. package/dist/objects/descriptor.d.ts +1 -1
  356. package/dist/objects/incidents.d.ts +2 -2
  357. package/dist/objects/lifecycle.d.ts +1 -1
  358. package/dist/objects/lifecycle.js +2 -1
  359. package/dist/objects/policies.d.ts +2 -2
  360. package/dist/objects/policies.js +2 -1
  361. package/dist/objects/processes.d.ts +2 -2
  362. package/dist/objects/project-briefs.d.ts +2 -2
  363. package/dist/objects/project-briefs.js +2 -3
  364. package/dist/objects/skills.d.ts +2 -2
  365. package/dist/postinstall.js +1 -1
  366. package/dist/rerankers/clef.js +3 -6
  367. package/dist/rerankers/cross-encoder.d.ts +31 -2
  368. package/dist/rerankers/cross-encoder.js +71 -98
  369. package/dist/rerankers/index.js +5 -4
  370. package/dist/rerankers/jev.js +2 -4
  371. package/dist/rerankers/outage-warning.d.ts +3 -1
  372. package/dist/rerankers/outage-warning.js +5 -3
  373. package/dist/search/bm25-search.js +1 -1
  374. package/dist/search/boosts.js +1 -1
  375. package/dist/search/embed-memories.d.ts +12 -0
  376. package/dist/search/embed-memories.js +389 -0
  377. package/dist/search/engine.d.ts +8 -0
  378. package/dist/search/engine.js +10 -0
  379. package/dist/search/goal-boost.d.ts +1 -1
  380. package/dist/search/goal-boost.js +6 -3
  381. package/dist/search/hybrid.d.ts +9 -2
  382. package/dist/search/hybrid.js +9 -4
  383. package/dist/search/physics-search.d.ts +6 -3
  384. package/dist/search/physics-search.js +22 -15
  385. package/dist/search/rerank.js +1 -1
  386. package/dist/search/vector.d.ts +8 -6
  387. package/dist/search/vector.js +14 -17
  388. package/dist/server/auth.d.ts +3 -1
  389. package/dist/server/auth.js +24 -15
  390. package/dist/server/boot.d.ts +2 -1
  391. package/dist/server/boot.js +34 -84
  392. package/dist/server/client-ip.d.ts +9 -6
  393. package/dist/server/client-ip.js +36 -17
  394. package/dist/server/deadline.d.ts +0 -2
  395. package/dist/server/deadline.js +1 -7
  396. package/dist/server/defaults.d.ts +1 -0
  397. package/dist/server/defaults.js +1 -0
  398. package/dist/server/mcp-http.js +16 -11
  399. package/dist/server/request.js +7 -2
  400. package/dist/server/route-checks.d.ts +7 -0
  401. package/dist/server/route-checks.js +42 -0
  402. package/dist/server/route-table.d.ts +9 -8
  403. package/dist/server/route-table.js +127 -133
  404. package/dist/server/routes/admin.d.ts +8 -8
  405. package/dist/server/routes/admin.js +13 -21
  406. package/dist/server/routes/customer-notes.d.ts +6 -6
  407. package/dist/server/routes/customer-notes.js +1 -2
  408. package/dist/server/routes/decisions.d.ts +6 -6
  409. package/dist/server/routes/decisions.js +2 -4
  410. package/dist/server/routes/incidents.d.ts +6 -6
  411. package/dist/server/routes/incidents.js +2 -5
  412. package/dist/server/routes/memories.d.ts +9 -9
  413. package/dist/server/routes/memories.js +19 -40
  414. package/dist/server/routes/object-routes.d.ts +6 -6
  415. package/dist/server/routes/object-routes.js +4 -7
  416. package/dist/server/routes/policies.d.ts +7 -7
  417. package/dist/server/routes/policies.js +2 -4
  418. package/dist/server/routes/predictions.d.ts +6 -6
  419. package/dist/server/routes/predictions.js +9 -13
  420. package/dist/server/routes/processes.d.ts +6 -6
  421. package/dist/server/routes/processes.js +1 -2
  422. package/dist/server/routes/project-briefs.d.ts +7 -7
  423. package/dist/server/routes/project-briefs.js +2 -4
  424. package/dist/server/routes/recall.d.ts +5 -5
  425. package/dist/server/routes/recall.js +6 -10
  426. package/dist/server/routes/skills.d.ts +7 -7
  427. package/dist/server/routes/skills.js +2 -4
  428. package/dist/server/server-detect.d.ts +7 -1
  429. package/dist/server/server-detect.js +36 -11
  430. package/dist/server/sleep-child.js +26 -7
  431. package/dist/server/sleep-offload.d.ts +11 -5
  432. package/dist/server/sleep-offload.js +17 -11
  433. package/dist/server/tls.d.ts +7 -2
  434. package/dist/server/tls.js +17 -5
  435. package/dist/server/types.d.ts +29 -12
  436. package/dist/server/validation.d.ts +1 -2
  437. package/dist/server/validation.js +6 -11
  438. package/dist/server.d.ts +4 -40
  439. package/dist/server.js +3 -29
  440. package/dist/sharing/global-store.d.ts +4 -5
  441. package/dist/sharing/global-store.js +8 -13
  442. package/dist/sharing/global-sync.js +38 -45
  443. package/dist/sharing/project-merge.d.ts +7 -14
  444. package/dist/sharing/project-merge.js +57 -121
  445. package/dist/sharing/search-both.js +10 -3
  446. package/dist/sharing/share.d.ts +2 -0
  447. package/dist/sharing/share.js +39 -38
  448. package/dist/store/ambient.js +7 -7
  449. package/dist/store/audit-event.d.ts +1 -1
  450. package/dist/store/audit.d.ts +0 -16
  451. package/dist/store/audit.js +4 -55
  452. package/dist/store/auth.d.ts +4 -2
  453. package/dist/store/auth.js +7 -3
  454. package/dist/store/candidates.d.ts +3 -2
  455. package/dist/store/candidates.js +59 -30
  456. package/dist/store/capture-write.d.ts +17 -0
  457. package/dist/store/capture-write.js +35 -0
  458. package/dist/store/cards.js +6 -5
  459. package/dist/store/compaction-caller.d.ts +18 -0
  460. package/dist/store/compaction-caller.js +29 -0
  461. package/dist/store/compactions-record.d.ts +115 -0
  462. package/dist/store/compactions-record.js +418 -0
  463. package/dist/store/compactions.js +6 -4
  464. package/dist/store/conflicts.d.ts +7 -1
  465. package/dist/store/conflicts.js +13 -9
  466. package/dist/store/connectors/dlq.d.ts +10 -0
  467. package/dist/store/connectors/dlq.js +33 -0
  468. package/dist/store/connectors/event-log.d.ts +13 -0
  469. package/dist/store/connectors/event-log.js +24 -0
  470. package/dist/store/connectors/github.d.ts +7 -9
  471. package/dist/store/connectors/github.js +35 -60
  472. package/dist/store/connectors/slack.d.ts +2 -11
  473. package/dist/store/connectors/slack.js +24 -57
  474. package/dist/store/dashboard-reads.js +8 -6
  475. package/dist/store/delete-and-batch.d.ts +6 -0
  476. package/dist/store/delete-and-batch.js +40 -6
  477. package/dist/store/delivery-recorder.d.ts +12 -5
  478. package/dist/store/delivery-recorder.js +13 -11
  479. package/dist/store/descendant-page.js +8 -4
  480. package/dist/store/dormant.d.ts +1 -1
  481. package/dist/store/dormant.js +10 -4
  482. package/dist/store/embeddings/index.d.ts +2 -12
  483. package/dist/store/embeddings/index.js +5 -374
  484. package/dist/store/entry-reads.d.ts +35 -4
  485. package/dist/store/entry-reads.js +86 -19
  486. package/dist/store/entry-row.js +9 -2
  487. package/dist/store/entry-writes.d.ts +15 -12
  488. package/dist/store/entry-writes.js +54 -22
  489. package/dist/store/failure-log-at.d.ts +8 -0
  490. package/dist/store/failure-log-at.js +16 -0
  491. package/dist/store/failure-log.d.ts +2 -2
  492. package/dist/store/failure-log.js +5 -3
  493. package/dist/{trust → store}/gated-write.d.ts +3 -1
  494. package/dist/{trust → store}/gated-write.js +7 -5
  495. package/dist/store/goals.js +22 -19
  496. package/dist/store/graph-reads.js +9 -6
  497. package/dist/store/graph-view-rows.js +2 -1
  498. package/dist/store/graph-writes.d.ts +6 -6
  499. package/dist/store/graph-writes.js +48 -71
  500. package/dist/store/half-life.js +2 -2
  501. package/dist/store/handoffs.d.ts +10 -4
  502. package/dist/store/handoffs.js +10 -9
  503. package/dist/store/index-and-stats.js +2 -2
  504. package/dist/store/index.d.ts +2 -2
  505. package/dist/store/index.js +1 -1
  506. package/dist/store/key-writes.js +1 -1
  507. package/dist/store/ledger-turn.d.ts +9 -0
  508. package/dist/store/ledger-turn.js +38 -0
  509. package/dist/store/mirrors.js +19 -10
  510. package/dist/store/open.d.ts +2 -5
  511. package/dist/store/open.js +42 -54
  512. package/dist/store/pilot-arm.d.ts +12 -0
  513. package/dist/store/pilot-arm.js +42 -0
  514. package/dist/store/port.d.ts +68 -6
  515. package/dist/store/port.js +8 -0
  516. package/dist/store/predictions.d.ts +1 -2
  517. package/dist/store/predictions.js +3 -6
  518. package/dist/store/project-tags.d.ts +62 -0
  519. package/dist/store/project-tags.js +67 -0
  520. package/dist/store/quality-repair.js +1 -1
  521. package/dist/store/quarantine.js +2 -1
  522. package/dist/store/recall-trace.d.ts +2 -0
  523. package/dist/store/recall-trace.js +20 -3
  524. package/dist/store/rejected-values.js +16 -10
  525. package/dist/store/rejection-probe.d.ts +4 -0
  526. package/dist/store/rejection-probe.js +19 -0
  527. package/dist/store/rejection.d.ts +0 -17
  528. package/dist/store/rejection.js +1 -21
  529. package/dist/store/rows.js +2 -2
  530. package/dist/store/rule-sql.d.ts +11 -0
  531. package/dist/store/rule-sql.js +31 -6
  532. package/dist/store/search-rows.d.ts +5 -5
  533. package/dist/store/search-rows.js +18 -16
  534. package/dist/store/sessions.js +4 -2
  535. package/dist/store/set-aside.d.ts +14 -0
  536. package/dist/store/set-aside.js +23 -0
  537. package/dist/store/sqlite/busy.d.ts +3 -0
  538. package/dist/store/sqlite/busy.js +8 -0
  539. package/dist/store/sqlite/connector-events-group.js +4 -7
  540. package/dist/store/sqlite/connector-writes-group.js +6 -4
  541. package/dist/store/sqlite/entry-writes-group.d.ts +3 -3
  542. package/dist/store/sqlite/entry-writes-group.js +3 -3
  543. package/dist/store/sqlite/error-codec.js +4 -3
  544. package/dist/store/sqlite/executor.js +10 -4
  545. package/dist/store/sqlite/graph-reads-group.js +1 -1
  546. package/dist/store/sqlite/held-connection.d.ts +11 -0
  547. package/dist/store/sqlite/held-connection.js +41 -0
  548. package/dist/store/sqlite/last-recall-group.d.ts +13 -0
  549. package/dist/store/sqlite/last-recall-group.js +57 -0
  550. package/dist/store/sqlite/local.d.ts +0 -17
  551. package/dist/store/sqlite/local.js +0 -31
  552. package/dist/store/sqlite/maintenance-groups.d.ts +6 -0
  553. package/dist/store/sqlite/maintenance-groups.js +60 -0
  554. package/dist/store/sqlite/object-rows.d.ts +1 -1
  555. package/dist/store/sqlite/objects-group.d.ts +1 -1
  556. package/dist/store/sqlite/objects-group.js +15 -7
  557. package/dist/store/sqlite/store.d.ts +1 -8
  558. package/dist/store/sqlite/store.js +13 -22
  559. package/dist/store/summaries.d.ts +10 -3
  560. package/dist/store/summaries.js +54 -11
  561. package/dist/store/token-ledger-rows.js +3 -2
  562. package/dist/store/token-ledger.d.ts +0 -7
  563. package/dist/store/token-ledger.js +0 -35
  564. package/dist/store/vector-index.js +8 -4
  565. package/dist/support-bundle.js +2 -3
  566. package/dist/trust/reject-flow.js +2 -2
  567. package/dist/util/agent-homes.d.ts +15 -0
  568. package/dist/util/agent-homes.js +34 -0
  569. package/dist/util/anthropic-messages.d.ts +6 -1
  570. package/dist/util/anthropic-messages.js +26 -7
  571. package/dist/util/atomic-write.d.ts +5 -2
  572. package/dist/util/atomic-write.js +12 -8
  573. package/dist/util/chunked.d.ts +3 -0
  574. package/dist/util/chunked.js +10 -0
  575. package/dist/util/ellipsize.d.ts +3 -0
  576. package/dist/util/ellipsize.js +5 -0
  577. package/dist/util/env.d.ts +12 -2
  578. package/dist/util/env.js +12 -2
  579. package/dist/util/format.d.ts +5 -0
  580. package/dist/util/format.js +10 -0
  581. package/dist/util/hook-payload.d.ts +8 -0
  582. package/dist/util/hook-payload.js +37 -0
  583. package/dist/util/http-retry.d.ts +6 -0
  584. package/dist/util/http-retry.js +43 -5
  585. package/dist/util/http-util.d.ts +0 -8
  586. package/dist/util/http-util.js +10 -21
  587. package/dist/util/limits.d.ts +7 -0
  588. package/dist/util/limits.js +14 -0
  589. package/dist/util/log.d.ts +4 -0
  590. package/dist/util/log.js +9 -0
  591. package/dist/util/request-scope.d.ts +9 -3
  592. package/dist/util/request-scope.js +18 -9
  593. package/dist/util/secret-detect.js +6 -1
  594. package/dist/util/spawn-argv.d.ts +9 -0
  595. package/dist/util/spawn-argv.js +57 -0
  596. package/dist/util/sql.d.ts +3 -0
  597. package/dist/util/sql.js +6 -0
  598. package/dist/util/sqlite-blocked.d.ts +2 -0
  599. package/dist/util/sqlite-blocked.js +5 -0
  600. package/dist/util/stream-tee.d.ts +3 -0
  601. package/dist/util/stream-tee.js +35 -0
  602. package/dist/util/time.d.ts +4 -0
  603. package/dist/util/time.js +4 -0
  604. package/dist/util/vector-codec.d.ts +4 -0
  605. package/dist/util/vector-codec.js +15 -0
  606. package/dist/util/version.d.ts +1 -1
  607. package/dist/util/version.js +1 -1
  608. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  609. package/extensions/openclaw-plugin/package.json +1 -1
  610. package/openclaw.plugin.json +1 -1
  611. package/package.json +4 -2
  612. package/dist/api/on-store.d.ts +0 -16
  613. package/dist/api/on-store.js +0 -38
  614. package/dist/store/embeddings/local.d.ts +0 -15
  615. package/dist/store/embeddings/local.js +0 -175
  616. /package/dist/{cli → api}/correction-latency.d.ts +0 -0
  617. /package/dist/{cli → api}/correction-latency.js +0 -0
  618. /package/dist/{cli → api}/provenance-coverage.d.ts +0 -0
  619. /package/dist/{cli → api}/provenance-coverage.js +0 -0
  620. /package/dist/{store → core}/object-types.d.ts +0 -0
  621. /package/dist/{store → core}/object-types.js +0 -0
  622. /package/dist/{capture → util}/compaction-items.d.ts +0 -0
  623. /package/dist/{capture → util}/compaction-items.js +0 -0
  624. /package/dist/{store → util}/yaml.d.ts +0 -0
  625. /package/dist/{store → util}/yaml.js +0 -0
@@ -1,9 +1,11 @@
1
1
  // The graph reads a view and a traversal share. Each opens hippo.db itself unless the caller hands it the handle its snapshot runs on.
2
+ import { DEFAULT_LIST_LIMIT } from '../util/limits.js';
2
3
  import { openHippoDb, closeHippoDb, withReadSnapshot } from '../db/index.js';
3
4
  import { onHandle } from './open.js';
4
5
  import { assertTenantId } from './tenant.js';
5
6
  import { GRAPH_ENTITY_TYPES, rowToEntity, rowToRelation, ENTITY_COLS, RELATION_COLS } from './graph-rows.js';
6
- const DEFAULT_GRAPH_PAGE_SIZE = 100;
7
+ import { placeholders } from '../util/sql.js';
8
+ const DEFAULT_GRAPH_PAGE_SIZE = DEFAULT_LIST_LIMIT;
7
9
  const DEFAULT_GRAPH_SCAN_LIMIT = 1000;
8
10
  /** Entities with an exact `name`, bounded by `limit` in SQL with a deterministic order, so graph-view focus finds `--entity NAME` directly
9
11
  * without materializing every same-name row. */
@@ -99,7 +101,7 @@ export function loadEntitiesByIds(hippoRoot, tenantId, ids, txDb) {
99
101
  const out = [];
100
102
  for (let i = 0; i < ids.length; i += IN_LIST_CHUNK) {
101
103
  const slice = ids.slice(i, i + IN_LIST_CHUNK);
102
- const ph = slice.map(() => '?').join(',');
104
+ const ph = placeholders(slice.length);
103
105
  // SAFETY: rows' shape matches the columns named in ENTITY_COLS above.
104
106
  const rows = db.prepare(`
105
107
  SELECT ${ENTITY_COLS} FROM entities
@@ -132,7 +134,7 @@ export function loadNeighborRelations(hippoRoot, tenantId, entityIds, opts = {},
132
134
  const byId = new Map();
133
135
  for (let i = 0; i < entityIds.length; i += IN_LIST_CHUNK) {
134
136
  const slice = entityIds.slice(i, i + IN_LIST_CHUNK);
135
- const ph = slice.map(() => '?').join(',');
137
+ const ph = placeholders(slice.length);
136
138
  // SAFETY: rows' shape matches the columns named in RELATION_COLS above.
137
139
  const rows = db.prepare(`
138
140
  SELECT ${RELATION_COLS} FROM relations
@@ -163,7 +165,7 @@ export function loadRelationsAmong(hippoRoot, tenantId, entityIds, opts = {}, tx
163
165
  const ownDb = txDb ? null : openHippoDb(hippoRoot);
164
166
  const db = txDb ?? ownDb;
165
167
  try {
166
- const ph = entityIds.map(() => '?').join(',');
168
+ const ph = placeholders(entityIds.length);
167
169
  // SAFETY: rows' shape matches the columns named in RELATION_COLS above.
168
170
  const rows = db.prepare(`
169
171
  SELECT ${RELATION_COLS} FROM relations
@@ -188,7 +190,7 @@ export function loadEntitiesByMemoryId(hippoRoot, tenantId, memoryIds) {
188
190
  const out = [];
189
191
  for (let i = 0; i < memoryIds.length; i += IN_LIST_CHUNK) {
190
192
  const slice = memoryIds.slice(i, i + IN_LIST_CHUNK);
191
- const ph = slice.map(() => '?').join(',');
193
+ const ph = placeholders(slice.length);
192
194
  // id ASC so chunk-local scan order never decides ties (id is an autoincrement PK).
193
195
  // SAFETY: rows' shape matches the columns named in ENTITY_COLS above.
194
196
  const rows = db.prepare(`
@@ -207,7 +209,8 @@ export function storedGraphOn(db, tenantId, memoryIds) {
207
209
  // SAFETY: the SELECT names exactly the columns of StoredEntity.
208
210
  const entities = db.prepare(`SELECT id, entity_type, name, memory_id, source_kind, source_object_type, source_object_id FROM entities WHERE tenant_id = ? ORDER BY id`).all(tenantId);
209
211
  // SAFETY: the SELECT names exactly the columns of StoredRelation.
210
- const relations = db.prepare(`SELECT id, from_entity_id, to_entity_id, rel_type, memory_id, source_kind, source_object_type, source_object_id FROM relations WHERE tenant_id = ? ORDER BY id`).all(tenantId);
212
+ const relations = db.prepare(`SELECT id, from_entity_id, to_entity_id, rel_type, memory_id, source_kind, source_object_type, source_object_id ` +
213
+ `FROM relations WHERE tenant_id = ? ORDER BY id`).all(tenantId);
211
214
  return { kinds, entities, relations };
212
215
  }
213
216
  function memoryKindsOn(db, memoryIds) {
@@ -1,4 +1,5 @@
1
1
  import { IN_LIST_CHUNK, loadEntities, loadEntitiesByIds, loadEntitiesByName, loadNeighborRelations, loadRelations, loadRelationsAmong } from './graph-reads.js';
2
+ import { placeholders } from '../util/sql.js';
2
3
  /** The items whose source memory `canRead` admits: a NULL memoryId has no scope to hide, and a missing memory fails closed. */
3
4
  function readableOnly(db, tenantId, items, canRead) {
4
5
  if (!canRead)
@@ -8,7 +9,7 @@ function readableOnly(db, tenantId, items, canRead) {
8
9
  for (let i = 0; i < ids.length; i += IN_LIST_CHUNK) {
9
10
  const slice = ids.slice(i, i + IN_LIST_CHUNK);
10
11
  // SAFETY: rows' shape matches the id and scope columns named in the SELECT.
11
- const rows = db.prepare(`SELECT id, scope FROM memories WHERE +tenant_id = ? AND id IN (${slice.map(() => '?').join(',')})`)
12
+ const rows = db.prepare(`SELECT id, scope FROM memories WHERE +tenant_id = ? AND id IN (${placeholders(slice.length)})`)
12
13
  .all(tenantId, ...slice);
13
14
  for (const r of rows)
14
15
  if (canRead(r.scope))
@@ -7,13 +7,13 @@ interface ResolvedGraphSource {
7
7
  memoryId: string | null;
8
8
  }
9
9
  export declare function resolveConsolidatedSource(db: DatabaseSyncLike, tenantId: string, memoryId: string | null, sourceObject: SourceObjectRef | null, label: string): ResolvedGraphSource;
10
- /** Insert a graph entity extracted from a consolidated memory; throws if the source memory is missing / cross-tenant / raw (the DB trigger is the backstop). */
11
- export declare function insertEntity(hippoRoot: string, tenantId: string, opts: InsertEntityOpts, txDb?: DatabaseSyncLike): Entity;
12
- /** Renames an entity or moves its memory provenance in place, keeping id and created_at; null when the row is gone.
10
+ /** Insert a graph entity on the caller's handle; throws if the source memory is missing / cross-tenant / raw (the DB trigger is the backstop). */
11
+ export declare function insertEntityRow(db: DatabaseSyncLike, tenantId: string, opts: InsertEntityOpts): Entity;
12
+ /** Renames an entity or moves its memory provenance in place on the caller's handle, keeping id and created_at; null when the row is gone.
13
13
  * A delete plus an insert would cascade away every relation that points at it. */
14
- export declare function updateEntity(hippoRoot: string, tenantId: string, id: number, opts: UpdateEntityOpts, txDb?: DatabaseSyncLike): Entity | null;
15
- /** Insert a graph relation between two same-tenant entities, sourced from a consolidated memory. */
16
- export declare function insertRelation(hippoRoot: string, tenantId: string, opts: InsertRelationOpts, txDb?: DatabaseSyncLike): Relation;
14
+ export declare function updateEntityRow(db: DatabaseSyncLike, tenantId: string, id: number, opts: UpdateEntityOpts): Entity | null;
15
+ /** Insert a graph relation between two same-tenant entities on the caller's handle, sourced from a consolidated memory. */
16
+ export declare function insertRelationRow(db: DatabaseSyncLike, tenantId: string, opts: InsertRelationOpts): Relation;
17
17
  /** The source object still holds the loader's rule (active or superseded); a closed or gone one gets no new graph row. */
18
18
  export declare function objectInForce(db: DatabaseSyncLike, tenantId: string, ref: SourceObjectRef): boolean;
19
19
  /** The lowest-id entity of this type anchored to the source object, which is the row a rebuild keeps. */
@@ -71,8 +71,8 @@ function assertSourceObjectUsable(db, tenantId, sourceObject, label) {
71
71
  }
72
72
  }
73
73
  }
74
- /** Insert a graph entity extracted from a consolidated memory; throws if the source memory is missing / cross-tenant / raw (the DB trigger is the backstop). */
75
- export function insertEntity(hippoRoot, tenantId, opts, txDb) {
74
+ /** Insert a graph entity on the caller's handle; throws if the source memory is missing / cross-tenant / raw (the DB trigger is the backstop). */
75
+ export function insertEntityRow(db, tenantId, opts) {
76
76
  assertTenantId('insertEntity', tenantId);
77
77
  if (!GRAPH_ENTITY_TYPES.has(opts.entityType)) {
78
78
  throw new Error(`insertEntity: entityType must be one of ${Array.from(GRAPH_ENTITY_TYPES).join('|')}; got ${opts.entityType}`);
@@ -81,25 +81,17 @@ export function insertEntity(hippoRoot, tenantId, opts, txDb) {
81
81
  const now = new Date().toISOString();
82
82
  const memoryId = opts.memoryId ?? null;
83
83
  const sourceObject = opts.sourceObject ?? null;
84
- const ownDb = txDb ? null : openHippoDb(hippoRoot);
85
- const db = txDb ?? ownDb;
86
- try {
87
- const { sourceKind, memoryId: effectiveMemoryId } = resolveConsolidatedSource(db, tenantId, memoryId, sourceObject, 'insertEntity');
88
- const result = db.prepare(`
89
- INSERT INTO entities(tenant_id, entity_type, name, memory_id, source_kind, source_object_type, source_object_id, created_at)
90
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
91
- `).run(tenantId, opts.entityType, name, effectiveMemoryId, sourceKind, sourceObject?.type ?? null, sourceObject?.id ?? null, now);
92
- const id = Number(result.lastInsertRowid ?? 0);
93
- // SAFETY: row's shape matches the columns named in ENTITY_COLS above.
94
- const row = db.prepare(`SELECT ${ENTITY_COLS} FROM entities WHERE id = ?`).get(id);
95
- if (!row)
96
- throw new Error('insertEntity: failed to reload inserted entity');
97
- return rowToEntity(row);
98
- }
99
- finally {
100
- if (ownDb)
101
- closeHippoDb(ownDb);
102
- }
84
+ const { sourceKind, memoryId: effectiveMemoryId } = resolveConsolidatedSource(db, tenantId, memoryId, sourceObject, 'insertEntity');
85
+ const result = db.prepare(`
86
+ INSERT INTO entities(tenant_id, entity_type, name, memory_id, source_kind, source_object_type, source_object_id, created_at)
87
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
88
+ `).run(tenantId, opts.entityType, name, effectiveMemoryId, sourceKind, sourceObject?.type ?? null, sourceObject?.id ?? null, now);
89
+ const id = Number(result.lastInsertRowid ?? 0);
90
+ // SAFETY: row's shape matches the columns named in ENTITY_COLS above.
91
+ const row = db.prepare(`SELECT ${ENTITY_COLS} FROM entities WHERE id = ?`).get(id);
92
+ if (!row)
93
+ throw new Error('insertEntity: failed to reload inserted entity');
94
+ return rowToEntity(row);
103
95
  }
104
96
  function checkedName(label, raw) {
105
97
  const name = (raw ?? '').trim();
@@ -110,33 +102,26 @@ function checkedName(label, raw) {
110
102
  }
111
103
  return name;
112
104
  }
113
- /** Renames an entity or moves its memory provenance in place, keeping id and created_at; null when the row is gone.
105
+ /** Renames an entity or moves its memory provenance in place on the caller's handle, keeping id and created_at; null when the row is gone.
114
106
  * A delete plus an insert would cascade away every relation that points at it. */
115
- export function updateEntity(hippoRoot, tenantId, id, opts, txDb) {
107
+ export function updateEntityRow(db, tenantId, id, opts) {
116
108
  assertTenantId('updateEntity', tenantId);
117
109
  const name = checkedName('updateEntity', opts.name);
118
- const db = txDb ?? openHippoDb(hippoRoot);
119
- try {
120
- // SAFETY: row's shape matches the columns named in ENTITY_COLS above.
121
- const row = db.prepare(`SELECT ${ENTITY_COLS} FROM entities WHERE id = ? AND tenant_id = ?`).get(id, tenantId);
122
- if (!row)
123
- return null;
124
- const entity = rowToEntity(row);
125
- const sourceObject = entity.sourceObjectType === undefined || entity.sourceObjectId === undefined
126
- ? null
127
- : { type: entity.sourceObjectType, id: entity.sourceObjectId };
128
- const resolved = resolveConsolidatedSource(db, tenantId, opts.memoryId ?? null, sourceObject, 'updateEntity');
129
- db.prepare(`UPDATE entities SET name = ?, memory_id = ?, source_kind = ? WHERE id = ? AND tenant_id = ?`)
130
- .run(name, resolved.memoryId, resolved.sourceKind, id, tenantId);
131
- return { ...entity, name, memoryId: resolved.memoryId, sourceKind: resolved.sourceKind };
132
- }
133
- finally {
134
- if (db !== txDb)
135
- closeHippoDb(db);
136
- }
110
+ // SAFETY: row's shape matches the columns named in ENTITY_COLS above.
111
+ const row = db.prepare(`SELECT ${ENTITY_COLS} FROM entities WHERE id = ? AND tenant_id = ?`).get(id, tenantId);
112
+ if (!row)
113
+ return null;
114
+ const entity = rowToEntity(row);
115
+ const sourceObject = entity.sourceObjectType === undefined || entity.sourceObjectId === undefined
116
+ ? null
117
+ : { type: entity.sourceObjectType, id: entity.sourceObjectId };
118
+ const resolved = resolveConsolidatedSource(db, tenantId, opts.memoryId ?? null, sourceObject, 'updateEntity');
119
+ db.prepare(`UPDATE entities SET name = ?, memory_id = ?, source_kind = ? WHERE id = ? AND tenant_id = ?`)
120
+ .run(name, resolved.memoryId, resolved.sourceKind, id, tenantId);
121
+ return { ...entity, name, memoryId: resolved.memoryId, sourceKind: resolved.sourceKind };
137
122
  }
138
- /** Insert a graph relation between two same-tenant entities, sourced from a consolidated memory. */
139
- export function insertRelation(hippoRoot, tenantId, opts, txDb) {
123
+ /** Insert a graph relation between two same-tenant entities on the caller's handle, sourced from a consolidated memory. */
124
+ export function insertRelationRow(db, tenantId, opts) {
140
125
  assertTenantId('insertRelation', tenantId);
141
126
  if (!GRAPH_RELATION_TYPES.has(opts.relType)) {
142
127
  throw new Error(`insertRelation: relType must be one of ${Array.from(GRAPH_RELATION_TYPES).join('|')}; got ${opts.relType}`);
@@ -144,35 +129,27 @@ export function insertRelation(hippoRoot, tenantId, opts, txDb) {
144
129
  const now = new Date().toISOString();
145
130
  const memoryId = opts.memoryId ?? null;
146
131
  const sourceObject = opts.sourceObject ?? null;
147
- const ownDb = txDb ? null : openHippoDb(hippoRoot);
148
- const db = txDb ?? ownDb;
149
- try {
150
- for (const [eid, role] of [[opts.fromEntityId, 'from'], [opts.toEntityId, 'to']]) {
151
- // SAFETY: ent's shape matches the single `tenant_id` column named in
152
- // the SELECT above.
153
- const ent = db.prepare(`SELECT tenant_id FROM entities WHERE id = ?`).get(eid);
154
- if (!ent)
155
- throw new Error(`insertRelation: ${role}_entity ${eid} not found`);
156
- if (ent.tenant_id !== tenantId) {
157
- throw new Error(`insertRelation: ${role}_entity ${eid} belongs to another tenant (no cross-tenant edges)`);
158
- }
132
+ for (const [eid, role] of [[opts.fromEntityId, 'from'], [opts.toEntityId, 'to']]) {
133
+ // SAFETY: ent's shape matches the single `tenant_id` column named in
134
+ // the SELECT above.
135
+ const ent = db.prepare(`SELECT tenant_id FROM entities WHERE id = ?`).get(eid);
136
+ if (!ent)
137
+ throw new Error(`insertRelation: ${role}_entity ${eid} not found`);
138
+ if (ent.tenant_id !== tenantId) {
139
+ throw new Error(`insertRelation: ${role}_entity ${eid} belongs to another tenant (no cross-tenant edges)`);
159
140
  }
160
- const { sourceKind, memoryId: effectiveMemoryId } = resolveConsolidatedSource(db, tenantId, memoryId, sourceObject, 'insertRelation');
161
- const result = db.prepare(`
162
- INSERT INTO relations(tenant_id, from_entity_id, to_entity_id, rel_type, memory_id, source_kind, source_object_type, source_object_id, created_at)
163
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
164
- `).run(tenantId, opts.fromEntityId, opts.toEntityId, opts.relType, effectiveMemoryId, sourceKind, sourceObject?.type ?? null, sourceObject?.id ?? null, now);
165
- const id = Number(result.lastInsertRowid ?? 0);
166
- // SAFETY: row's shape matches the columns named in RELATION_COLS above.
167
- const row = db.prepare(`SELECT ${RELATION_COLS} FROM relations WHERE id = ?`).get(id);
168
- if (!row)
169
- throw new Error('insertRelation: failed to reload inserted relation');
170
- return rowToRelation(row);
171
- }
172
- finally {
173
- if (ownDb)
174
- closeHippoDb(ownDb);
175
141
  }
142
+ const { sourceKind, memoryId: effectiveMemoryId } = resolveConsolidatedSource(db, tenantId, memoryId, sourceObject, 'insertRelation');
143
+ const result = db.prepare(`
144
+ INSERT INTO relations(tenant_id, from_entity_id, to_entity_id, rel_type, memory_id, source_kind, source_object_type, source_object_id, created_at)
145
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
146
+ `).run(tenantId, opts.fromEntityId, opts.toEntityId, opts.relType, effectiveMemoryId, sourceKind, sourceObject?.type ?? null, sourceObject?.id ?? null, now);
147
+ const id = Number(result.lastInsertRowid ?? 0);
148
+ // SAFETY: row's shape matches the columns named in RELATION_COLS above.
149
+ const row = db.prepare(`SELECT ${RELATION_COLS} FROM relations WHERE id = ?`).get(id);
150
+ if (!row)
151
+ throw new Error('insertRelation: failed to reload inserted relation');
152
+ return rowToRelation(row);
176
153
  }
177
154
  /** The source object still holds the loader's rule (active or superseded); a closed or gone one gets no new graph row. */
178
155
  export function objectInForce(db, tenantId, ref) {
@@ -34,9 +34,9 @@ function writeMove(db, move, old, actor) {
34
34
  const byTenant = new Map();
35
35
  for (const e of move.entries) {
36
36
  // One record per tenant, filled in place: copying it per row made the write grow with the square of the store.
37
- let record = byTenant.get(e.tenantId);
37
+ let record = byTenant.get(e.tenant_id);
38
38
  if (!record)
39
- byTenant.set(e.tenantId, (record = {}));
39
+ byTenant.set(e.tenant_id, (record = {}));
40
40
  record[e.id] = old.get(e.id);
41
41
  }
42
42
  for (const [tenantId, oldHalfLives] of byTenant) {
@@ -2,7 +2,7 @@ import { type SessionHandoff, type HandoffOutcome, type HandoffEvidence } from '
2
2
  import type { TaskSnapshot } from './rows.js';
3
3
  import { type ContinuityKey } from './sessions.js';
4
4
  /** Column list shared by every session_handoffs SELECT; cards.ts reuses it for the card handoff lookup. */
5
- export declare const HANDOFF_COLUMNS = "id, session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, created_at, constraints_json, evidence_json, outcome, target_runtime, card_id";
5
+ export declare const HANDOFF_COLUMNS: string;
6
6
  /** Save a session handoff record; returns the persisted handoff. */
7
7
  export declare function saveSessionHandoff(hippoRoot: string, tenantId: string, handoff: Omit<SessionHandoff, 'updatedAt'>, key?: ContinuityKey): SessionHandoff;
8
8
  interface HandoffFilter {
@@ -17,10 +17,16 @@ export declare function loadLatestHandoff(hippoRoot: string, tenantId: string, s
17
17
  export declare function loadHandoffById(hippoRoot: string, tenantId: string, id: number): SessionHandoff | null;
18
18
  /** Stamp the outcome on a session's newest handoff, only if it has none yet. Returns rows changed. */
19
19
  export declare function stampHandoffOutcome(hippoRoot: string, tenantId: string, sessionId: string, outcome: HandoffOutcome): number;
20
+ export interface SessionEndHandoffRequest {
21
+ readonly tenantId: string;
22
+ readonly sessionId: string;
23
+ readonly evidence: HandoffEvidence | null;
24
+ readonly derived?: Pick<TaskSnapshot, 'task' | 'summary' | 'next_step'> | null;
25
+ readonly key?: ContinuityKey;
26
+ readonly inPlace?: boolean;
27
+ }
20
28
  /** Session-end handoff from the active snapshot, else `derived` transcript state; `inPlace` rewrites an earlier transcript read instead of adding a revision.
21
29
  * Returns null when no source is the session's, a newer handoff covers it, or the latest one is not transcript-derived or already holds `derived`. */
22
- export declare function writeSessionEndHandoff(hippoRoot: string, tenantId: string, sessionId: string, evidence: HandoffEvidence | null, derived?: Pick<TaskSnapshot, 'task' | 'summary' | 'next_step'> | null, key?: ContinuityKey, options?: {
23
- inPlace?: boolean;
24
- }): SessionHandoff | null;
30
+ export declare function writeSessionEndHandoff(hippoRoot: string, request: SessionEndHandoffRequest): SessionHandoff | null;
25
31
  export {};
26
32
  //# sourceMappingURL=handoffs.d.ts.map
@@ -1,11 +1,12 @@
1
1
  import { closeHippoDb } from '../db/index.js';
2
2
  import { rowToSessionHandoff, isHandoffOutcome, } from '../core/handoff.js';
3
- import { scopeAdmitSql } from './recall-scope.js';
3
+ import { scopeAdmitSql } from './rule-sql.js';
4
4
  import { assertTenantId } from './tenant.js';
5
5
  import { onHandle, openStore } from './open.js';
6
6
  import { continuityStamp, continuityWhere, loadActiveTaskSnapshot } from './sessions.js';
7
7
  /** Column list shared by every session_handoffs SELECT; cards.ts reuses it for the card handoff lookup. */
8
- export const HANDOFF_COLUMNS = 'id, session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, created_at, constraints_json, evidence_json, outcome, target_runtime, card_id';
8
+ export const HANDOFF_COLUMNS = 'id, session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, created_at, constraints_json, ' +
9
+ 'evidence_json, outcome, target_runtime, card_id';
9
10
  /** Save a session handoff record; returns the persisted handoff. */
10
11
  export function saveSessionHandoff(hippoRoot, tenantId, handoff, key) {
11
12
  assertTenantId('saveSessionHandoff', tenantId);
@@ -15,10 +16,9 @@ export function saveSessionHandoff(hippoRoot, tenantId, handoff, key) {
15
16
  // Scope is stored as given; read-side default-deny in api.recall + cmdRecall
16
17
  // continuity excludes slack:private:* and 'unknown:legacy'.
17
18
  try {
18
- const result = db.prepare(`
19
- INSERT INTO session_handoffs(session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, tenant_id, created_at, constraints_json, evidence_json, outcome, target_runtime, card_id, owner_subject, origin_project)
20
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
21
- `).run(handoff.sessionId, handoff.repoRoot ?? null, handoff.taskId ?? null, handoff.summary, handoff.nextAction ?? null, JSON.stringify(handoff.artifacts ?? []), handoff.scope ?? null, tenantId, now, JSON.stringify(handoff.constraints ?? []), handoff.evidence ? JSON.stringify(handoff.evidence) : null, handoff.outcome ?? null, handoff.targetRuntime ?? null, handoff.cardId ?? null, stamp?.owner ?? null, stamp?.origin ?? null);
19
+ const result = db.prepare(`\n INSERT INTO session_handoffs(session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, tenant_id, created_at, ` +
20
+ `constraints_json, evidence_json, outcome, target_runtime, card_id, owner_subject, origin_project)\n` +
21
+ ` VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(handoff.sessionId, handoff.repoRoot ?? null, handoff.taskId ?? null, handoff.summary, handoff.nextAction ?? null, JSON.stringify(handoff.artifacts ?? []), handoff.scope ?? null, tenantId, now, JSON.stringify(handoff.constraints ?? []), handoff.evidence ? JSON.stringify(handoff.evidence) : null, handoff.outcome ?? null, handoff.targetRuntime ?? null, handoff.cardId ?? null, stamp?.owner ?? null, stamp?.origin ?? null);
22
22
  const id = Number(result.lastInsertRowid ?? 0);
23
23
  // SAFETY: row's shape matches HANDOFF_COLUMNS.
24
24
  const row = db.prepare(`SELECT ${HANDOFF_COLUMNS} FROM session_handoffs WHERE id = ?`).get(id);
@@ -169,7 +169,8 @@ function buildSessionEndHandoff(sessionId, snapshot, existing, handoffEvidence,
169
169
  }
170
170
  /** Session-end handoff from the active snapshot, else `derived` transcript state; `inPlace` rewrites an earlier transcript read instead of adding a revision.
171
171
  * Returns null when no source is the session's, a newer handoff covers it, or the latest one is not transcript-derived or already holds `derived`. */
172
- export function writeSessionEndHandoff(hippoRoot, tenantId, sessionId, evidence, derived = null, key, options = {}) {
172
+ export function writeSessionEndHandoff(hippoRoot, request) {
173
+ const { tenantId, sessionId, evidence, derived = null, key, inPlace } = request;
173
174
  assertTenantId('writeSessionEndHandoff', tenantId);
174
175
  if (key)
175
176
  continuityStamp(key); // a partial key is a caller bug, so fail loud rather than write nothing
@@ -179,7 +180,7 @@ export function writeSessionEndHandoff(hippoRoot, tenantId, sessionId, evidence,
179
180
  let handoffEvidence = evidence;
180
181
  let fromTranscript = false;
181
182
  // After every reply the transcript is newer than the last compaction's snapshot, which the open chat keeps for the next one.
182
- const snapshotGivesWay = options.inPlace === true && derived !== null && active?.source === 'pre-compact';
183
+ const snapshotGivesWay = inPlace === true && derived !== null && active?.source === 'pre-compact';
183
184
  if (active && active.session_id === sessionId && !snapshotGivesWay) {
184
185
  // Strict '>': a same-millisecond tie must not swallow the session's only write (test 6e).
185
186
  if (existing && existing.updatedAt > active.updated_at)
@@ -197,7 +198,7 @@ export function writeSessionEndHandoff(hippoRoot, tenantId, sessionId, evidence,
197
198
  const outcome = sessionOutcome(hippoRoot, tenantId, sessionId);
198
199
  const handoff = buildSessionEndHandoff(sessionId, snapshot, existing, handoffEvidence, outcome);
199
200
  // A miss means a handoff landed since the read, and a new transcript row would hide it.
200
- if (fromTranscript && options.inPlace && existing)
201
+ if (fromTranscript && inPlace && existing)
201
202
  return replaceTranscriptHandoff(hippoRoot, tenantId, handoff, key);
202
203
  return saveSessionHandoff(hippoRoot, tenantId, handoff, key);
203
204
  }
@@ -1,5 +1,5 @@
1
1
  import { withWriteScope, setMeta, isSqliteBusy, pruneConsolidationRuns, getMeta } from '../db/index.js';
2
- import { RejectedValueError } from './rejection.js';
2
+ import { RejectedValueError } from '../core/api-errors.js';
3
3
  import { log } from '../util/log.js';
4
4
  import { audit } from './audit-event.js';
5
5
  import { stampOriginProjectForImport, upsertEntryRow } from './entry-row.js';
@@ -113,7 +113,7 @@ export function loadStats(hippoRoot) {
113
113
  export function appendConsolidationRun(hippoRoot, run) {
114
114
  onHandle(hippoRoot, (db) => {
115
115
  db.prepare(`INSERT INTO consolidation_runs(timestamp, decayed, merged, removed) VALUES (?, ?, ?, ?)`).run(run.timestamp, run.decayed, run.merged, run.removed);
116
- pruneConsolidationRuns(db, 50);
116
+ pruneConsolidationRuns(db);
117
117
  writeStatsMirror(hippoRoot, buildStatsFromDb(db));
118
118
  }, openStore);
119
119
  }
@@ -1,4 +1,4 @@
1
- export type { AmbientCandidateRequest, ContextReads, EntryRemoval, EntryTarget, EntryWrite, EntryWrites, HippoStore, KeyAudit, KeyListQuery, KeyMint, KeyRevoke, KeyWrites, OutcomeWrite, RawArchive, RecallSearchArgs, RecallWrites, SelfKeyMint, StoreGroup, StoreGroups, SupersedeWrite, VectorBackfillQuery, VectorReads, VectorRowWrite, VectorWrite, VectorWriteResult, VectorWrites, } from './port.js';
1
+ export type { AmbientCandidateRequest, ContextReads, EntryRemoval, EntryTarget, EntryWrite, EntryWrites, HippoStore, KeyAudit, KeyListQuery, KeyMint, KeyRevoke, KeyWrites, LastRecall, LastRecallWrites, OutcomeWrite, RawArchive, RecallSearchArgs, RecallWrites, SelfKeyMint, StoreGroup, StoreGroups, SupersedeWrite, VectorBackfillQuery, VectorReads, VectorRowWrite, VectorWrite, VectorWriteResult, VectorWrites, } from './port.js';
2
2
  export { hasGroup, requireGroup } from './port.js';
3
- export * from './sqlite/store.js';
3
+ export { sqliteStore } from './sqlite/store.js';
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1,3 +1,3 @@
1
1
  export { hasGroup, requireGroup } from './port.js';
2
- export * from './sqlite/store.js';
2
+ export { sqliteStore } from './sqlite/store.js';
3
3
  //# sourceMappingURL=index.js.map
@@ -3,7 +3,7 @@ import { BadRequestError, ConflictError, NotFoundError } from '../core/api-error
3
3
  import { appendAuditEvent } from './audit.js';
4
4
  import { grantScope, insertApiKey, listLiveOwnedKeyIds, revokeApiKey, ungrantScope } from './auth.js';
5
5
  import { withWriteScope } from '../db/index.js';
6
- import { isRestrictedScope } from './recall-scope.js';
6
+ import { isRestrictedScope } from '../core/recall-scope.js';
7
7
  import { selectApiKeyOwner } from './tenant-lookup.js';
8
8
  /** The auth_create row a mint writes; the plaintext never reaches it. */
9
9
  function createAuditOf({ key, actor, metadata }) {
@@ -1,5 +1,9 @@
1
1
  import type { DeliveryEventInput } from './delivery-recorder.js';
2
2
  import { type LastSent, type TokenSurface, type TokenUse } from './token-ledger.js';
3
+ import { type PilotArm } from './pilot-arm.js';
4
+ /** Says why a ledger row did not land, at the level its class earns: busy warns once through
5
+ * noteStoreBusy, absent is debug with no stack, unexpected warns once with the error class and stack. */
6
+ export declare function noteLedgerRowSkipped<E>(error: E): void;
3
7
  /** Stores one delivery event and returns its id, or null when the write failed. */
4
8
  export type DeliveryWrite = (input: DeliveryEventInput) => number | null;
5
9
  /** The token rows of one turn and the delivery event that follows them. */
@@ -14,4 +18,9 @@ export interface LedgerTurn {
14
18
  export declare function recordLedgerTurn(hippoRoot: string, turn: LedgerTurn): void;
15
19
  /** What the session last sent on `surface`, or null, as lastSentState reads it. */
16
20
  export declare function lastSentOnSurface(hippoRoot: string, tenantId: string, sessionId: string | null | undefined, surface: TokenSurface): LastSent | null;
21
+ /** The session's pilot arm: `write` books it as ensurePilotArm does, else the stored arm or the hash arm. */
22
+ export declare function pilotArmOnRoot(hippoRoot: string, tenantId: string, sessionId: string, rateBp: number, opts: {
23
+ write: boolean;
24
+ ownTenantOnly?: boolean;
25
+ }): PilotArm;
17
26
  //# sourceMappingURL=ledger-turn.d.ts.map
@@ -1,6 +1,37 @@
1
+ // One hook or context turn's token-ledger work by store root: each call opens hippo.db, runs on one connection and closes it.
2
+ import { isSqliteBusy, noteStoreBusy } from '../db/index.js';
3
+ import { errorFields, errorMessage, log } from '../util/log.js';
1
4
  import { lastSentState, recordTokenUse } from './token-ledger.js';
2
5
  import { onHandle } from './open.js';
6
+ import { ensurePilotArm, hashArm, readPilotArm } from './pilot-arm.js';
3
7
  import { writeDeliveryEventOnHandle } from './recall-trace.js';
8
+ // SQLite's result codes for a hippo.db it cannot read: a corrupt image, and a file that is no database.
9
+ const SQLITE_CORRUPT = 11;
10
+ const SQLITE_NOTADB = 26;
11
+ /** The one rule for a skipped ledger row. `absent` is a store with no token_ledger table or a hippo.db
12
+ * SQLite cannot read; the command that owns the store reports that, and a hook must stay quiet about it. */
13
+ function ledgerSkipClass(error) {
14
+ if (isSqliteBusy(error))
15
+ return 'busy';
16
+ const code = error instanceof Error && 'errcode' in error ? error.errcode : undefined;
17
+ if (code === SQLITE_CORRUPT || code === SQLITE_NOTADB)
18
+ return 'absent';
19
+ return errorMessage(error).includes('no such table: token_ledger') ? 'absent' : 'unexpected';
20
+ }
21
+ /** Says why a ledger row did not land, at the level its class earns: busy warns once through
22
+ * noteStoreBusy, absent is debug with no stack, unexpected warns once with the error class and stack. */
23
+ export function noteLedgerRowSkipped(error) {
24
+ const skip = ledgerSkipClass(error);
25
+ if (skip === 'busy') {
26
+ noteStoreBusy('token ledger row skipped');
27
+ return;
28
+ }
29
+ const message = `token ledger row skipped: ${errorMessage(error)}`;
30
+ if (skip === 'absent')
31
+ log.debug(message);
32
+ else
33
+ log.warnThenDebug('token-ledger-row', message, errorFields(error));
34
+ }
4
35
  /** Books a turn's token rows, then its delivery event, on one connection. */
5
36
  export function recordLedgerTurn(hippoRoot, turn) {
6
37
  const { onRowError } = turn;
@@ -24,4 +55,11 @@ export function recordLedgerTurn(hippoRoot, turn) {
24
55
  export function lastSentOnSurface(hippoRoot, tenantId, sessionId, surface) {
25
56
  return onHandle(hippoRoot, (db) => lastSentState(db, tenantId, sessionId, surface));
26
57
  }
58
+ /** The session's pilot arm: `write` books it as ensurePilotArm does, else the stored arm or the hash arm. */
59
+ export function pilotArmOnRoot(hippoRoot, tenantId, sessionId, rateBp, opts) {
60
+ const { ownTenantOnly } = opts;
61
+ return onHandle(hippoRoot, (db) => opts.write
62
+ ? ensurePilotArm(db, tenantId, sessionId, rateBp, { ownTenantOnly })
63
+ : readPilotArm(db, sessionId, ownTenantOnly ? tenantId : undefined) ?? hashArm(sessionId, rateBp));
64
+ }
27
65
  //# sourceMappingURL=ledger-turn.js.map
@@ -2,13 +2,18 @@ import { DEFAULT_TENANT_ID } from '../util/env.js';
2
2
  import * as fs from 'fs';
3
3
  import * as path from 'path';
4
4
  import { Layer } from '../core/memory.js';
5
- import { dumpFrontmatter } from './yaml.js';
6
- import { getMeta } from '../db/index.js';
5
+ import { dumpFrontmatter } from '../util/yaml.js';
6
+ import { getMeta, CONSOLIDATION_RUNS_KEPT } from '../db/index.js';
7
7
  import { oncePerStore } from '../db/connect.js';
8
8
  import { errorFields, errorMessage, log } from '../util/log.js';
9
9
  import { parseJsonArray, INDEX_VERSION, parseLastTraceId, MEMORY_SELECT_COLUMNS, rowToEntry, rowToMemoryConflict, } from './rows.js';
10
- import { serializeEntry } from './markdown.js';
10
+ import { serializeEntry } from '../core/markdown.js';
11
+ import { writeFileAtomic } from '../util/atomic-write.js';
11
12
  const SCORE_DECIMALS = 3;
13
+ // Mirrors are derived and rebuildable from the store, so they skip the fsyncs (the cost on Windows) and keep the temp-and-rename atomicity.
14
+ function writeMirror(file, text) {
15
+ writeFileAtomic(file, text, { durable: false });
16
+ }
12
17
  export function layerDir(root, layer) {
13
18
  return path.join(root, layer);
14
19
  }
@@ -61,7 +66,7 @@ export function writeActiveTaskMirror(hippoRoot, tenantId, snapshot) {
61
66
  body.push(`## Session`, snapshot.session_id, '');
62
67
  }
63
68
  fs.mkdirSync(path.dirname(filePath), MIRROR_FOLDER);
64
- fs.writeFileSync(filePath, `${fm}\n\n${body.join('\n')}`, 'utf8');
69
+ writeMirror(filePath, `${fm}\n\n${body.join('\n')}`);
65
70
  }
66
71
  export function removeActiveTaskMirror(hippoRoot, tenantId) {
67
72
  const filePath = activeTaskMirrorPath(hippoRoot, tenantId);
@@ -99,7 +104,7 @@ export function writeRecentSessionMirror(hippoRoot, tenantId, events) {
99
104
  }
100
105
  lines.push('');
101
106
  fs.mkdirSync(path.dirname(filePath), MIRROR_FOLDER);
102
- fs.writeFileSync(filePath, `${fm}\n\n${lines.join('\n')}`, 'utf8');
107
+ writeMirror(filePath, `${fm}\n\n${lines.join('\n')}`);
103
108
  }
104
109
  function writeConflictMirrors(hippoRoot, conflicts) {
105
110
  const conflictDir = path.join(hippoRoot, 'conflicts');
@@ -128,7 +133,7 @@ function writeConflictMirrors(hippoRoot, conflicts) {
128
133
  `- Status: ${conflict.status}`,
129
134
  '',
130
135
  ].join('\n');
131
- fs.writeFileSync(path.join(conflictDir, filename), `${fm}\n\n${body}`, 'utf8');
136
+ writeMirror(path.join(conflictDir, filename), `${fm}\n\n${body}`);
132
137
  }
133
138
  for (const existing of fs.readdirSync(conflictDir)) {
134
139
  if (existing === '.gitkeep')
@@ -142,7 +147,7 @@ export function writeMarkdownMirror(hippoRoot, entry) {
142
147
  removeEntryMirrors(hippoRoot, entry.id);
143
148
  const dir = layerDir(hippoRoot, entry.layer);
144
149
  fs.mkdirSync(dir, MIRROR_FOLDER);
145
- fs.writeFileSync(path.join(dir, `${entry.id}.md`), serializeEntry(entry), 'utf8');
150
+ writeMirror(path.join(dir, `${entry.id}.md`), serializeEntry(entry));
146
151
  }
147
152
  // Every layer, Trace included: `writeMarkdownMirror` writes any layer, and a stale trace mirror
148
153
  // is the resurrection channel bootstrapLegacyStore/rebuildIndex guard against.
@@ -223,8 +228,12 @@ export function readLastRecall(db) {
223
228
  };
224
229
  }
225
230
  export function buildStatsFromDb(db) {
226
- // SAFETY: runs' shape matches the four columns named in the SELECT above.
227
- const runs = db.prepare(`SELECT timestamp, decayed, merged, removed FROM consolidation_runs ORDER BY timestamp ASC, id ASC`).all();
231
+ // SAFETY: runs' shape matches the four columns named in the SELECT below.
232
+ const runs = db.prepare(`
233
+ SELECT timestamp, decayed, merged, removed FROM (
234
+ SELECT id, timestamp, decayed, merged, removed FROM consolidation_runs ORDER BY timestamp DESC, id DESC LIMIT ?
235
+ ) ORDER BY timestamp ASC, id ASC
236
+ `).all(CONSOLIDATION_RUNS_KEPT);
228
237
  return {
229
238
  total_remembered: Number(getMeta(db, 'total_remembered', '0')),
230
239
  total_recalled: Number(getMeta(db, 'total_recalled', '0')),
@@ -240,7 +249,7 @@ export function buildStatsFromDb(db) {
240
249
  /** Write the `index.json` mirror file for an already-derived index. Exported for
241
250
  * `rebuildIndex` (the only index.json writer) and the longmemeval benchmark. */
242
251
  export function writeIndexMirror(hippoRoot, index) {
243
- mirrorBestEffort('index.json', () => fs.writeFileSync(path.join(hippoRoot, 'index.json'), JSON.stringify(index, null, 2), 'utf8'));
252
+ mirrorBestEffort('index.json', () => overwriteInPlace(path.join(hippoRoot, 'index.json'), JSON.stringify(index, null, 2)));
244
253
  }
245
254
  export function writeStatsMirror(hippoRoot, stats) {
246
255
  mirrorBestEffort('stats.json', () => overwriteInPlace(path.join(hippoRoot, 'stats.json'), JSON.stringify(stats, null, 2)));
@@ -1,15 +1,12 @@
1
1
  import { type MemoryEntry } from '../core/memory.js';
2
2
  import { type DatabaseSyncLike } from '../db/index.js';
3
- import { type ResolveProjectIdentityOpts } from '../core/project-identity.js';
4
- /** Nearest ancestor store like git; the strict join is the fallback so `hippo init` still creates `<cwd>/.hippo`. */
5
- export declare function getHippoRoot(cwd?: string, opts?: ResolveProjectIdentityOpts): string;
6
- export declare function isInitialized(hippoRoot: string): boolean;
7
3
  export declare function initStore(hippoRoot: string): void;
8
4
  /** One open connection with init done on it, for callers who used to pay for `initStore` + a second `openHippoDb`. */
9
5
  export declare function openStore(hippoRoot: string, opts?: {
10
6
  busyWaitMs?: number;
11
7
  }): DatabaseSyncLike;
12
- /** One call on a handle of its own, closed after; pass openStore where the call also sets up mirror folders and legacy rows. */
8
+ /** One call on a handle of its own, closed after (a request scope's handle stays open);
9
+ * pass openStore where the call also sets up mirror folders and legacy rows. */
13
10
  export declare function onHandle<T>(hippoRoot: string, fn: (db: DatabaseSyncLike) => T, open?: (hippoRoot: string) => DatabaseSyncLike): T;
14
11
  /** `meta` key holding the default half-life base a store's memories are on (src/consolidate/half-life-migration.ts). */
15
12
  export declare const HALF_LIFE_BASE_META_KEY = "default_half_life_base";