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,54 +1,20 @@
1
- // One record per Claude Code compaction, and what turns its summary into kept memories.
1
+ // What turns a compaction's summary into text the store keeps; the SQL is src/store/compactions-record.ts.
2
2
  import * as fs from 'fs';
3
- import * as path from 'path';
4
- import { ConflictError } from '../core/api-errors.js';
5
3
  import { isStringValue } from '../core/capture-contract.js';
6
- import { COMPACTION_ITEM_MAX_CHARS, compactSummaryBody, parseCompactionItems, selectItemRows } from './compaction-items.js';
4
+ import { COMPACTION_ITEM_MAX_CHARS, compactSummaryBody, parseCompactionItems } from '../util/compaction-items.js';
7
5
  import { importSpool, spool } from './compaction-spool.js';
8
- import { isSharedStore, loadConfig } from '../core/config.js';
9
- import { closeHippoDb, isSqliteBusy, openHippoDb, withWriteScopeOr } from '../db/index.js';
10
- import { gatedWrite } from '../trust/gated-write.js';
11
- import { COMPACTION_MEMORY_TAG, COMPACTION_SOURCE_PREFIX, Layer, createMemory, generateId } from '../core/memory.js';
12
- import { fallbackOrigin, isGlobalStoreRoot, projectId, projectNames, resolveProjectIdentity } from '../core/project-identity.js';
13
- import { maskEmails, redactSecretsStrict } from '../util/secret-detect.js';
14
- import { closeStartedWithoutSummary, compactionProgress, compactionRowsByRequest, heldMemoryRows, insertStartedCompaction, insertSummarisedCompaction, latestCompactionRows, latestStartedRows, markCompactionDone, markCompactionSummarised, markSnapshotSavedRow, nextCompactionStart, openTranscriptRows, stalledSummarisedRows, } from '../store/compactions.js';
15
- import { strengthenRetrievedOn, writeEntryMirrors } from '../store/entry-writes.js';
16
- import { isRecallBoostAblated } from '../core/ablation.js';
17
- import { updateStats } from '../store/index-and-stats.js';
6
+ import { replayStoredCompactions, saveCompactionAt, } from '../store/compactions-record.js';
18
7
  import { resolveTenantId } from '../store/tenant.js';
19
- import { errorMessage, log as logger } from '../util/log.js';
8
+ import { maskEmails, redactSecretsStrict } from '../util/secret-detect.js';
9
+ import { errorMessage, reportCompactionFailure } from '../util/log.js';
20
10
  import { readTranscriptTail, truncateCodePointSafe } from '../util/transcript-tail.js';
21
- /** PostCompact has 10 s in all (PreCompact 30 s), so a locked store must be given up on early. */
22
- export const COMPACTION_DB_WAIT_MS = 2000;
23
11
  /** Tested verbatim: Claude Code hands PreCompact stdout to the summariser as instructions. */
24
- export const PRE_COMPACT_INSTRUCTION = "In your summary, add a last section titled 'Memories for hippo'. List, one per line starting with '- ', each lesson learned, decision made (with its reason) and correction the user gave in this session that should outlive it. Write each as a standalone sentence that names its subject. Leave out anything an earlier summary already listed under 'Memories for hippo', and anything this session already saved with `hippo remember`. Write '- none' if nothing new remains.";
12
+ export const PRE_COMPACT_INSTRUCTION = "In your summary, add a last section titled 'Memories for hippo'. List, one per line starting with '- ', each lesson learned, decision made (with its " +
13
+ "reason) and correction the user gave in this session that should outlive it. Write each as a standalone sentence that names its subject. Leave out " +
14
+ "anything an earlier summary already listed under 'Memories for hippo', and anything this session already saved with `hippo remember`. Write '- none' " +
15
+ "if nothing new remains.";
25
16
  const SUMMARY_MAX_CHARS = 256 * 1024;
26
- /** Long enough that a live hook has finished with its own record. */
27
- export const REPLAY_AFTER_MS = 10 * 60_000;
28
- /** Claude Code deletes transcripts after 30 days, so an older gap can never be filled. */
29
- export const TRANSCRIPT_FILL_WINDOW_MS = 30 * 24 * 60 * 60_000;
30
17
  const TRANSCRIPT_TAIL_CAPS = [1 << 20, 8 << 20, 64 << 20];
31
- /** The marker redactSecretsStrict writes; an item holding it was a secret before it was stored. */
32
- const REDACTED = '[REDACTED]';
33
- /** Where the session ran: rows written through the global store or a shared store keep the project the session was in. */
34
- function compactionProject(hippoRoot, cwd) {
35
- if (!isGlobalStoreRoot(hippoRoot) && !isSharedStore(hippoRoot))
36
- return resolveProjectIdentity(path.dirname(hippoRoot));
37
- // No cwd means user-global, as stampOriginProject gives the global store; undefined would fall back to the hook's own cwd.
38
- return cwd === null ? '' : resolveProjectIdentity(cwd);
39
- }
40
- /** The record column cannot hold NULL, but an item from an unknown folder on a shared store must not read as user-global. */
41
- function itemOrigin(hippoRoot, ctx) {
42
- return ctx.cwd === null && isSharedStore(hippoRoot) ? fallbackOrigin(hippoRoot) : ctx.originProject;
43
- }
44
- function compactionOrigin(hippoRoot, cwd) {
45
- return projectId(compactionProject(hippoRoot, cwd));
46
- }
47
- /** The names a record's held rows may carry: its origin, plus the folder name rows saved before project ids used. */
48
- function heldOrigins(hippoRoot, cwd, originProject) {
49
- const names = projectNames(compactionProject(hippoRoot, cwd));
50
- return names.includes(originProject) ? names : [originProject];
51
- }
52
18
  function scrub(text) {
53
19
  return maskEmails(redactSecretsStrict(text));
54
20
  }
@@ -58,271 +24,11 @@ export function readCompactionText(compactSummary) {
58
24
  const parsed = parseCompactionItems(body);
59
25
  return { summary: truncateCodePointSafe(scrub(body), SUMMARY_MAX_CHARS), items: parsed.items.map(scrub), found: parsed.found };
60
26
  }
61
- /** A caller's items scrubbed as readCompactionText scrubs a summary's, since another machine's scrub is not trusted; cut after it, as a mask can run longer than what it hides. */
27
+ /** A caller's items scrubbed as readCompactionText scrubs a summary's, since another machine's scrub is not trusted; cut after it, as a
28
+ * mask can run longer than what it hides. */
62
29
  export function scrubCompactionItems(items) {
63
30
  return items.map((item) => truncateCodePointSafe(scrub(item), COMPACTION_ITEM_MAX_CHARS));
64
31
  }
65
- function toRecord(row) {
66
- const listed = row.items_json === null ? [] : JSON.parse(row.items_json);
67
- return {
68
- id: row.id,
69
- tenantId: row.tenant_id,
70
- sessionId: row.session_id,
71
- originProject: row.origin_project,
72
- trigger: row.compact_trigger,
73
- cwd: row.cwd,
74
- transcriptPath: row.transcript_path,
75
- snapshotSaved: row.snapshot_saved === 1,
76
- startedAt: row.started_at,
77
- summarisedAt: row.summarised_at,
78
- summary: row.summary,
79
- items: Array.isArray(listed) ? listed.filter(isStringValue) : [],
80
- itemsWritten: row.items_written,
81
- status: row.status,
82
- };
83
- }
84
- export function startCompaction(db, tenantId, start, at = new Date()) {
85
- const id = generateId('cmp');
86
- insertStartedCompaction(db, tenantId, { id, ...start, startedAt: at.toISOString() });
87
- return id;
88
- }
89
- /** A session's newest record, or null. */
90
- export function latestCompaction(db, tenantId, sessionId) {
91
- return latestCompactionRows(db, tenantId, sessionId).map(toRecord)[0] ?? null;
92
- }
93
- /** The record a caller's request made, whatever state it reached, so a retry neither writes its items twice nor starts a second record; another session's id is a ConflictError. */
94
- export function compactionByRequest(db, tenantId, requestId, sessionId) {
95
- const record = compactionRowsByRequest(db, tenantId, requestId).map(toRecord)[0] ?? null;
96
- // Sessions are owner-bound, so this also keeps one owner from reading or finishing another's record.
97
- if (record !== null && record.sessionId !== sessionId)
98
- throw new ConflictError('request id belongs to another session');
99
- return record;
100
- }
101
- /** Pre-compact's record for the compaction that is ending: the session's newest `started` one within REPLAY_AFTER_MS before `at`, so an older one is left for the transcript fill. */
102
- function latestStarted(db, tenantId, sessionId, at) {
103
- return latestStartedRows(db, tenantId, sessionId, at.toISOString(), new Date(at.getTime() - REPLAY_AFTER_MS).toISOString()).map(toRecord)[0] ?? null;
104
- }
105
- function markSummarised(db, tenantId, id, options) {
106
- const { text, summarisedAt, requestId } = options;
107
- return markCompactionSummarised(db, tenantId, id, { summary: text.summary, itemsJson: JSON.stringify(text.items), summarisedAt, requestId });
108
- }
109
- /** Best effort, never throws: a compaction must not fail because its record could not be written. */
110
- export function recordCompactionStart(hippoRoot, start, log) {
111
- let db;
112
- try {
113
- db = openHippoDb(hippoRoot, { busyWaitMs: COMPACTION_DB_WAIT_MS });
114
- return startCompaction(db, resolveTenantId({}), { ...start, originProject: compactionOrigin(hippoRoot, start.cwd) });
115
- }
116
- catch (err) {
117
- log(`compaction record not started: ${errorMessage(err)}`);
118
- return null;
119
- }
120
- finally {
121
- if (db)
122
- closeHippoDb(db);
123
- }
124
- }
125
- /** On the caller's handle and tenant, so a server marks the record under the caller's tenant with its own wait. */
126
- export function markSnapshotSaved(db, tenantId, recordId) {
127
- markSnapshotSavedRow(db, tenantId, recordId);
128
- }
129
- export function recordSnapshotSaved(hippoRoot, tenantId, recordId, log) {
130
- let db;
131
- try {
132
- db = openHippoDb(hippoRoot, { busyWaitMs: COMPACTION_DB_WAIT_MS });
133
- markSnapshotSaved(db, tenantId, recordId);
134
- }
135
- catch (err) {
136
- log(`compaction record not marked with its snapshot: ${errorMessage(err)}`);
137
- }
138
- finally {
139
- if (db)
140
- closeHippoDb(db);
141
- }
142
- }
143
- /** Puts the summary on the session's `started` record, or inserts a `summarised` one when pre-compact wrote none. One statement each. */
144
- export function recordSummary(db, hippoRoot, tenantId, options) {
145
- const { meta, text, at, caller = {} } = options;
146
- const now = new Date().toISOString();
147
- const itemsJson = JSON.stringify(text.items);
148
- const { requestId } = caller;
149
- const started = latestStarted(db, tenantId, meta.sessionId, at);
150
- if (started && markSummarised(db, tenantId, started.id, { text, summarisedAt: now, requestId })) {
151
- return { ...started, summary: text.summary, items: text.items, summarisedAt: now, status: 'summarised' };
152
- }
153
- const originProject = caller.originProject ?? compactionOrigin(hippoRoot, meta.cwd);
154
- const id = generateId('cmp');
155
- insertSummarisedCompaction(db, tenantId, { ...meta, originProject, startedAt: at.toISOString() }, { id, summary: text.summary, itemsJson, summarisedAt: now, requestId });
156
- return {
157
- id, tenantId, sessionId: meta.sessionId, originProject, trigger: meta.trigger, cwd: meta.cwd, transcriptPath: meta.transcriptPath,
158
- snapshotSaved: false, startedAt: at.toISOString(), summarisedAt: now, summary: text.summary, items: text.items, itemsWritten: 0, status: 'summarised',
159
- };
160
- }
161
- /** Words whose loss reverses or narrows a statement: "do not", "can't", "only", "unless". */
162
- const PROTECTED_WORDS = new Set(['not', 'no', 'never', 'none', 'nor', 'without', 'cannot', 't', 'only', 'except', 'unless', 'until']);
163
- /** Below this share of the held text's words, an item is a fragment of something longer, not a restatement. */
164
- const RESTATE_MIN_SHARE = 0.5;
165
- function words(text) {
166
- return text.normalize('NFC').toLowerCase().split(/[^\p{L}\p{M}\p{N}_]+/u).filter(Boolean);
167
- }
168
- /** True when `item` is `held` with words left out, in the same order, keeping every number and protected word. Spacing, case and punctuation may differ. */
169
- function restates(item, held) {
170
- if (item.length === 0 || item.length < RESTATE_MIN_SHARE * held.length)
171
- return false;
172
- const kept = new Set(item);
173
- let next = 0;
174
- for (const w of held) {
175
- if (next < item.length && w === item[next])
176
- next++;
177
- else if (!kept.has(w) && (PROTECTED_WORDS.has(w) || /\p{N}/u.test(w)))
178
- return false;
179
- }
180
- return next === item.length;
181
- }
182
- /** Live rows of one tenant and origin that default recall shows: a compaction often restates what an earlier one, or the user, already saved. */
183
- function heldRows(db, tenantId, origins) {
184
- return heldMemoryRows(db, tenantId, origins).map((r) => ({ id: r.id, sessionId: r.source_session_id, words: words(r.content) }));
185
- }
186
- function compactionEntry(text, ctx, origin, baseHalfLifeDays) {
187
- return {
188
- ...createMemory(text, {
189
- layer: Layer.Episodic,
190
- tags: [COMPACTION_MEMORY_TAG],
191
- source: `${COMPACTION_SOURCE_PREFIX}${ctx.sessionId}`,
192
- confidence: 'observed',
193
- kind: 'distilled',
194
- source_session_id: ctx.sessionId,
195
- tenantId: ctx.tenantId,
196
- baseHalfLifeDays,
197
- }),
198
- origin_project: origin,
199
- };
200
- }
201
- /** Runs inside saveItems' transaction: restatements of held rows are counted, the rest go through the write gate. */
202
- function writeItemRows(db, hippoRoot, ctx, rows, baseHalfLifeDays) {
203
- const out = { written: [], repeats: 0, refused: 0, restated: [] };
204
- const held = heldRows(db, ctx.tenantId, ctx.caller?.origins ?? heldOrigins(hippoRoot, ctx.cwd, ctx.originProject));
205
- const origin = ctx.caller === undefined ? itemOrigin(hippoRoot, ctx) : ctx.originProject;
206
- const restated = new Set();
207
- for (const text of rows) {
208
- const itemWords = words(text);
209
- const match = held.find((h) => restates(itemWords, h.words));
210
- if (match) {
211
- out.repeats++;
212
- if (match.id !== null && match.sessionId !== ctx.sessionId)
213
- restated.add(match.id);
214
- continue;
215
- }
216
- // createMemory throws below 3 chars, which would sink the whole transaction.
217
- if (text.trim().length < 3) {
218
- out.refused++;
219
- continue;
220
- }
221
- const entry = compactionEntry(text, ctx, origin, baseHalfLifeDays);
222
- if (gatedWrite(db, hippoRoot, entry, { actor: ctx.caller?.actor ?? 'post-compact' }) === 'written') {
223
- out.written.push(entry);
224
- held.push({ id: null, sessionId: ctx.sessionId, words: itemWords });
225
- }
226
- else {
227
- out.refused++;
228
- }
229
- }
230
- out.restated = [...restated];
231
- return out;
232
- }
233
- /** After commit: report skips, mirror the new rows, bump the counter. */
234
- function finishItemWrites(hippoRoot, writes, log) {
235
- if (writes.repeats > 0)
236
- log(`skipped ${writes.repeats} item(s) the store already holds`);
237
- if (writes.refused > 0)
238
- log(`skipped ${writes.refused} item(s) the write gate refused`);
239
- for (const entry of writes.written)
240
- writeEntryMirrors(hippoRoot, entry);
241
- if (writes.written.length > 0) {
242
- try {
243
- updateStats(hippoRoot, { remembered: writes.written.length });
244
- }
245
- catch (err) {
246
- // The rows are committed; a counter that could not be bumped must not turn that into a failed step.
247
- log(`remembered counter not updated: ${errorMessage(err)}`);
248
- }
249
- }
250
- }
251
- /** Items that become rows, then the record `done`, in one transaction so two sessions cannot both insert one text. Mirrors after commit. */
252
- export function saveItems(db, hippoRoot, ctx, log) {
253
- const usable = ctx.items.filter((item) => !item.includes(REDACTED));
254
- if (usable.length < ctx.items.length)
255
- log(`skipped ${ctx.items.length - usable.length} item(s) as secret`);
256
- const { rows, tooLong, capped } = selectItemRows(usable);
257
- if (tooLong > 0)
258
- log(`item too long: ${tooLong} kept in the record only`);
259
- if (capped > 0)
260
- log(`capped: ${capped} more kept in the record only`);
261
- const baseHalfLifeDays = loadConfig(hippoRoot).defaultHalfLifeDays;
262
- let finishedItems = 0;
263
- const writes = withWriteScopeOr(db, 'save_items', (rollback) => {
264
- if (ctx.recordId !== null) {
265
- // A replayer that read the record before another finished it must not write its items again.
266
- const current = compactionProgress(db, ctx.tenantId, ctx.recordId);
267
- if (current?.status !== 'summarised') {
268
- finishedItems = current?.items_written ?? 0;
269
- return rollback(null);
270
- }
271
- }
272
- const written = writeItemRows(db, hippoRoot, ctx, rows, baseHalfLifeDays);
273
- // Said again by another session is the same signal as being recalled; the same session carrying it forward is not.
274
- strengthenRetrievedOn(db, written.restated, { tenantId: ctx.tenantId, recallBoostAblated: isRecallBoostAblated() });
275
- if (ctx.recordId !== null) {
276
- markCompactionDone(db, ctx.tenantId, ctx.recordId, written.written.length);
277
- }
278
- return written;
279
- });
280
- if (writes === null) {
281
- log(`${ctx.recordId} was already finished by another process`);
282
- return finishedItems;
283
- }
284
- finishItemWrites(hippoRoot, writes, log);
285
- return writes.written.length;
286
- }
287
- /** One failure, told once to the hook's output and once to the structured log. */
288
- function reportFailure(log, step, reason) {
289
- log(`${step} failed: ${reason}`);
290
- logger.error(`post-compact: ${step} failed: ${reason}`);
291
- }
292
- function recordStep(step) {
293
- try {
294
- const record = recordSummary(step.db, step.hippoRoot, step.tenantId, { meta: step.payload, text: step.text, at: step.at });
295
- step.result.snapshotSaved = record.snapshotSaved;
296
- return record;
297
- }
298
- catch (err) {
299
- if (isSqliteBusy(err))
300
- throw err;
301
- reportFailure(step.log, 'record step', errorMessage(err));
302
- return null;
303
- }
304
- }
305
- /** Busy with a saved record defers to sleep; any other failure goes to the caller. */
306
- function itemsStep(step, record) {
307
- const { payload, hippoRoot, log } = step;
308
- try {
309
- step.result.written = saveItems(step.db, hippoRoot, {
310
- tenantId: step.tenantId,
311
- recordId: record?.id ?? null,
312
- sessionId: payload.sessionId,
313
- originProject: record?.originProject ?? compactionOrigin(hippoRoot, payload.cwd),
314
- cwd: payload.cwd,
315
- items: step.text.items,
316
- }, log);
317
- }
318
- catch (err) {
319
- if (!isSqliteBusy(err) || record === null)
320
- throw err;
321
- // The record already holds the items; sleep finishes them.
322
- step.result.deferred = true;
323
- log(`store busy, items left for the next sleep: ${errorMessage(err)}`);
324
- }
325
- }
326
32
  function spoolSummary(hippoRoot, payload, text, at, reason, result, log) {
327
33
  try {
328
34
  spool(hippoRoot, resolveTenantId({}), payload, text, at);
@@ -330,36 +36,22 @@ function spoolSummary(hippoRoot, payload, text, at, reason, result, log) {
330
36
  log(`store busy, summary spooled: ${reason}`);
331
37
  }
332
38
  catch (spoolErr) {
333
- reportFailure(log, 'spool', errorMessage(spoolErr));
39
+ reportCompactionFailure(log, 'spool', errorMessage(spoolErr));
334
40
  }
335
41
  }
336
42
  /** The PostCompact work: record the summary, then write its items. Each step is independent; a busy store spools or defers. Never throws. */
337
43
  export function saveCompaction(hippoRoot, payload, log) {
338
- const result = { written: null, deferred: false, snapshotSaved: false };
339
44
  if (payload.compactSummary === null) {
340
45
  log('skip: payload has no compact_summary');
341
- return result;
46
+ return { written: null, deferred: false, snapshotSaved: false };
342
47
  }
343
48
  const at = new Date();
344
49
  const { found, ...text } = readCompactionText(payload.compactSummary);
345
50
  if (!found)
346
51
  log('no memories section');
347
- let db;
348
- try {
349
- db = openHippoDb(hippoRoot, { busyWaitMs: COMPACTION_DB_WAIT_MS });
350
- const step = { db, hippoRoot, tenantId: resolveTenantId({}), payload, text, at, result, log };
351
- itemsStep(step, recordStep(step));
352
- }
353
- catch (err) {
354
- if (isSqliteBusy(err) || db === undefined)
355
- spoolSummary(hippoRoot, payload, text, at, errorMessage(err), result, log);
356
- else
357
- reportFailure(log, 'items step', errorMessage(err));
358
- }
359
- finally {
360
- if (db)
361
- closeHippoDb(db);
362
- }
52
+ const { result, spoolReason } = saveCompactionAt(hippoRoot, payload, text, at, log);
53
+ if (spoolReason !== null)
54
+ spoolSummary(hippoRoot, payload, text, at, spoolReason, result, log);
363
55
  return result;
364
56
  }
365
57
  /** The one line PostCompact prints, or null when nothing was saved. */
@@ -404,110 +96,21 @@ function transcriptSummary(transcriptPath, afterMs, beforeMs) {
404
96
  }
405
97
  return null;
406
98
  }
407
- function closeWithoutSummary(db, tenantId, id, log) {
408
- if (closeStartedWithoutSummary(db, tenantId, id) > 0)
409
- log(`${id} closed as no-summary: its transcript holds no summary for it`);
410
- }
411
- function nextStartedAt(db, record) {
412
- return nextCompactionStart(db, record.tenantId, record.sessionId, record.startedAt);
413
- }
414
- /** The one place a record becomes the argument saveItems takes. */
415
- function itemContext(tenantId, record, items = record.items) {
416
- return { tenantId, recordId: record.id, sessionId: record.sessionId, originProject: record.originProject, cwd: record.cwd, items };
417
- }
418
- /** Records a spooled summary, then writes its items. */
419
- function spoolImporter(db, hippoRoot, log) {
420
- return (spooled, recorded) => {
421
- const record = recordSummary(db, hippoRoot, spooled.tenantId, { meta: spooled.payload, text: spooled.text, at: spooled.at });
422
- // The record holds the items now, so the file is done even if the write below fails.
423
- recorded();
424
- saveItems(db, hippoRoot, itemContext(spooled.tenantId, record), log);
99
+ function replaySources(hippoRoot, log) {
100
+ return {
101
+ importSpool: (tenantId, deadline, record) => importSpool(hippoRoot, tenantId, log, deadline, record),
102
+ transcriptExists: (transcriptPath) => fs.existsSync(transcriptPath),
103
+ transcriptText: (transcriptPath, afterMs, beforeMs) => {
104
+ const found = transcriptSummary(transcriptPath, afterMs, beforeMs);
105
+ if (found === null)
106
+ return null;
107
+ const { found: listed, ...text } = readCompactionText(found);
108
+ return { text, listed };
109
+ },
425
110
  };
426
111
  }
427
- function replayStalled(db, hippoRoot, tenantId, now, log, deadline) {
428
- let finished = 0;
429
- const stalled = stalledSummarisedRows(db, tenantId, new Date(now - REPLAY_AFTER_MS).toISOString()).map(toRecord);
430
- for (const record of stalled) {
431
- if (Date.now() > deadline)
432
- break;
433
- try {
434
- saveItems(db, hippoRoot, itemContext(tenantId, record), log);
435
- finished++;
436
- }
437
- catch (err) {
438
- log(`replay of ${record.id} failed: ${errorMessage(err)}`);
439
- }
440
- }
441
- return finished;
442
- }
443
- function replaySpool(db, hippoRoot, tenantId, log, deadline) {
444
- try {
445
- return importSpool(hippoRoot, tenantId, log, deadline, spoolImporter(db, hippoRoot, log));
446
- }
447
- catch (err) {
448
- log(`spool import failed: ${errorMessage(err)}`);
449
- return 0;
450
- }
451
- }
452
- /** Fills one open record from its transcript; true when it saved items. */
453
- function fillFromTranscript(db, hippoRoot, tenantId, record, log) {
454
- if (record.transcriptPath === null || !fs.existsSync(record.transcriptPath))
455
- return false;
456
- const next = nextStartedAt(db, record);
457
- const found = transcriptSummary(record.transcriptPath, Date.parse(record.startedAt), next === null ? Number.POSITIVE_INFINITY : Date.parse(next));
458
- if (found === null) {
459
- // The record is past REPLAY_AFTER_MS, so a window that is fully scanned or out of reach stays empty.
460
- closeWithoutSummary(db, tenantId, record.id, log);
461
- return false;
462
- }
463
- const { found: listed, ...text } = readCompactionText(found);
464
- if (!listed)
465
- log(`no memories section in the transcript summary for ${record.id}`);
466
- if (!markSummarised(db, tenantId, record.id, { text, summarisedAt: new Date().toISOString() })) {
467
- log(`${record.id} was filled by another process`);
468
- return false;
469
- }
470
- saveItems(db, hippoRoot, itemContext(tenantId, record, text.items), log);
471
- return true;
472
- }
473
- function replayOpen(db, hippoRoot, tenantId, now, log, deadline) {
474
- let finished = 0;
475
- const open = openTranscriptRows(db, tenantId, new Date(now - REPLAY_AFTER_MS).toISOString(), new Date(now - TRANSCRIPT_FILL_WINDOW_MS).toISOString()).map(toRecord);
476
- for (const record of open) {
477
- if (Date.now() > deadline)
478
- break;
479
- try {
480
- if (fillFromTranscript(db, hippoRoot, tenantId, record, log))
481
- finished++;
482
- }
483
- catch (err) {
484
- log(`transcript fill of ${record.id} failed: ${errorMessage(err)}`);
485
- }
486
- }
487
- return finished;
488
- }
489
- /** Finishes what a killed hook or a busy store left: `summarised` records, spool files, and `started` records the transcript can fill. Returns how many compactions it saved. */
490
- export function replayCompactions(db, hippoRoot, log, deadline = Number.POSITIVE_INFINITY) {
491
- const tenantId = resolveTenantId({});
492
- const now = Date.now();
493
- return replayStalled(db, hippoRoot, tenantId, now, log, deadline)
494
- + replaySpool(db, hippoRoot, tenantId, log, deadline)
495
- + replayOpen(db, hippoRoot, tenantId, now, log, deadline);
496
- }
497
- /** For `hippo sleep` and post-compact: opens the store itself and never throws. */
112
+ /** For `hippo sleep` and post-compact: finishes what a killed hook or a busy store left, never throws. */
498
113
  export function replayCompactionsAt(hippoRoot, log, opts = {}) {
499
- let db;
500
- try {
501
- db = openHippoDb(hippoRoot, { busyWaitMs: opts.busyWaitMs });
502
- return replayCompactions(db, hippoRoot, log, opts.deadline);
503
- }
504
- catch (err) {
505
- log(`replay failed: ${errorMessage(err)}`);
506
- return 0;
507
- }
508
- finally {
509
- if (db)
510
- closeHippoDb(db);
511
- }
114
+ return replayStoredCompactions(hippoRoot, replaySources(hippoRoot, log), log, opts);
512
115
  }
513
116
  //# sourceMappingURL=compaction-record.js.map
@@ -1,6 +1,8 @@
1
- import type { CompactionText, Log, PostCompactPayload } from './compaction-record.js';
1
+ import type { CompactionText, Log } from '../store/compactions-record.js';
2
+ import type { PostCompactPayload } from './compaction-record.js';
2
3
  export declare const SPOOL_DIR = "compactions-spool";
3
- /** Starts the log line of a step that broke with an unexpected error, so the session-start banner counts it; a set-aside file is counted by its `.bad` name instead. */
4
+ /** Starts the log line of a step that broke with an unexpected error, so the session-start banner counts it; a set-aside file is counted
5
+ * by its `.bad` name instead. */
4
6
  export declare const SPOOL_PROBLEM = "spool problem: ";
5
7
  /** Only the fs calls the spool makes, so a test can stand in for one of them. */
6
8
  export interface SpoolFs {
@@ -20,8 +22,6 @@ export interface SpoolFs {
20
22
  flag?: 'wx';
21
23
  }): void;
22
24
  }
23
- /** Test-only seam, so a test can make one fs call fail; null restores the real fs. */
24
- export declare function _setSpoolFsForTests(next: SpoolFs | null): void;
25
25
  export interface SpooledCompaction {
26
26
  tenantId: string;
27
27
  payload: PostCompactPayload;
@@ -30,7 +30,7 @@ export interface SpooledCompaction {
30
30
  }
31
31
  /** Records one spooled compaction; it calls `recorded` once the store holds the summary, so the file is done even if a later step throws. */
32
32
  export type SpoolImporter = (spooled: SpooledCompaction, recorded: () => void) => void;
33
- export declare function spool(hippoRoot: string, tenantId: string, payload: PostCompactPayload, text: CompactionText, at: Date): void;
33
+ export declare function spool(hippoRoot: string, tenantId: string, payload: PostCompactPayload, text: CompactionText, at: Date, fsx?: SpoolFs): void;
34
34
  /** null when the text is not a spooled compaction. */
35
35
  export declare function parseSpooled(text: string, fallbackTenantId: string): SpooledCompaction | null;
36
36
  export interface SpoolCounts {
@@ -39,7 +39,7 @@ export interface SpoolCounts {
39
39
  bad: number;
40
40
  }
41
41
  /** What doctor reports, read only: files a replay should have taken by now, claims and tmp files a dead process left, and `.bad` files. */
42
- export declare function spoolCounts(hippoRoot: string, now: Date, waitingAfterMs: number): SpoolCounts;
42
+ export declare function spoolCounts(hippoRoot: string, now: Date, waitingAfterMs: number, fsx?: SpoolFs): SpoolCounts;
43
43
  /** One replayer at a time holds `replay.lock`, so only one process claims a file even where Windows lets two renames of it both land. */
44
- export declare function importSpool(hippoRoot: string, tenantId: string, log: Log, deadline: number, importOne: SpoolImporter): number;
44
+ export declare function importSpool(hippoRoot: string, tenantId: string, log: Log, deadline: number, importOne: SpoolImporter, fsx?: SpoolFs): number;
45
45
  //# sourceMappingURL=compaction-spool.d.ts.map