hippo-memory 1.59.0 → 1.61.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 (596) hide show
  1. package/README.md +1 -1
  2. package/dist/ablation.js +9 -27
  3. package/dist/agent-memories/apply.js +4 -1
  4. package/dist/agent-memories/claude-code.js +1 -1
  5. package/dist/agent-memories/codex.js +1 -1
  6. package/dist/agent-memories/gemini.js +1 -1
  7. package/dist/agent-memories/legacy.js +1 -1
  8. package/dist/agent-memories/source.js +1 -1
  9. package/dist/agent-memories/sync.js +8 -3
  10. package/dist/ambient-store.d.ts +14 -0
  11. package/dist/ambient-store.js +90 -0
  12. package/dist/ambient.d.ts +23 -0
  13. package/dist/ambient.js +72 -50
  14. package/dist/api/assemble.d.ts +93 -0
  15. package/dist/api/assemble.js +152 -0
  16. package/dist/api/audit.d.ts +17 -0
  17. package/dist/api/audit.js +23 -0
  18. package/dist/api/auth.d.ts +79 -0
  19. package/dist/api/auth.js +178 -0
  20. package/dist/api/context-types.d.ts +105 -0
  21. package/dist/api/context-types.js +3 -0
  22. package/dist/api/context.d.ts +31 -0
  23. package/dist/api/context.js +705 -0
  24. package/dist/api/dormant.d.ts +30 -0
  25. package/dist/api/dormant.js +140 -0
  26. package/dist/api/drill-down.d.ts +84 -0
  27. package/dist/api/drill-down.js +123 -0
  28. package/dist/api/forget.d.ts +57 -0
  29. package/dist/api/forget.js +87 -0
  30. package/dist/api/goals.d.ts +18 -0
  31. package/dist/api/goals.js +33 -0
  32. package/dist/api/learn.d.ts +31 -0
  33. package/dist/api/learn.js +88 -0
  34. package/dist/api/outcome.d.ts +61 -0
  35. package/dist/api/outcome.js +66 -0
  36. package/dist/api/promote.d.ts +54 -0
  37. package/dist/api/promote.js +203 -0
  38. package/dist/api/quarantine.d.ts +24 -0
  39. package/dist/api/quarantine.js +121 -0
  40. package/dist/api/recall-types.d.ts +390 -0
  41. package/dist/api/recall-types.js +3 -0
  42. package/dist/api/recall.d.ts +36 -0
  43. package/dist/api/recall.js +634 -0
  44. package/dist/api/remember.d.ts +35 -0
  45. package/dist/api/remember.js +43 -0
  46. package/dist/api/sleep.d.ts +136 -0
  47. package/dist/api/sleep.js +271 -0
  48. package/dist/api/tokens.d.ts +26 -0
  49. package/dist/api/tokens.js +60 -0
  50. package/dist/api/types.d.ts +56 -0
  51. package/dist/api/types.js +38 -0
  52. package/dist/api.d.ts +20 -1260
  53. package/dist/api.js +25 -2711
  54. package/dist/audit.d.ts +3 -0
  55. package/dist/audit.js +7 -3
  56. package/dist/auth.d.ts +45 -4
  57. package/dist/auth.js +125 -48
  58. package/dist/autolearn.js +7 -4
  59. package/dist/capture/command.d.ts +33 -0
  60. package/dist/capture/command.js +264 -0
  61. package/dist/capture/compact.d.ts +44 -0
  62. package/dist/capture/compact.js +354 -0
  63. package/dist/capture/extract.d.ts +21 -0
  64. package/dist/capture/extract.js +464 -0
  65. package/dist/capture/transcript.d.ts +40 -0
  66. package/dist/capture/transcript.js +193 -0
  67. package/dist/capture-error.js +2 -1
  68. package/dist/churn-git.js +4 -2
  69. package/dist/cli/audit.d.ts +3 -0
  70. package/dist/cli/audit.js +159 -0
  71. package/dist/cli/auth.d.ts +2 -0
  72. package/dist/cli/auth.js +171 -0
  73. package/dist/cli/briefs.d.ts +4 -0
  74. package/dist/cli/briefs.js +435 -0
  75. package/dist/cli/card.d.ts +3 -0
  76. package/dist/cli/card.js +333 -0
  77. package/dist/cli/context.d.ts +15 -0
  78. package/dist/cli/context.js +366 -0
  79. package/dist/cli/continuity.d.ts +6 -0
  80. package/dist/cli/continuity.js +445 -0
  81. package/dist/cli/curate.d.ts +19 -0
  82. package/dist/cli/curate.js +555 -0
  83. package/dist/cli/dag.d.ts +5 -0
  84. package/dist/cli/dag.js +177 -0
  85. package/dist/cli/decisions.d.ts +4 -0
  86. package/dist/cli/decisions.js +528 -0
  87. package/dist/cli/eval.d.ts +5 -0
  88. package/dist/cli/eval.js +213 -0
  89. package/dist/cli/explain.d.ts +4 -0
  90. package/dist/cli/explain.js +150 -0
  91. package/dist/cli/goals.d.ts +2 -0
  92. package/dist/cli/goals.js +196 -0
  93. package/dist/cli/hook-blocks.d.ts +18 -0
  94. package/dist/cli/hook-blocks.js +233 -0
  95. package/dist/cli/init.d.ts +2 -0
  96. package/dist/cli/init.js +305 -0
  97. package/dist/cli/maintenance.d.ts +4 -0
  98. package/dist/cli/maintenance.js +179 -0
  99. package/dist/cli/playbooks.d.ts +4 -0
  100. package/dist/cli/playbooks.js +556 -0
  101. package/dist/cli/projects.js +1 -1
  102. package/dist/cli/recall.d.ts +7 -0
  103. package/dist/cli/recall.js +597 -0
  104. package/dist/cli/remember.d.ts +5 -0
  105. package/dist/cli/remember.js +442 -0
  106. package/dist/cli/serve.d.ts +5 -0
  107. package/dist/cli/serve.js +40 -0
  108. package/dist/cli/session-hooks.d.ts +29 -0
  109. package/dist/cli/session-hooks.js +637 -0
  110. package/dist/cli/setup.d.ts +4 -0
  111. package/dist/cli/setup.js +376 -0
  112. package/dist/cli/shared.d.ts +15 -19
  113. package/dist/cli/shared.js +50 -341
  114. package/dist/cli/slack.d.ts +2 -0
  115. package/dist/cli/slack.js +171 -0
  116. package/dist/cli/status.d.ts +18 -0
  117. package/dist/cli/status.js +400 -0
  118. package/dist/cli/transfer.d.ts +10 -0
  119. package/dist/cli/transfer.js +438 -0
  120. package/dist/cli/usage.d.ts +85 -0
  121. package/dist/cli/usage.js +741 -0
  122. package/dist/cli.d.ts +319 -13
  123. package/dist/cli.js +436 -8580
  124. package/dist/client.js +15 -8
  125. package/dist/compaction-record.js +12 -9
  126. package/dist/config.js +12 -11
  127. package/dist/connectors/github/backfill.js +94 -87
  128. package/dist/connectors/github/cli-impl.js +5 -3
  129. package/dist/connectors/github/dlq.js +67 -54
  130. package/dist/connectors/github/ingest.js +34 -35
  131. package/dist/connectors/github/tenant-routing.js +3 -2
  132. package/dist/connectors/github/webhook.js +135 -216
  133. package/dist/connectors/slack/dlq.js +49 -61
  134. package/dist/connectors/slack/ingest.js +55 -48
  135. package/dist/connectors/slack/tenant-routing.js +4 -3
  136. package/dist/connectors/slack/webhook.js +72 -74
  137. package/dist/consolidate/conflicts.d.ts +10 -0
  138. package/dist/consolidate/conflicts.js +178 -0
  139. package/dist/consolidate/decay.d.ts +12 -0
  140. package/dist/consolidate/decay.js +145 -0
  141. package/dist/consolidate/llm-passes.d.ts +3 -0
  142. package/dist/consolidate/llm-passes.js +141 -0
  143. package/dist/consolidate/merge.d.ts +7 -0
  144. package/dist/consolidate/merge.js +251 -0
  145. package/dist/consolidate/physics-pass.d.ts +3 -0
  146. package/dist/consolidate/physics-pass.js +60 -0
  147. package/dist/consolidate/run.d.ts +69 -0
  148. package/dist/consolidate/run.js +76 -0
  149. package/dist/consolidate/sleep.d.ts +18 -0
  150. package/dist/consolidate/sleep.js +209 -0
  151. package/dist/consolidate/traces.d.ts +4 -0
  152. package/dist/consolidate/traces.js +178 -0
  153. package/dist/context-auto.js +7 -11
  154. package/dist/context-render.d.ts +1 -1
  155. package/dist/context-render.js +1 -1
  156. package/dist/customer-notes.d.ts +3 -0
  157. package/dist/customer-notes.js +6 -4
  158. package/dist/dag.js +13 -12
  159. package/dist/dashboard-actions.d.ts +20 -0
  160. package/dist/dashboard-actions.js +88 -0
  161. package/dist/dashboard-params.d.ts +45 -0
  162. package/dist/dashboard-params.js +127 -0
  163. package/dist/dashboard-queries.d.ts +15 -0
  164. package/dist/dashboard-queries.js +355 -0
  165. package/dist/dashboard-snapshot.d.ts +138 -0
  166. package/dist/dashboard-snapshot.js +308 -0
  167. package/dist/dashboard-types.d.ts +163 -0
  168. package/dist/dashboard-types.js +3 -0
  169. package/dist/dashboard.d.ts +6 -7
  170. package/dist/dashboard.js +231 -203
  171. package/dist/db/busy.d.ts +5 -0
  172. package/dist/db/busy.js +24 -0
  173. package/dist/db/continuity.d.ts +5 -0
  174. package/dist/db/continuity.js +145 -0
  175. package/dist/db/meta.d.ts +8 -0
  176. package/dist/db/meta.js +35 -0
  177. package/dist/db/migrate.d.ts +9 -0
  178. package/dist/db/migrate.js +138 -0
  179. package/dist/db/migrations/index.d.ts +5 -0
  180. package/dist/db/migrations/index.js +109 -0
  181. package/dist/db/migrations/types.d.ts +14 -0
  182. package/dist/db/migrations/types.js +2 -0
  183. package/dist/db/migrations/v01.d.ts +3 -0
  184. package/dist/db/migrations/v01.js +38 -0
  185. package/dist/db/migrations/v02.d.ts +3 -0
  186. package/dist/db/migrations/v02.js +21 -0
  187. package/dist/db/migrations/v03.d.ts +3 -0
  188. package/dist/db/migrations/v03.js +22 -0
  189. package/dist/db/migrations/v04.d.ts +3 -0
  190. package/dist/db/migrations/v04.js +28 -0
  191. package/dist/db/migrations/v05.d.ts +3 -0
  192. package/dist/db/migrations/v05.js +21 -0
  193. package/dist/db/migrations/v06.d.ts +3 -0
  194. package/dist/db/migrations/v06.js +25 -0
  195. package/dist/db/migrations/v07.d.ts +3 -0
  196. package/dist/db/migrations/v07.js +13 -0
  197. package/dist/db/migrations/v08.d.ts +3 -0
  198. package/dist/db/migrations/v08.js +8 -0
  199. package/dist/db/migrations/v09.d.ts +3 -0
  200. package/dist/db/migrations/v09.js +13 -0
  201. package/dist/db/migrations/v10.d.ts +3 -0
  202. package/dist/db/migrations/v10.js +17 -0
  203. package/dist/db/migrations/v11.d.ts +3 -0
  204. package/dist/db/migrations/v11.js +15 -0
  205. package/dist/db/migrations/v12.d.ts +3 -0
  206. package/dist/db/migrations/v12.js +11 -0
  207. package/dist/db/migrations/v13.d.ts +3 -0
  208. package/dist/db/migrations/v13.js +15 -0
  209. package/dist/db/migrations/v14.d.ts +3 -0
  210. package/dist/db/migrations/v14.js +66 -0
  211. package/dist/db/migrations/v15.d.ts +3 -0
  212. package/dist/db/migrations/v15.js +42 -0
  213. package/dist/db/migrations/v16.d.ts +3 -0
  214. package/dist/db/migrations/v16.js +61 -0
  215. package/dist/db/migrations/v17.d.ts +3 -0
  216. package/dist/db/migrations/v17.js +46 -0
  217. package/dist/db/migrations/v18.d.ts +3 -0
  218. package/dist/db/migrations/v18.js +60 -0
  219. package/dist/db/migrations/v19.d.ts +3 -0
  220. package/dist/db/migrations/v19.js +28 -0
  221. package/dist/db/migrations/v20.d.ts +3 -0
  222. package/dist/db/migrations/v20.js +42 -0
  223. package/dist/db/migrations/v21.d.ts +3 -0
  224. package/dist/db/migrations/v21.js +16 -0
  225. package/dist/db/migrations/v22.d.ts +3 -0
  226. package/dist/db/migrations/v22.js +82 -0
  227. package/dist/db/migrations/v23.d.ts +3 -0
  228. package/dist/db/migrations/v23.js +48 -0
  229. package/dist/db/migrations/v24.d.ts +3 -0
  230. package/dist/db/migrations/v24.js +72 -0
  231. package/dist/db/migrations/v25.d.ts +3 -0
  232. package/dist/db/migrations/v25.js +46 -0
  233. package/dist/db/migrations/v26.d.ts +3 -0
  234. package/dist/db/migrations/v26.js +23 -0
  235. package/dist/db/migrations/v27.d.ts +3 -0
  236. package/dist/db/migrations/v27.js +57 -0
  237. package/dist/db/migrations/v28.d.ts +3 -0
  238. package/dist/db/migrations/v28.js +38 -0
  239. package/dist/db/migrations/v29.d.ts +3 -0
  240. package/dist/db/migrations/v29.js +78 -0
  241. package/dist/db/migrations/v30.d.ts +3 -0
  242. package/dist/db/migrations/v30.js +92 -0
  243. package/dist/db/migrations/v31.d.ts +3 -0
  244. package/dist/db/migrations/v31.js +74 -0
  245. package/dist/db/migrations/v32.d.ts +3 -0
  246. package/dist/db/migrations/v32.js +102 -0
  247. package/dist/db/migrations/v33.d.ts +3 -0
  248. package/dist/db/migrations/v33.js +104 -0
  249. package/dist/db/migrations/v34.d.ts +3 -0
  250. package/dist/db/migrations/v34.js +93 -0
  251. package/dist/db/migrations/v35.d.ts +3 -0
  252. package/dist/db/migrations/v35.js +98 -0
  253. package/dist/db/migrations/v36.d.ts +3 -0
  254. package/dist/db/migrations/v36.js +98 -0
  255. package/dist/db/migrations/v37.d.ts +3 -0
  256. package/dist/db/migrations/v37.js +219 -0
  257. package/dist/db/migrations/v38.d.ts +3 -0
  258. package/dist/db/migrations/v38.js +277 -0
  259. package/dist/db/migrations/v39.d.ts +3 -0
  260. package/dist/db/migrations/v39.js +59 -0
  261. package/dist/db/migrations/v40.d.ts +3 -0
  262. package/dist/db/migrations/v40.js +74 -0
  263. package/dist/db/migrations/v41.d.ts +3 -0
  264. package/dist/db/migrations/v41.js +43 -0
  265. package/dist/db/migrations/v42.d.ts +3 -0
  266. package/dist/db/migrations/v42.js +41 -0
  267. package/dist/db/migrations/v43.d.ts +3 -0
  268. package/dist/db/migrations/v43.js +67 -0
  269. package/dist/db/migrations/v44.d.ts +3 -0
  270. package/dist/db/migrations/v44.js +28 -0
  271. package/dist/db/migrations/v45.d.ts +3 -0
  272. package/dist/db/migrations/v45.js +30 -0
  273. package/dist/db/migrations/v46.d.ts +3 -0
  274. package/dist/db/migrations/v46.js +25 -0
  275. package/dist/db/migrations/v47.d.ts +3 -0
  276. package/dist/db/migrations/v47.js +17 -0
  277. package/dist/db/migrations/v48.d.ts +3 -0
  278. package/dist/db/migrations/v48.js +10 -0
  279. package/dist/db/migrations/v49.d.ts +3 -0
  280. package/dist/db/migrations/v49.js +31 -0
  281. package/dist/db/migrations/v50.d.ts +3 -0
  282. package/dist/db/migrations/v50.js +67 -0
  283. package/dist/db/migrations/v51.d.ts +3 -0
  284. package/dist/db/migrations/v51.js +14 -0
  285. package/dist/db/migrations/v52.d.ts +3 -0
  286. package/dist/db/migrations/v52.js +7 -0
  287. package/dist/db/open.d.ts +23 -0
  288. package/dist/db/open.js +146 -0
  289. package/dist/db/sqlite.d.ts +21 -0
  290. package/dist/db/sqlite.js +8 -0
  291. package/dist/db/tables.d.ts +7 -0
  292. package/dist/db/tables.js +38 -0
  293. package/dist/db.d.ts +6 -46
  294. package/dist/db.js +5 -3036
  295. package/dist/decisions.d.ts +4 -1
  296. package/dist/decisions.js +9 -7
  297. package/dist/dedupe.js +3 -2
  298. package/dist/delivery-recorder.js +5 -1
  299. package/dist/doctor.js +4 -3
  300. package/dist/dormant.js +1 -0
  301. package/dist/embedding-provider.d.ts +1 -1
  302. package/dist/embedding-provider.js +7 -5
  303. package/dist/embeddings.d.ts +9 -52
  304. package/dist/embeddings.js +47 -298
  305. package/dist/env.d.ts +75 -0
  306. package/dist/env.js +119 -0
  307. package/dist/eval-suite.js +1 -1
  308. package/dist/eval.js +2 -2
  309. package/dist/extract.js +5 -4
  310. package/dist/gated-write.js +3 -1
  311. package/dist/goals.d.ts +3 -1
  312. package/dist/goals.js +18 -0
  313. package/dist/graph/read.d.ts +73 -0
  314. package/dist/graph/read.js +325 -0
  315. package/dist/graph/rows.d.ts +45 -0
  316. package/dist/graph/rows.js +51 -0
  317. package/dist/graph/types.d.ts +83 -0
  318. package/dist/graph/types.js +11 -0
  319. package/dist/graph/write.d.ts +93 -0
  320. package/dist/{graph.js → graph/write.js} +8 -391
  321. package/dist/graph-extract.js +2 -1
  322. package/dist/graph-recall.d.ts +1 -1
  323. package/dist/graph-recall.js +2 -2
  324. package/dist/graph-stream.js +1 -1
  325. package/dist/graph-view.d.ts +1 -1
  326. package/dist/graph-view.js +1 -1
  327. package/dist/half-life-migration.d.ts +1 -1
  328. package/dist/half-life-migration.js +2 -1
  329. package/dist/handoff.js +3 -0
  330. package/dist/hooks/codex-session.d.ts +8 -0
  331. package/dist/hooks/codex-session.js +76 -0
  332. package/dist/hooks/codex-wrapper.d.ts +55 -0
  333. package/dist/hooks/codex-wrapper.js +288 -0
  334. package/dist/hooks/json-hooks.d.ts +63 -0
  335. package/dist/hooks/json-hooks.js +356 -0
  336. package/dist/hooks/opencode.d.ts +50 -0
  337. package/dist/hooks/opencode.js +202 -0
  338. package/dist/hooks/shared.d.ts +54 -0
  339. package/dist/hooks/shared.js +77 -0
  340. package/dist/http-retry.d.ts +2 -0
  341. package/dist/http-retry.js +4 -3
  342. package/dist/http-util.d.ts +3 -0
  343. package/dist/http-util.js +10 -0
  344. package/dist/{importers.d.ts → importers/core.d.ts} +13 -17
  345. package/dist/importers/core.js +141 -0
  346. package/dist/importers/markdown-parse.d.ts +41 -0
  347. package/dist/importers/markdown-parse.js +132 -0
  348. package/dist/importers/markdown.d.ts +3 -0
  349. package/dist/importers/markdown.js +92 -0
  350. package/dist/importers/sources.d.ts +7 -0
  351. package/dist/importers/sources.js +229 -0
  352. package/dist/importers/vault.d.ts +11 -0
  353. package/dist/importers/vault.js +352 -0
  354. package/dist/incidents.d.ts +3 -0
  355. package/dist/incidents.js +8 -5
  356. package/dist/index.d.ts +25 -6
  357. package/dist/index.js +23 -6
  358. package/dist/invalidation.js +2 -1
  359. package/dist/judgment.js +7 -3
  360. package/dist/keyset.d.ts +13 -0
  361. package/dist/keyset.js +8 -0
  362. package/dist/local-embedding.d.ts +13 -0
  363. package/dist/local-embedding.js +165 -0
  364. package/dist/log.d.ts +7 -0
  365. package/dist/log.js +19 -1
  366. package/dist/mcp/admin-tools.d.ts +8 -0
  367. package/dist/mcp/admin-tools.js +116 -0
  368. package/dist/mcp/format.d.ts +27 -0
  369. package/dist/mcp/format.js +135 -0
  370. package/dist/mcp/memory-tools.d.ts +5 -0
  371. package/dist/mcp/memory-tools.js +83 -0
  372. package/dist/mcp/protocol.d.ts +83 -0
  373. package/dist/mcp/protocol.js +55 -0
  374. package/dist/mcp/recall-tools.d.ts +6 -0
  375. package/dist/mcp/recall-tools.js +320 -0
  376. package/dist/mcp/request.d.ts +10 -0
  377. package/dist/mcp/request.js +163 -0
  378. package/dist/mcp/server.d.ts +4 -70
  379. package/dist/mcp/server.js +8 -1172
  380. package/dist/mcp/session-state.d.ts +11 -0
  381. package/dist/mcp/session-state.js +28 -0
  382. package/dist/mcp/stdio.d.ts +8 -0
  383. package/dist/mcp/stdio.js +79 -0
  384. package/dist/mcp/tools.d.ts +11 -0
  385. package/dist/mcp/tools.js +247 -0
  386. package/dist/memory.d.ts +8 -3
  387. package/dist/memory.js +27 -1
  388. package/dist/multihop.d.ts +1 -1
  389. package/dist/multihop.js +2 -1
  390. package/dist/owner-validation.js +2 -1
  391. package/dist/physics-state.js +10 -7
  392. package/dist/policies.d.ts +3 -0
  393. package/dist/policies.js +8 -6
  394. package/dist/postinstall.js +3 -2
  395. package/dist/predictions/planning-fallacy.d.ts +100 -0
  396. package/dist/predictions/planning-fallacy.js +190 -0
  397. package/dist/{predictions.d.ts → predictions/store.d.ts} +7 -102
  398. package/dist/predictions/store.js +434 -0
  399. package/dist/processes.d.ts +3 -0
  400. package/dist/processes.js +8 -5
  401. package/dist/project-briefs.d.ts +3 -0
  402. package/dist/project-briefs.js +7 -5
  403. package/dist/project-identity.d.ts +1 -1
  404. package/dist/project-identity.js +12 -6
  405. package/dist/project-merge.js +3 -1
  406. package/dist/quarantine.d.ts +2 -1
  407. package/dist/quarantine.js +8 -5
  408. package/dist/raw-archive-mirror-cleanup.js +2 -1
  409. package/dist/raw-archive.js +1 -1
  410. package/dist/recall-history.js +3 -2
  411. package/dist/recall-pipeline.d.ts +2 -2
  412. package/dist/recall-pipeline.js +16 -8
  413. package/dist/recall-scope.js +1 -1
  414. package/dist/recall-trace.d.ts +3 -3
  415. package/dist/recall-trace.js +10 -14
  416. package/dist/refine-llm.js +20 -11
  417. package/dist/reject-flow.js +6 -1
  418. package/dist/rerankers/clef.d.ts +2 -2
  419. package/dist/rerankers/clef.js +72 -30
  420. package/dist/rerankers/cross-encoder.js +6 -4
  421. package/dist/rerankers/jev.d.ts +4 -2
  422. package/dist/rerankers/jev.js +24 -19
  423. package/dist/rerankers/llm.d.ts +4 -2
  424. package/dist/rerankers/llm.js +61 -41
  425. package/dist/rerankers/types.d.ts +1 -1
  426. package/dist/salience.js +1 -1
  427. package/dist/same-text.d.ts +2 -0
  428. package/dist/same-text.js +4 -0
  429. package/dist/scheduler.d.ts +1 -0
  430. package/dist/scheduler.js +26 -3
  431. package/dist/scope.js +4 -3
  432. package/dist/search/as-of.d.ts +10 -0
  433. package/dist/search/as-of.js +22 -0
  434. package/dist/search/bm25-search.d.ts +14 -0
  435. package/dist/search/bm25-search.js +43 -0
  436. package/dist/search/bm25.d.ts +15 -0
  437. package/dist/search/bm25.js +54 -0
  438. package/dist/search/boosts.d.ts +54 -0
  439. package/dist/search/boosts.js +94 -0
  440. package/dist/search/breakdown.d.ts +7 -0
  441. package/dist/search/breakdown.js +20 -0
  442. package/dist/search/explain.d.ts +25 -0
  443. package/dist/search/explain.js +31 -0
  444. package/dist/search/finalize.d.ts +8 -0
  445. package/dist/search/finalize.js +52 -0
  446. package/dist/search/fusion.d.ts +27 -0
  447. package/dist/search/fusion.js +42 -0
  448. package/dist/search/hybrid-score.d.ts +20 -0
  449. package/dist/search/hybrid-score.js +73 -0
  450. package/dist/search/hybrid.d.ts +46 -0
  451. package/dist/search/hybrid.js +64 -0
  452. package/dist/search/physics-search.d.ts +29 -0
  453. package/dist/search/physics-search.js +162 -0
  454. package/dist/search/rerank.d.ts +10 -0
  455. package/dist/search/rerank.js +72 -0
  456. package/dist/search/temporal.d.ts +15 -0
  457. package/dist/search/temporal.js +45 -0
  458. package/dist/search/types.d.ts +91 -0
  459. package/dist/search/types.js +2 -0
  460. package/dist/search/vector.d.ts +30 -0
  461. package/dist/search/vector.js +71 -0
  462. package/dist/secret-detect.d.ts +2 -0
  463. package/dist/secret-detect.js +3 -1
  464. package/dist/server/auth.d.ts +52 -0
  465. package/dist/server/auth.js +221 -0
  466. package/dist/server/client-ip.d.ts +25 -0
  467. package/dist/server/client-ip.js +92 -0
  468. package/dist/server/cursor.d.ts +23 -0
  469. package/dist/server/cursor.js +58 -0
  470. package/dist/server/lifecycle.d.ts +7 -0
  471. package/dist/server/lifecycle.js +29 -0
  472. package/dist/server/mcp-http.d.ts +5 -0
  473. package/dist/server/mcp-http.js +199 -0
  474. package/dist/server/request.d.ts +33 -0
  475. package/dist/server/request.js +103 -0
  476. package/dist/server/routes/admin.d.ts +9 -0
  477. package/dist/server/routes/admin.js +158 -0
  478. package/dist/server/routes/customer-notes.d.ts +7 -0
  479. package/dist/server/routes/customer-notes.js +112 -0
  480. package/dist/server/routes/decisions.d.ts +7 -0
  481. package/dist/server/routes/decisions.js +133 -0
  482. package/dist/server/routes/incidents.d.ts +7 -0
  483. package/dist/server/routes/incidents.js +126 -0
  484. package/dist/server/routes/memories.d.ts +10 -0
  485. package/dist/server/routes/memories.js +179 -0
  486. package/dist/server/routes/policies.d.ts +8 -0
  487. package/dist/server/routes/policies.js +151 -0
  488. package/dist/server/routes/predictions.d.ts +7 -0
  489. package/dist/server/routes/predictions.js +164 -0
  490. package/dist/server/routes/processes.d.ts +7 -0
  491. package/dist/server/routes/processes.js +161 -0
  492. package/dist/server/routes/project-briefs.d.ts +8 -0
  493. package/dist/server/routes/project-briefs.js +136 -0
  494. package/dist/server/routes/recall.d.ts +8 -0
  495. package/dist/server/routes/recall.js +340 -0
  496. package/dist/server/routes/skills.d.ts +8 -0
  497. package/dist/server/routes/skills.js +150 -0
  498. package/dist/server/types.d.ts +56 -0
  499. package/dist/server/types.js +2 -0
  500. package/dist/server/validation.d.ts +14 -0
  501. package/dist/server/validation.js +91 -0
  502. package/dist/server.d.ts +7 -61
  503. package/dist/server.js +92 -2368
  504. package/dist/session-digest.d.ts +1 -1
  505. package/dist/session-digest.js +9 -2
  506. package/dist/shared.d.ts +3 -1
  507. package/dist/shared.js +46 -40
  508. package/dist/skills.d.ts +3 -0
  509. package/dist/skills.js +7 -5
  510. package/dist/stdin.js +3 -2
  511. package/dist/store/audit-event.d.ts +19 -0
  512. package/dist/store/audit-event.js +33 -0
  513. package/dist/store/candidates.d.ts +42 -0
  514. package/dist/store/candidates.js +152 -0
  515. package/dist/store/conflicts.d.ts +44 -0
  516. package/dist/store/conflicts.js +444 -0
  517. package/dist/store/delete-and-batch.d.ts +63 -0
  518. package/dist/store/delete-and-batch.js +310 -0
  519. package/dist/store/entry-reads.d.ts +92 -0
  520. package/dist/store/entry-reads.js +255 -0
  521. package/dist/store/entry-row.d.ts +67 -0
  522. package/dist/store/entry-row.js +208 -0
  523. package/dist/store/entry-writes.d.ts +46 -0
  524. package/dist/store/entry-writes.js +148 -0
  525. package/dist/store/handoffs.d.ts +26 -0
  526. package/dist/store/handoffs.js +184 -0
  527. package/dist/store/index-and-stats.d.ts +52 -0
  528. package/dist/store/index-and-stats.js +214 -0
  529. package/dist/store/markdown.d.ts +10 -0
  530. package/dist/store/markdown.js +108 -0
  531. package/dist/store/mirrors.d.ts +49 -0
  532. package/dist/store/mirrors.js +312 -0
  533. package/dist/store/open.d.ts +15 -0
  534. package/dist/store/open.js +223 -0
  535. package/dist/store/rows.d.ts +178 -0
  536. package/dist/store/rows.js +158 -0
  537. package/dist/store/search-rows.d.ts +86 -0
  538. package/dist/store/search-rows.js +254 -0
  539. package/dist/store/sessions.d.ts +83 -0
  540. package/dist/store/sessions.js +272 -0
  541. package/dist/store/summaries.d.ts +94 -0
  542. package/dist/store/summaries.js +377 -0
  543. package/dist/store/tenant-lookup.d.ts +12 -0
  544. package/dist/store/tenant-lookup.js +16 -0
  545. package/dist/store-cards.js +2 -1
  546. package/dist/summary-dirty.d.ts +4 -0
  547. package/dist/summary-dirty.js +32 -0
  548. package/dist/support-bundle.js +4 -3
  549. package/dist/tenant.js +2 -2
  550. package/dist/token-ledger.js +1 -0
  551. package/dist/tokenize.d.ts +2 -0
  552. package/dist/tokenize.js +16 -0
  553. package/dist/transcript-tail.d.ts +7 -0
  554. package/dist/transcript-tail.js +48 -0
  555. package/dist/vector-store.d.ts +27 -0
  556. package/dist/vector-store.js +210 -0
  557. package/dist/version.d.ts +2 -2
  558. package/dist/version.js +2 -2
  559. package/dist/working-memory.js +1 -1
  560. package/dist/yaml.js +36 -11
  561. package/dist-ui/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
  562. package/dist-ui/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
  563. package/dist-ui/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
  564. package/dist-ui/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
  565. package/dist-ui/assets/ibm-plex-mono-latin-600-normal-BgSNZQsw.woff2 +0 -0
  566. package/dist-ui/assets/ibm-plex-mono-latin-600-normal-DWFSQ4vo.woff +0 -0
  567. package/dist-ui/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
  568. package/dist-ui/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
  569. package/dist-ui/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
  570. package/dist-ui/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff +0 -0
  571. package/dist-ui/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
  572. package/dist-ui/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
  573. package/dist-ui/assets/index-DPN7cP19.js +33 -0
  574. package/dist-ui/assets/index-dFloKRVr.css +1 -0
  575. package/dist-ui/index.html +3 -25
  576. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  577. package/extensions/openclaw-plugin/package.json +1 -1
  578. package/openclaw.plugin.json +1 -1
  579. package/package.json +2 -1
  580. package/dist/capture.d.ts +0 -155
  581. package/dist/capture.js +0 -1293
  582. package/dist/consolidate.d.ts +0 -58
  583. package/dist/consolidate.js +0 -1123
  584. package/dist/graph.d.ts +0 -245
  585. package/dist/hooks.d.ts +0 -208
  586. package/dist/hooks.js +0 -1073
  587. package/dist/importers.js +0 -897
  588. package/dist/predictions.js +0 -620
  589. package/dist/search.d.ts +0 -320
  590. package/dist/search.js +0 -968
  591. package/dist/store.d.ts +0 -744
  592. package/dist/store.js +0 -3372
  593. package/dist-ui/assets/d3-BiWEKnn4.js +0 -1
  594. package/dist-ui/assets/index-BhT8RvO6.js +0 -61
  595. package/dist-ui/assets/index-RoXXJ5dq.css +0 -1
  596. package/dist-ui/assets/three-BDgTxR1l.js +0 -4112
@@ -0,0 +1,88 @@
1
+ // Git auto-learn: fix/revert/bug commit subjects become memories. `hippo learn`, init, sleep and MCP hippo_learn share it.
2
+ import { ForbiddenError } from '../api-errors.js';
3
+ import { fetchGitLog, extractLessons, partitionLessons, isGitRepo } from '../autolearn.js';
4
+ import { loadConfig } from '../config.js';
5
+ import { embedMemory } from '../embeddings.js';
6
+ import { extractInvalidationTarget, invalidateMatching } from '../invalidation.js';
7
+ import { computeSchemaFit, createMemory, Layer } from '../memory.js';
8
+ import { extractPathTags } from '../path-context.js';
9
+ import { RejectedValueError } from '../rejection.js';
10
+ import { duplicateKey, longestWord, storedTextKeys } from '../same-text.js';
11
+ import { loadTextsHoldingWords } from '../store/candidates.js';
12
+ import { loadAllEntries } from '../store/entry-reads.js';
13
+ import { writeEntry } from '../store/entry-writes.js';
14
+ import { updateStats } from '../store/index-and-stats.js';
15
+ // SHORTCUT: two profiles keep each surface's rows as they were; fold MCP onto the CLI profile once it may invalidate.
16
+ export const CLI_LEARN = Object.freeze({ tags: Object.freeze(['error', 'git-learned']), source: 'git-learn', full: true });
17
+ export const MCP_LEARN = Object.freeze({ tags: Object.freeze(['git-learned']), source: 'git', full: false });
18
+ /** Learn from `repoPath`'s last `days` of commits into the caller's tenant. Host admin only. */
19
+ export function learn(ctx, opts) {
20
+ // It reads the host's own git history, which belongs to the host, not to the caller's tenant.
21
+ if (!ctx.actor.hostAdmin)
22
+ throw new ForbiddenError('hippo_learn requires a host admin');
23
+ const none = { added: 0, skipped: 0, rejected: 0, lowInfo: 0, invalidations: [] };
24
+ if (!isGitRepo(opts.repoPath))
25
+ return { status: 'not-a-repo', ...none };
26
+ const gitLog = fetchGitLog(opts.repoPath, opts.days);
27
+ if (!gitLog.trim())
28
+ return { status: 'no-commits', ...none };
29
+ const config = loadConfig(ctx.hippoRoot);
30
+ const parsed = extractLessons(gitLog, config.gitLearnPatterns);
31
+ if (parsed.length === 0)
32
+ return { status: 'no-lessons', ...none };
33
+ // The gate filters the loop input, so a dropped lesson neither stores nor invalidates; docs/decisions git-learn-gate-placement says why.
34
+ const { kept, dropped } = partitionLessons(parsed);
35
+ return { status: 'scanned', lowInfo: dropped.length, ...writeLessons(ctx, kept, opts, config) };
36
+ }
37
+ function writeLessons(ctx, lessons, opts, config) {
38
+ const { hippoRoot, tenantId } = ctx;
39
+ const { profile } = opts;
40
+ // Schema fit needs every row; without it, only rows holding a lesson's longest word can be its copy.
41
+ const existing = profile.full ? loadAllEntries(hippoRoot, tenantId) : undefined;
42
+ const keys = storedTextKeys(existing ?? loadTextsHoldingWords(hippoRoot, tenantId, lessons.map(longestWord)));
43
+ const pathTags = profile.full ? extractPathTags(opts.repoPath) : [];
44
+ const counts = { added: 0, skipped: 0, rejected: 0, invalidations: [] };
45
+ for (const lesson of lessons) {
46
+ if (keys.has(duplicateKey(lesson))) {
47
+ counts.skipped++;
48
+ continue;
49
+ }
50
+ const target = profile.full ? extractInvalidationTarget(lesson) : null;
51
+ if (target) {
52
+ const { invalidated } = invalidateMatching(hippoRoot, target, tenantId);
53
+ if (invalidated > 0)
54
+ counts.invalidations.push({ from: target.from, count: invalidated });
55
+ }
56
+ const entry = createMemory(lesson, {
57
+ layer: Layer.Episodic,
58
+ tags: [...profile.tags],
59
+ source: profile.source,
60
+ confidence: 'observed',
61
+ schema_fit: existing && computeSchemaFit(lesson, [...profile.tags], existing),
62
+ tenantId,
63
+ baseHalfLifeDays: config.defaultHalfLifeDays,
64
+ });
65
+ for (const tag of pathTags)
66
+ if (!entry.tags.includes(tag))
67
+ entry.tags.push(tag);
68
+ // A refused lesson must not abort the rest of the git-log scan.
69
+ try {
70
+ writeEntry(hippoRoot, entry, { actor: ctx.actor.subject });
71
+ }
72
+ catch (err) {
73
+ if (err instanceof RejectedValueError) {
74
+ counts.rejected++;
75
+ continue;
76
+ }
77
+ throw err;
78
+ }
79
+ if (profile.full)
80
+ updateStats(hippoRoot, { remembered: 1 });
81
+ keys.add(duplicateKey(lesson));
82
+ if (profile.full)
83
+ void embedMemory(hippoRoot, entry);
84
+ counts.added++;
85
+ }
86
+ return counts;
87
+ }
88
+ //# sourceMappingURL=learn.js.map
@@ -0,0 +1,61 @@
1
+ import type { Context } from './types.js';
2
+ /**
3
+ * Apply a positive/negative outcome to a list of recently-recalled memory ids.
4
+ * Used by the MCP `hippo_outcome` tool and the HTTP `POST /v1/outcome` route.
5
+ * Tenant-scoped: ids that don't belong to ctx.tenantId are silently skipped
6
+ * (matches the prior MCP semantics — a stale id from another tenant doesn't
7
+ * crash the call). Each successful outcome emits one audit_log row with
8
+ * op='outcome' tagged with ctx.actor.subject.
9
+ *
10
+ * Returns `{applied, appliedIds}`. `appliedIds` is the tenant-filtered subset
11
+ * of input ids that actually had `applyOutcome` run on them (i.e. ids whose
12
+ * `readEntry(..., ctx.tenantId)` resolved). Callers that surface the id list
13
+ * over a multi-tenant boundary (HTTP /v1/outcome last-recall path, Python SDK)
14
+ * MUST return `appliedIds` instead of the raw input list — otherwise the
15
+ * non-applied (cross-tenant) ids leak to the caller. Added in v1.11.4 to
16
+ * close that disclosure path on POST /v1/outcome.
17
+ *
18
+ * `opts.traceId` (LC1, docs/plans/2026-08-02-lc1-recall-trace-persistence.md):
19
+ * OPTIONAL additive opt so a programmatic caller can link this outcome to
20
+ * the recall_traces row it judges. NOT applied unconditionally — an SDK
21
+ * caller passing explicit ids with no preceding CLI/context recall would
22
+ * otherwise get linked to a stale, unrelated trace. `outcomeForLastRecall`
23
+ * supplies this automatically from `last_trace_id`; every other caller
24
+ * (server.ts explicit-ids path, MCP hippo_outcome) omits it and gets no
25
+ * linkage, which is correct.
26
+ */
27
+ export interface OutcomeResult {
28
+ applied: number;
29
+ appliedIds: string[];
30
+ }
31
+ export declare function outcome(ctx: Context, ids: ReadonlyArray<string>, good: boolean, opts?: {
32
+ traceId?: number;
33
+ }): OutcomeResult;
34
+ /**
35
+ * Apply an outcome to the ids most recently returned by `recall()`.
36
+ *
37
+ * Reads `loadIndex(ctx.hippoRoot).last_retrieval_ids` (per-hippoRoot local
38
+ * state; not tenant-scoped at the index layer) and forwards to `outcome()`,
39
+ * which DOES tenant-filter via `readEntry(..., ctx.tenantId)`. Cross-tenant
40
+ * ids in `last_retrieval_ids` are silently skipped, matching the MCP
41
+ * `hippo_outcome` semantics.
42
+ *
43
+ * **Tenant-safe response shape (v1.11.4 security fix):** the returned `ids`
44
+ * field contains ONLY the tenant-filtered subset that actually had outcomes
45
+ * applied (i.e. `appliedIds` from the inner `outcome()` call). Earlier
46
+ * versions returned the raw `last_retrieval_ids` regardless of tenant, which
47
+ * leaked cross-tenant memory IDs to the caller via POST /v1/outcome's
48
+ * no-body last-recall response. The fix is at this helper so all callers
49
+ * (CLI cmdOutcome, HTTP /v1/outcome, MCP `hippo_outcome` if added later)
50
+ * inherit the tenant-safe contract.
51
+ *
52
+ * Do NOT tighten `loadIndex` with `tenantId` inside this helper — doing so
53
+ * would break the (correct) cross-tenant-silent-skip behavior covered by
54
+ * the test in `tests/api-outcome-for-last-recall.test.ts`.
55
+ */
56
+ export interface OutcomeForLastRecallResult {
57
+ applied: number;
58
+ ids: string[];
59
+ }
60
+ export declare function outcomeForLastRecall(ctx: Context, good: boolean): OutcomeForLastRecallResult;
61
+ //# sourceMappingURL=outcome.d.ts.map
@@ -0,0 +1,66 @@
1
+ // Outcome feedback on recalled memories.
2
+ import { openHippoDb, closeHippoDb } from '../db.js';
3
+ import { writeEntry } from '../store/entry-writes.js';
4
+ import { readEntry } from '../store/entry-reads.js';
5
+ import { loadIndex } from '../store/index-and-stats.js';
6
+ import { applyOutcome, CHURN_STALE_TAG } from '../memory.js';
7
+ import { appendAuditEvent } from '../audit.js';
8
+ import { recordTraceOutcome } from '../recall-trace.js';
9
+ export function outcome(ctx, ids, good, opts) {
10
+ const appliedIds = [];
11
+ const db = openHippoDb(ctx.hippoRoot);
12
+ try {
13
+ for (const id of ids) {
14
+ const entry = readEntry(ctx.hippoRoot, id, ctx.tenantId);
15
+ if (!entry)
16
+ continue;
17
+ let updated = applyOutcome(entry, good);
18
+ if (good && updated.tags.includes(CHURN_STALE_TAG)) { // FE2: a good outcome reconfirms the entry
19
+ updated = { ...updated, tags: updated.tags.filter((t) => t !== CHURN_STALE_TAG) };
20
+ }
21
+ writeEntry(ctx.hippoRoot, updated, { actor: ctx.actor.subject });
22
+ appendAuditEvent(db, {
23
+ tenantId: ctx.tenantId,
24
+ actor: ctx.actor.subject,
25
+ op: 'outcome',
26
+ targetId: id,
27
+ metadata: { good },
28
+ });
29
+ appliedIds.push(id);
30
+ }
31
+ // LC1: link the outcome to its trace, recording only the ids actually
32
+ // credited (post tenant-filtering, matches appliedIds). Lives in its own
33
+ // append-only table so audit_log pruning can never erase training data.
34
+ if (opts?.traceId !== undefined && appliedIds.length > 0) {
35
+ recordTraceOutcome(db, {
36
+ traceId: opts.traceId,
37
+ tenantId: ctx.tenantId,
38
+ outcome: good ? 'positive' : 'negative',
39
+ memoryIds: appliedIds,
40
+ });
41
+ }
42
+ }
43
+ finally {
44
+ closeHippoDb(db);
45
+ }
46
+ return { applied: appliedIds.length, appliedIds };
47
+ }
48
+ export function outcomeForLastRecall(ctx, good) {
49
+ const idx = loadIndex(ctx.hippoRoot);
50
+ const ids = idx.last_retrieval_ids;
51
+ if (ids.length === 0)
52
+ return { applied: 0, ids: [] };
53
+ // LC1 F1(d) structural fix (docs/plans/2026-08-02-lc1-recall-trace-persistence.md):
54
+ // read the trace id from the SAME `loadIndex` snapshot already in hand
55
+ // (idx.last_trace_id) — a single-snapshot read, not a second DB round
56
+ // trip via a now-deleted readLastTraceId helper. The value is already
57
+ // strict-parsed by buildIndexFromDb's parseLastTraceId (store.ts): every
58
+ // consumer gets a clean positive-integer string or null, never a garbage
59
+ // value that could reach outcome() and INSERT trace_id=0/NaN. null on a
60
+ // fresh store / pre-v40 flow / api.recall-only usage — outcome() skips
61
+ // linkage silently when traceId is undefined.
62
+ const traceId = idx.last_trace_id !== null ? Number(idx.last_trace_id) : null;
63
+ const { applied, appliedIds } = outcome(ctx, ids, good, traceId !== null ? { traceId } : undefined);
64
+ return { applied, ids: appliedIds };
65
+ }
66
+ //# sourceMappingURL=outcome.js.map
@@ -0,0 +1,54 @@
1
+ import { type DatabaseSyncLike } from '../db.js';
2
+ import type { Context } from './types.js';
3
+ /**
4
+ * Copy a local memory into the global store. Mirrors `cmdPromote` in cli.ts:
5
+ * the `writeEntry` inside `promoteToGlobal` emits a 'remember' on the global
6
+ * db; we add a 'promote' audit event on the global db so the user-facing
7
+ * intent stays distinct from the underlying upsert.
8
+ *
9
+ * Note: `promoteToGlobal` does not currently take a tenantId override — it
10
+ * reads the entry from the local root via `readEntry` (no tenant filter) and
11
+ * preserves the entry's existing tenantId on the global side. Task 4 may
12
+ * tighten this once writeEntry/readEntry thread tenant context.
13
+ */
14
+ export interface PromoteResult {
15
+ ok: true;
16
+ sourceId: string;
17
+ globalId: string;
18
+ }
19
+ export declare function promote(ctx: Context, id: string): PromoteResult;
20
+ /**
21
+ * Replace an old memory with new content, chaining old.superseded_by = new.id.
22
+ * Mirrors `cmdSupersede` in cli.ts (without flag-driven layer/tag/pin overrides
23
+ * — A1 keeps the API minimal; the CLI handler will continue to handle those
24
+ * flags and pass the resolved values once Task 4 lands).
25
+ */
26
+ export interface SupersedeResult {
27
+ ok: true;
28
+ oldId: string;
29
+ newId: string;
30
+ }
31
+ export declare function supersede(ctx: Context, oldId: string, newContent: string): SupersedeResult;
32
+ /**
33
+ * Archive a kind='raw' memory: snapshot into raw_archive, mark archived, delete.
34
+ *
35
+ * `archiveRawMemory` audits the operation internally (op='archive_raw') using the
36
+ * row's own tenant_id. We DO NOT emit a second audit event here to avoid double-
37
+ * emitting the archive_raw op (unlike Task 1 remember/forget where the underlying
38
+ * helpers hardcode actor='cli'). Instead we pass `ctx.actor.subject` through as `who`,
39
+ * and raw-archive.ts uses that for the audit row.
40
+ */
41
+ export interface ArchiveRawOpts {
42
+ /**
43
+ * Connector idempotency hook (v0.39 commit 3). Runs inside the same
44
+ * SAVEPOINT as the archive — throwing rolls the archive back. Used by the
45
+ * Slack deletion connector to mark the deletion event seen atomically.
46
+ */
47
+ afterArchive?: (db: DatabaseSyncLike, archivedMemoryId: string) => void;
48
+ }
49
+ export interface ArchiveRawResult {
50
+ ok: true;
51
+ archivedAt: string;
52
+ }
53
+ export declare function archiveRaw(ctx: Context, id: string, reason: string, opts?: ArchiveRawOpts): ArchiveRawResult;
54
+ //# sourceMappingURL=promote.d.ts.map
@@ -0,0 +1,203 @@
1
+ // Promote to the global store, supersede with a successor, and archive raw memories.
2
+ import { openHippoDb, closeHippoDb, isSqliteBusy } from '../db.js';
3
+ import { ConflictError, NotFoundError } from '../api-errors.js';
4
+ import { auditRejectionRefusal } from '../store/audit-event.js';
5
+ import { stampOriginProject } from '../store/entry-row.js';
6
+ import { removeEntryMirrors } from '../store/mirrors.js';
7
+ import { writeEntryDbOnly, writeEntryMirrors } from '../store/entry-writes.js';
8
+ import { readEntry } from '../store/entry-reads.js';
9
+ import { updateStatsUnlessBusy } from '../store/index-and-stats.js';
10
+ import { markSummaryDirtyInTx } from '../summary-dirty.js';
11
+ import { RejectedValueError } from '../rejection.js';
12
+ import { log } from '../log.js';
13
+ import { createSuccessor } from '../memory.js';
14
+ import { appendAuditEvent } from '../audit.js';
15
+ import { promoteToGlobal } from '../shared.js';
16
+ import { archiveRawMemory } from '../raw-archive.js';
17
+ import { loadConfig } from '../config.js';
18
+ import { selectMemoryTenant } from '../store/tenant-lookup.js';
19
+ export function promote(ctx, id) {
20
+ // Tenant scope: promoteToGlobal reads the entry from the local root via
21
+ // readEntry without a tenant filter, so a Bearer for tenant A could
22
+ // promote tenant B's row by guessing or leaking the id. Pre-check the
23
+ // row's tenant_id and deny cross-tenant access with the same not-found
24
+ // wording archiveRaw uses (no info leak about whether the id exists in
25
+ // another tenant).
26
+ const ownerDb = openHippoDb(ctx.hippoRoot);
27
+ try {
28
+ if (selectMemoryTenant(ownerDb, id) !== ctx.tenantId) {
29
+ throw new NotFoundError(`memory not found: ${id}`);
30
+ }
31
+ }
32
+ finally {
33
+ closeHippoDb(ownerDb);
34
+ }
35
+ // The 'promote' row commits with the global copy, so no write follows the commit and a busy store fails the whole promote.
36
+ const globalEntry = promoteToGlobal(ctx.hippoRoot, id, {
37
+ actor: ctx.actor.subject,
38
+ tenantId: ctx.tenantId,
39
+ afterWrite: (db, globalId) => appendAuditEvent(db, {
40
+ tenantId: ctx.tenantId,
41
+ actor: ctx.actor.subject,
42
+ op: 'promote',
43
+ targetId: globalId,
44
+ metadata: { sourceId: id },
45
+ }),
46
+ });
47
+ return { ok: true, sourceId: id, globalId: globalEntry.id };
48
+ }
49
+ export function supersede(ctx, oldId, newContent) {
50
+ // Read old (tenant-scoped). readEntry filters by tenantId, so a Bearer for
51
+ // tenant A on tenant B's id throws "Memory not found" here without any
52
+ // info leak.
53
+ const old = readEntry(ctx.hippoRoot, oldId, ctx.tenantId);
54
+ if (!old) {
55
+ throw new NotFoundError(`Memory not found: ${oldId}`);
56
+ }
57
+ // Guard: not already superseded. The CAS UPDATE below race-safely closes
58
+ // the window between this read and the write; this check just produces a
59
+ // clearer error in the common single-writer case.
60
+ if (old.superseded_by) {
61
+ throw new ConflictError(`Memory ${oldId} is already superseded by ${old.superseded_by}. Supersede that one instead.`);
62
+ }
63
+ const newEntry = createSuccessor(old, newContent, {
64
+ tenantId: ctx.tenantId,
65
+ baseHalfLifeDays: loadConfig(ctx.hippoRoot).defaultHalfLifeDays,
66
+ });
67
+ // Race-safe transition: open a fresh db handle, BEGIN IMMEDIATE, run all
68
+ // three steps (CAS on old + writeEntryDbOnly(new) + supersede audit row)
69
+ // inside the same transaction. Two concurrent supersedes: exactly one CAS
70
+ // wins (changes=1), the other gets changes=0 and throws CONFLICT. No
71
+ // dangling-pointer window: the new memory's row commits atomically with
72
+ // the old.superseded_by pointer.
73
+ const db = openHippoDb(ctx.hippoRoot);
74
+ try {
75
+ db.exec('BEGIN IMMEDIATE');
76
+ try {
77
+ // 1. CAS update: only succeed if old.superseded_by IS NULL AND the
78
+ // row still belongs to ctx.tenantId. Tenant filter is belt-and-
79
+ // braces with the readEntry above — it costs nothing and closes
80
+ // a hypothetical window where ownership changes between read and
81
+ // update.
82
+ const result = db.prepare(`
83
+ UPDATE memories
84
+ SET superseded_by = ?
85
+ WHERE id = ? AND tenant_id = ? AND superseded_by IS NULL
86
+ `).run(newEntry.id, oldId, ctx.tenantId);
87
+ if ((result.changes ?? 0) === 0) {
88
+ db.exec('ROLLBACK');
89
+ throw new ConflictError(`Memory ${oldId} already superseded by another writer`);
90
+ }
91
+ // v0.30 / E2 — DAG live-coupling: OLD entry just transitioned to
92
+ // superseded. Its parent (if any) needs rebuild. Lands strictly
93
+ // between the rollback guard above and the writeEntryDbOnly(NEW)
94
+ // below so a failed CAS hits throw before this hook. The NEW
95
+ // entry's parent (typically same parent) is auto-marked by the
96
+ // writeEntryDbOnly hook (same parent → idempotent, audits once).
97
+ if (old.dag_parent_id) {
98
+ markSummaryDirtyInTx(db, old.dag_parent_id, ctx.tenantId, ctx.actor.subject);
99
+ }
100
+ // 2. Write new memory inside same tx via writeEntryDbOnly (DB-only
101
+ // path). This emits its OWN 'remember' audit row for the new
102
+ // memory inside the SAVEPOINT — atomic with the row INSERT.
103
+ writeEntryDbOnly(db, stampOriginProject(ctx.hippoRoot, newEntry), { actor: ctx.actor.subject });
104
+ // 3. User-facing 'supersede' audit row inside the same tx so the
105
+ // chain pointer + audit trail commit atomically.
106
+ appendAuditEvent(db, {
107
+ tenantId: ctx.tenantId,
108
+ actor: ctx.actor.subject,
109
+ op: 'supersede',
110
+ targetId: oldId,
111
+ metadata: { newId: newEntry.id },
112
+ });
113
+ db.exec('COMMIT');
114
+ }
115
+ catch (err) {
116
+ try {
117
+ db.exec('ROLLBACK');
118
+ }
119
+ catch { /* already rolled back */ }
120
+ // AT1 (plan §3): refusal audit lands post-ROLLBACK, in a fresh
121
+ // implicit transaction the aborted outer one cannot claw back — then
122
+ // rethrow so the caller sees the refusal.
123
+ if (err instanceof RejectedValueError) {
124
+ auditRejectionRefusal(db, err, ctx.actor.subject);
125
+ }
126
+ throw err;
127
+ }
128
+ // Mirrors after COMMIT, while the db handle is still open. Same
129
+ // invariant as the original writeEntry: a mirror failure leaves disk
130
+ // MISSING the markdown for the new memory (rebuildIndex rewrites every
131
+ // markdown mirror from the DB) but DOES NOT desync the DB or
132
+ // roll back the supersede. Logged + swallowed, non-fatal.
133
+ try {
134
+ writeEntryMirrors(ctx.hippoRoot, newEntry);
135
+ }
136
+ catch (mirrorErr) {
137
+ log.error(`supersede: mirror write failed (non-fatal, will self-heal): ${mirrorErr instanceof Error ? mirrorErr.message : String(mirrorErr)}`);
138
+ }
139
+ }
140
+ finally {
141
+ closeHippoDb(db);
142
+ }
143
+ return { ok: true, oldId, newId: newEntry.id };
144
+ }
145
+ export function archiveRaw(ctx, id, reason, opts = {}) {
146
+ const db = openHippoDb(ctx.hippoRoot);
147
+ let mirrorOk = false;
148
+ try {
149
+ // Tenant scope: archiveRawMemory looks up the row by id alone, so a
150
+ // Bearer for tenant A could archive tenant B's raw row without this
151
+ // pre-check. Deny cross-tenant access with the same not-found message
152
+ // archiveRawMemory itself would throw on a missing row, so we don't
153
+ // leak whether the id exists in another tenant.
154
+ if (selectMemoryTenant(db, id) !== ctx.tenantId) {
155
+ throw new NotFoundError(`memory not found: ${id}`);
156
+ }
157
+ archiveRawMemory(db, id, {
158
+ reason,
159
+ who: ctx.actor.subject,
160
+ afterArchive: opts.afterArchive,
161
+ });
162
+ // archiveRawMemory deletes the memories row but leaves any legacy markdown
163
+ // mirror in <root>/{buffer,episodic,semantic}/<id>.md untouched. If we left
164
+ // the mirror in place, a subsequent initStore() on an empty memories table
165
+ // would silently re-import the row via bootstrapLegacyStore — defeating the
166
+ // archive (and the GDPR right-to-be-forgotten promise on raw rows). Mirror
167
+ // forget() at src/store.ts:1046, which uses the same removeEntryMirrors call.
168
+ // The DB transaction has already committed; if filesystem unlink fails here
169
+ // we log and continue. The mirror reaper in openHippoDb will catch it on
170
+ // next DB open: raw_archive.mirror_cleaned_at stays NULL until every layer
171
+ // mirror for this id is gone, so the reaper genuinely retries.
172
+ try {
173
+ removeEntryMirrors(ctx.hippoRoot, id);
174
+ mirrorOk = true;
175
+ }
176
+ catch (mirrorErr) {
177
+ log.error(`archiveRaw: mirror cleanup failed for ${id} (will retry via reaper on next openHippoDb): ${mirrorErr instanceof Error ? mirrorErr.message : String(mirrorErr)}`);
178
+ }
179
+ if (mirrorOk) {
180
+ // Stamp mirror_cleaned_at now so the next openHippoDb reaper SELECT
181
+ // returns empty for this row. NULL stays untouched on failure -> retry.
182
+ try {
183
+ db.prepare(`UPDATE raw_archive SET mirror_cleaned_at = ? WHERE memory_id = ?`).run(new Date().toISOString(), id);
184
+ }
185
+ catch (err) {
186
+ if (!isSqliteBusy(err))
187
+ throw err;
188
+ log.warnThenDebug('archive-mirror-stamp-busy', `archived ${id}; the store was busy, so the mirror reaper will re-check it on the next open`);
189
+ }
190
+ }
191
+ }
192
+ finally {
193
+ closeHippoDb(db);
194
+ }
195
+ // Counted here rather than in the CLI: the HTTP archive route calls this too,
196
+ // so a routed archive would otherwise never reach the forgotten counter.
197
+ updateStatsUnlessBusy(ctx.hippoRoot, { forgotten: 1 }, `removed ${id}`);
198
+ // archiveRawMemory does not return the archive_at timestamp it wrote. We
199
+ // emit a fresh ISO timestamp here for the API response. Within a millisecond
200
+ // of the actual write, fine for a server response shape.
201
+ return { ok: true, archivedAt: new Date().toISOString() };
202
+ }
203
+ //# sourceMappingURL=promote.js.map
@@ -0,0 +1,24 @@
1
+ import { type QuarantineStatus } from '../quarantine.js';
2
+ import type { KeysetPosition } from '../keyset.js';
3
+ import type { Context } from './types.js';
4
+ export interface QuarantineListItem {
5
+ id: string;
6
+ originalScope: string | null;
7
+ reason: string;
8
+ status: QuarantineStatus;
9
+ quarantinedAt: string;
10
+ decidedAt: string | null;
11
+ decidedBy: string | null;
12
+ contentPreview: string;
13
+ }
14
+ /** A tenant's quarantined memories, newest first. Default `status` is 'pending' (the review queue). */
15
+ export declare function quarantineList(ctx: Context, opts?: {
16
+ status?: QuarantineStatus | 'all';
17
+ limit?: number;
18
+ after?: KeysetPosition;
19
+ }): QuarantineListItem[];
20
+ /** Release a quarantined memory to its original scope. Admin only; the scope guard refuses a row moved since (mirrors restoreDormant). */
21
+ export declare function quarantineApprove(ctx: Context, id: string): void;
22
+ /** Keep a quarantined memory hidden for good. Admin only; the raw row is untouched (append-only). */
23
+ export declare function quarantineReject(ctx: Context, id: string): void;
24
+ //# sourceMappingURL=quarantine.d.ts.map
@@ -0,0 +1,121 @@
1
+ // Quarantine review: list, approve and reject held memories.
2
+ import { openHippoDb, closeHippoDb } from '../db.js';
3
+ import { ConflictError, ForbiddenError, NotFoundError } from '../api-errors.js';
4
+ import { writeEntryMirrors } from '../store/entry-writes.js';
5
+ import { readEntry } from '../store/entry-reads.js';
6
+ import { quarantineScopeFor, getQuarantineRow, listQuarantineRows, approveQuarantineRow, rejectQuarantineRow, } from '../quarantine.js';
7
+ import { log } from '../log.js';
8
+ import { appendAuditEvent } from '../audit.js';
9
+ const QUARANTINE_PREVIEW_CHARS = 200;
10
+ /** A tenant's quarantined memories, newest first. Default `status` is 'pending' (the review queue). */
11
+ export function quarantineList(ctx, opts = {}) {
12
+ const db = openHippoDb(ctx.hippoRoot);
13
+ try {
14
+ const rows = listQuarantineRows(db, ctx.tenantId, opts.status ?? 'pending', opts.limit, opts.after);
15
+ return rows.map((row) => {
16
+ const entry = readEntry(ctx.hippoRoot, row.memoryId, ctx.tenantId);
17
+ return {
18
+ id: row.memoryId,
19
+ originalScope: row.originalScope,
20
+ reason: row.reason,
21
+ status: row.status,
22
+ quarantinedAt: row.quarantinedAt,
23
+ decidedAt: row.decidedAt,
24
+ decidedBy: row.decidedBy,
25
+ contentPreview: entry ? entry.content.slice(0, QUARANTINE_PREVIEW_CHARS) : '',
26
+ };
27
+ });
28
+ }
29
+ finally {
30
+ closeHippoDb(db);
31
+ }
32
+ }
33
+ function loadPendingQuarantineRow(db, tenantId, id) {
34
+ const row = getQuarantineRow(db, tenantId, id);
35
+ if (!row)
36
+ throw new NotFoundError(`not quarantined: ${id}`);
37
+ if (row.status !== 'pending')
38
+ throw new ConflictError(`${id} is already ${row.status}`);
39
+ return row;
40
+ }
41
+ /** Release a quarantined memory to its original scope. Admin only; the scope guard refuses a row moved since (mirrors restoreDormant). */
42
+ export function quarantineApprove(ctx, id) {
43
+ if (ctx.actor.role !== 'admin') {
44
+ throw new ForbiddenError('Only an admin key can approve a quarantined memory');
45
+ }
46
+ const db = openHippoDb(ctx.hippoRoot);
47
+ try {
48
+ db.exec('BEGIN IMMEDIATE');
49
+ try {
50
+ const row = loadPendingQuarantineRow(db, ctx.tenantId, id);
51
+ const quarantineScope = quarantineScopeFor(row.originalScope);
52
+ const updated = db
53
+ .prepare(`UPDATE memories SET scope = ? WHERE id = ? AND tenant_id = ? AND scope = ?`)
54
+ .run(row.originalScope, id, ctx.tenantId, quarantineScope);
55
+ if (Number(updated.changes ?? 0) !== 1) {
56
+ throw new ConflictError(`memory ${id} scope changed since quarantine; refusing to approve`);
57
+ }
58
+ approveQuarantineRow(db, ctx.tenantId, id, ctx.actor.subject);
59
+ appendAuditEvent(db, {
60
+ tenantId: ctx.tenantId,
61
+ actor: ctx.actor.subject,
62
+ op: 'quarantine_approve',
63
+ targetId: id,
64
+ metadata: { originalScope: row.originalScope },
65
+ });
66
+ db.exec('COMMIT');
67
+ }
68
+ catch (err) {
69
+ try {
70
+ db.exec('ROLLBACK');
71
+ }
72
+ catch { /* already rolled back */ }
73
+ throw err;
74
+ }
75
+ }
76
+ finally {
77
+ closeHippoDb(db);
78
+ }
79
+ // Post-commit, best-effort: a failed rewrite leaves the mirror showing the quarantine scope (fail-closed).
80
+ try {
81
+ const restored = readEntry(ctx.hippoRoot, id, ctx.tenantId);
82
+ if (restored)
83
+ writeEntryMirrors(ctx.hippoRoot, restored);
84
+ }
85
+ catch (err) {
86
+ log.error(`quarantine: mirror rewrite failed for ${id}: ${err instanceof Error ? err.message : String(err)}`);
87
+ }
88
+ }
89
+ /** Keep a quarantined memory hidden for good. Admin only; the raw row is untouched (append-only). */
90
+ export function quarantineReject(ctx, id) {
91
+ if (ctx.actor.role !== 'admin') {
92
+ throw new ForbiddenError('Only an admin key can reject a quarantined memory');
93
+ }
94
+ const db = openHippoDb(ctx.hippoRoot);
95
+ try {
96
+ db.exec('BEGIN IMMEDIATE');
97
+ try {
98
+ loadPendingQuarantineRow(db, ctx.tenantId, id);
99
+ rejectQuarantineRow(db, ctx.tenantId, id, ctx.actor.subject);
100
+ appendAuditEvent(db, {
101
+ tenantId: ctx.tenantId,
102
+ actor: ctx.actor.subject,
103
+ op: 'quarantine_reject',
104
+ targetId: id,
105
+ metadata: {},
106
+ });
107
+ db.exec('COMMIT');
108
+ }
109
+ catch (err) {
110
+ try {
111
+ db.exec('ROLLBACK');
112
+ }
113
+ catch { /* already rolled back */ }
114
+ throw err;
115
+ }
116
+ }
117
+ finally {
118
+ closeHippoDb(db);
119
+ }
120
+ }
121
+ //# sourceMappingURL=quarantine.js.map