hippo-memory 1.60.0 → 1.62.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 (593) hide show
  1. package/README.md +29 -54
  2. package/dist/ablation.js +9 -27
  3. package/dist/agent-memories/apply.d.ts +1 -1
  4. package/dist/agent-memories/apply.js +4 -1
  5. package/dist/agent-memories/claude-code.d.ts +3 -1
  6. package/dist/agent-memories/claude-code.js +54 -10
  7. package/dist/agent-memories/codex.js +1 -1
  8. package/dist/agent-memories/gemini.js +1 -1
  9. package/dist/agent-memories/legacy.js +1 -1
  10. package/dist/agent-memories/source.js +1 -1
  11. package/dist/agent-memories/sync.d.ts +3 -3
  12. package/dist/agent-memories/sync.js +22 -9
  13. package/dist/agent-memories/types.d.ts +0 -2
  14. package/dist/ambient-store.d.ts +14 -0
  15. package/dist/ambient-store.js +90 -0
  16. package/dist/ambient.d.ts +23 -0
  17. package/dist/ambient.js +72 -50
  18. package/dist/api/assemble.d.ts +93 -0
  19. package/dist/api/assemble.js +153 -0
  20. package/dist/api/audit.d.ts +17 -0
  21. package/dist/api/audit.js +23 -0
  22. package/dist/api/auth.d.ts +79 -0
  23. package/dist/api/auth.js +178 -0
  24. package/dist/api/context-select.d.ts +49 -0
  25. package/dist/api/context-select.js +344 -0
  26. package/dist/api/context-types.d.ts +105 -0
  27. package/dist/api/context-types.js +3 -0
  28. package/dist/api/context.d.ts +31 -0
  29. package/dist/api/context.js +378 -0
  30. package/dist/api/dormant.d.ts +30 -0
  31. package/dist/api/dormant.js +140 -0
  32. package/dist/api/drill-down.d.ts +84 -0
  33. package/dist/api/drill-down.js +126 -0
  34. package/dist/api/forget.d.ts +57 -0
  35. package/dist/api/forget.js +87 -0
  36. package/dist/api/goals.d.ts +18 -0
  37. package/dist/api/goals.js +33 -0
  38. package/dist/api/learn.d.ts +31 -0
  39. package/dist/api/learn.js +88 -0
  40. package/dist/api/outcome.d.ts +61 -0
  41. package/dist/api/outcome.js +66 -0
  42. package/dist/api/promote.d.ts +54 -0
  43. package/dist/api/promote.js +192 -0
  44. package/dist/api/quarantine.d.ts +24 -0
  45. package/dist/api/quarantine.js +121 -0
  46. package/dist/api/recall-types.d.ts +390 -0
  47. package/dist/api/recall-types.js +3 -0
  48. package/dist/api/recall.d.ts +36 -0
  49. package/dist/api/recall.js +499 -0
  50. package/dist/api/remember.d.ts +35 -0
  51. package/dist/api/remember.js +43 -0
  52. package/dist/api/sleep.d.ts +136 -0
  53. package/dist/api/sleep.js +256 -0
  54. package/dist/api/tokens.d.ts +26 -0
  55. package/dist/api/tokens.js +60 -0
  56. package/dist/api/types.d.ts +56 -0
  57. package/dist/api/types.js +38 -0
  58. package/dist/api.d.ts +20 -1262
  59. package/dist/api.js +25 -2727
  60. package/dist/audit.d.ts +3 -0
  61. package/dist/audit.js +6 -3
  62. package/dist/auth.d.ts +45 -4
  63. package/dist/auth.js +125 -48
  64. package/dist/autolearn.js +2 -2
  65. package/dist/capture/command.d.ts +33 -0
  66. package/dist/capture/command.js +264 -0
  67. package/dist/capture/compact.d.ts +44 -0
  68. package/dist/capture/compact.js +354 -0
  69. package/dist/capture/extract.d.ts +21 -0
  70. package/dist/capture/extract.js +464 -0
  71. package/dist/capture/transcript.d.ts +40 -0
  72. package/dist/capture/transcript.js +193 -0
  73. package/dist/capture-error.js +2 -1
  74. package/dist/churn-git.js +4 -2
  75. package/dist/cli/audit.d.ts +3 -0
  76. package/dist/cli/audit.js +159 -0
  77. package/dist/cli/auth.d.ts +2 -0
  78. package/dist/cli/auth.js +171 -0
  79. package/dist/cli/briefs.d.ts +4 -0
  80. package/dist/cli/briefs.js +453 -0
  81. package/dist/cli/card.d.ts +3 -0
  82. package/dist/cli/card.js +333 -0
  83. package/dist/cli/context.d.ts +15 -0
  84. package/dist/cli/context.js +376 -0
  85. package/dist/cli/continuity.d.ts +6 -0
  86. package/dist/cli/continuity.js +457 -0
  87. package/dist/cli/curate.d.ts +19 -0
  88. package/dist/cli/curate.js +556 -0
  89. package/dist/cli/dag.d.ts +5 -0
  90. package/dist/cli/dag.js +177 -0
  91. package/dist/cli/decisions.d.ts +4 -0
  92. package/dist/cli/decisions.js +528 -0
  93. package/dist/cli/eval.d.ts +5 -0
  94. package/dist/cli/eval.js +213 -0
  95. package/dist/cli/explain.d.ts +4 -0
  96. package/dist/cli/explain.js +156 -0
  97. package/dist/cli/goals.d.ts +2 -0
  98. package/dist/cli/goals.js +196 -0
  99. package/dist/cli/hook-blocks.d.ts +18 -0
  100. package/dist/cli/hook-blocks.js +233 -0
  101. package/dist/cli/init.d.ts +2 -0
  102. package/dist/cli/init.js +305 -0
  103. package/dist/cli/maintenance.d.ts +4 -0
  104. package/dist/cli/maintenance.js +190 -0
  105. package/dist/cli/playbooks.d.ts +4 -0
  106. package/dist/cli/playbooks.js +573 -0
  107. package/dist/cli/projects.js +9 -6
  108. package/dist/cli/recall.d.ts +7 -0
  109. package/dist/cli/recall.js +582 -0
  110. package/dist/cli/remember.d.ts +5 -0
  111. package/dist/cli/remember.js +485 -0
  112. package/dist/cli/serve.d.ts +5 -0
  113. package/dist/cli/serve.js +40 -0
  114. package/dist/cli/session-hooks.d.ts +29 -0
  115. package/dist/cli/session-hooks.js +647 -0
  116. package/dist/cli/setup.d.ts +4 -0
  117. package/dist/cli/setup.js +397 -0
  118. package/dist/cli/shared.d.ts +15 -19
  119. package/dist/cli/shared.js +50 -341
  120. package/dist/cli/slack.d.ts +2 -0
  121. package/dist/cli/slack.js +171 -0
  122. package/dist/cli/status.d.ts +18 -0
  123. package/dist/cli/status.js +409 -0
  124. package/dist/cli/transfer.d.ts +10 -0
  125. package/dist/cli/transfer.js +424 -0
  126. package/dist/cli/usage.d.ts +85 -0
  127. package/dist/cli/usage.js +741 -0
  128. package/dist/cli.d.ts +71 -120
  129. package/dist/cli.js +170 -8469
  130. package/dist/client.js +15 -8
  131. package/dist/compaction-record.d.ts +0 -2
  132. package/dist/compaction-record.js +7 -5
  133. package/dist/connectors/github/backfill.js +94 -87
  134. package/dist/connectors/github/cli-impl.js +4 -3
  135. package/dist/connectors/github/dlq.js +67 -54
  136. package/dist/connectors/github/ingest.js +34 -35
  137. package/dist/connectors/github/tenant-routing.js +3 -2
  138. package/dist/connectors/github/webhook.js +135 -216
  139. package/dist/connectors/slack/dlq.js +49 -61
  140. package/dist/connectors/slack/ingest.js +55 -48
  141. package/dist/connectors/slack/tenant-routing.js +4 -3
  142. package/dist/connectors/slack/webhook.js +72 -74
  143. package/dist/consolidate/conflicts.d.ts +10 -0
  144. package/dist/consolidate/conflicts.js +178 -0
  145. package/dist/consolidate/decay.d.ts +12 -0
  146. package/dist/consolidate/decay.js +145 -0
  147. package/dist/consolidate/llm-passes.d.ts +3 -0
  148. package/dist/consolidate/llm-passes.js +141 -0
  149. package/dist/consolidate/merge.d.ts +7 -0
  150. package/dist/consolidate/merge.js +251 -0
  151. package/dist/consolidate/physics-pass.d.ts +3 -0
  152. package/dist/consolidate/physics-pass.js +60 -0
  153. package/dist/consolidate/run.d.ts +69 -0
  154. package/dist/consolidate/run.js +76 -0
  155. package/dist/consolidate/sleep.d.ts +18 -0
  156. package/dist/consolidate/sleep.js +209 -0
  157. package/dist/consolidate/traces.d.ts +4 -0
  158. package/dist/consolidate/traces.js +178 -0
  159. package/dist/context-auto.js +7 -11
  160. package/dist/context-render.d.ts +1 -1
  161. package/dist/context-render.js +1 -1
  162. package/dist/customer-notes.d.ts +3 -0
  163. package/dist/customer-notes.js +83 -72
  164. package/dist/dag.js +225 -188
  165. package/dist/dashboard-actions.d.ts +20 -0
  166. package/dist/dashboard-actions.js +88 -0
  167. package/dist/dashboard-params.d.ts +45 -0
  168. package/dist/dashboard-params.js +127 -0
  169. package/dist/dashboard-queries.d.ts +15 -0
  170. package/dist/dashboard-queries.js +355 -0
  171. package/dist/dashboard-snapshot.d.ts +138 -0
  172. package/dist/dashboard-snapshot.js +308 -0
  173. package/dist/dashboard-types.d.ts +163 -0
  174. package/dist/dashboard-types.js +3 -0
  175. package/dist/dashboard.d.ts +6 -7
  176. package/dist/dashboard.js +228 -202
  177. package/dist/db/busy.d.ts +5 -0
  178. package/dist/db/busy.js +24 -0
  179. package/dist/db/continuity.d.ts +5 -0
  180. package/dist/db/continuity.js +145 -0
  181. package/dist/db/meta.d.ts +8 -0
  182. package/dist/db/meta.js +35 -0
  183. package/dist/db/migrate.d.ts +9 -0
  184. package/dist/db/migrate.js +138 -0
  185. package/dist/db/migrations/index.d.ts +5 -0
  186. package/dist/db/migrations/index.js +109 -0
  187. package/dist/db/migrations/types.d.ts +14 -0
  188. package/dist/db/migrations/types.js +2 -0
  189. package/dist/db/migrations/v01.d.ts +3 -0
  190. package/dist/db/migrations/v01.js +38 -0
  191. package/dist/db/migrations/v02.d.ts +3 -0
  192. package/dist/db/migrations/v02.js +21 -0
  193. package/dist/db/migrations/v03.d.ts +3 -0
  194. package/dist/db/migrations/v03.js +22 -0
  195. package/dist/db/migrations/v04.d.ts +3 -0
  196. package/dist/db/migrations/v04.js +28 -0
  197. package/dist/db/migrations/v05.d.ts +3 -0
  198. package/dist/db/migrations/v05.js +21 -0
  199. package/dist/db/migrations/v06.d.ts +3 -0
  200. package/dist/db/migrations/v06.js +25 -0
  201. package/dist/db/migrations/v07.d.ts +3 -0
  202. package/dist/db/migrations/v07.js +13 -0
  203. package/dist/db/migrations/v08.d.ts +3 -0
  204. package/dist/db/migrations/v08.js +8 -0
  205. package/dist/db/migrations/v09.d.ts +3 -0
  206. package/dist/db/migrations/v09.js +13 -0
  207. package/dist/db/migrations/v10.d.ts +3 -0
  208. package/dist/db/migrations/v10.js +17 -0
  209. package/dist/db/migrations/v11.d.ts +3 -0
  210. package/dist/db/migrations/v11.js +15 -0
  211. package/dist/db/migrations/v12.d.ts +3 -0
  212. package/dist/db/migrations/v12.js +11 -0
  213. package/dist/db/migrations/v13.d.ts +3 -0
  214. package/dist/db/migrations/v13.js +15 -0
  215. package/dist/db/migrations/v14.d.ts +3 -0
  216. package/dist/db/migrations/v14.js +66 -0
  217. package/dist/db/migrations/v15.d.ts +3 -0
  218. package/dist/db/migrations/v15.js +42 -0
  219. package/dist/db/migrations/v16.d.ts +3 -0
  220. package/dist/db/migrations/v16.js +61 -0
  221. package/dist/db/migrations/v17.d.ts +3 -0
  222. package/dist/db/migrations/v17.js +46 -0
  223. package/dist/db/migrations/v18.d.ts +3 -0
  224. package/dist/db/migrations/v18.js +60 -0
  225. package/dist/db/migrations/v19.d.ts +3 -0
  226. package/dist/db/migrations/v19.js +28 -0
  227. package/dist/db/migrations/v20.d.ts +3 -0
  228. package/dist/db/migrations/v20.js +42 -0
  229. package/dist/db/migrations/v21.d.ts +3 -0
  230. package/dist/db/migrations/v21.js +16 -0
  231. package/dist/db/migrations/v22.d.ts +3 -0
  232. package/dist/db/migrations/v22.js +82 -0
  233. package/dist/db/migrations/v23.d.ts +3 -0
  234. package/dist/db/migrations/v23.js +48 -0
  235. package/dist/db/migrations/v24.d.ts +3 -0
  236. package/dist/db/migrations/v24.js +72 -0
  237. package/dist/db/migrations/v25.d.ts +3 -0
  238. package/dist/db/migrations/v25.js +46 -0
  239. package/dist/db/migrations/v26.d.ts +3 -0
  240. package/dist/db/migrations/v26.js +23 -0
  241. package/dist/db/migrations/v27.d.ts +3 -0
  242. package/dist/db/migrations/v27.js +57 -0
  243. package/dist/db/migrations/v28.d.ts +3 -0
  244. package/dist/db/migrations/v28.js +38 -0
  245. package/dist/db/migrations/v29.d.ts +3 -0
  246. package/dist/db/migrations/v29.js +78 -0
  247. package/dist/db/migrations/v30.d.ts +3 -0
  248. package/dist/db/migrations/v30.js +92 -0
  249. package/dist/db/migrations/v31.d.ts +3 -0
  250. package/dist/db/migrations/v31.js +74 -0
  251. package/dist/db/migrations/v32.d.ts +3 -0
  252. package/dist/db/migrations/v32.js +102 -0
  253. package/dist/db/migrations/v33.d.ts +3 -0
  254. package/dist/db/migrations/v33.js +104 -0
  255. package/dist/db/migrations/v34.d.ts +3 -0
  256. package/dist/db/migrations/v34.js +93 -0
  257. package/dist/db/migrations/v35.d.ts +3 -0
  258. package/dist/db/migrations/v35.js +98 -0
  259. package/dist/db/migrations/v36.d.ts +3 -0
  260. package/dist/db/migrations/v36.js +98 -0
  261. package/dist/db/migrations/v37.d.ts +3 -0
  262. package/dist/db/migrations/v37.js +219 -0
  263. package/dist/db/migrations/v38.d.ts +3 -0
  264. package/dist/db/migrations/v38.js +277 -0
  265. package/dist/db/migrations/v39.d.ts +3 -0
  266. package/dist/db/migrations/v39.js +59 -0
  267. package/dist/db/migrations/v40.d.ts +3 -0
  268. package/dist/db/migrations/v40.js +74 -0
  269. package/dist/db/migrations/v41.d.ts +3 -0
  270. package/dist/db/migrations/v41.js +43 -0
  271. package/dist/db/migrations/v42.d.ts +3 -0
  272. package/dist/db/migrations/v42.js +41 -0
  273. package/dist/db/migrations/v43.d.ts +3 -0
  274. package/dist/db/migrations/v43.js +67 -0
  275. package/dist/db/migrations/v44.d.ts +3 -0
  276. package/dist/db/migrations/v44.js +28 -0
  277. package/dist/db/migrations/v45.d.ts +3 -0
  278. package/dist/db/migrations/v45.js +30 -0
  279. package/dist/db/migrations/v46.d.ts +3 -0
  280. package/dist/db/migrations/v46.js +25 -0
  281. package/dist/db/migrations/v47.d.ts +3 -0
  282. package/dist/db/migrations/v47.js +17 -0
  283. package/dist/db/migrations/v48.d.ts +3 -0
  284. package/dist/db/migrations/v48.js +10 -0
  285. package/dist/db/migrations/v49.d.ts +3 -0
  286. package/dist/db/migrations/v49.js +31 -0
  287. package/dist/db/migrations/v50.d.ts +3 -0
  288. package/dist/db/migrations/v50.js +67 -0
  289. package/dist/db/migrations/v51.d.ts +3 -0
  290. package/dist/db/migrations/v51.js +14 -0
  291. package/dist/db/migrations/v52.d.ts +3 -0
  292. package/dist/db/migrations/v52.js +7 -0
  293. package/dist/db/open.d.ts +23 -0
  294. package/dist/db/open.js +146 -0
  295. package/dist/db/sqlite.d.ts +21 -0
  296. package/dist/db/sqlite.js +8 -0
  297. package/dist/db/tables.d.ts +7 -0
  298. package/dist/db/tables.js +38 -0
  299. package/dist/db.d.ts +6 -46
  300. package/dist/db.js +5 -3049
  301. package/dist/decisions.d.ts +4 -1
  302. package/dist/decisions.js +102 -83
  303. package/dist/dedupe.js +3 -2
  304. package/dist/delivery-recorder.js +4 -1
  305. package/dist/doctor.js +14 -10
  306. package/dist/embedding-provider.d.ts +1 -1
  307. package/dist/embedding-provider.js +4 -3
  308. package/dist/embeddings.d.ts +9 -52
  309. package/dist/embeddings.js +43 -297
  310. package/dist/env.d.ts +75 -0
  311. package/dist/env.js +119 -0
  312. package/dist/eval-suite.js +1 -1
  313. package/dist/eval.js +2 -2
  314. package/dist/extract.js +1 -1
  315. package/dist/gated-write.js +3 -1
  316. package/dist/goals.d.ts +3 -1
  317. package/dist/goals.js +117 -86
  318. package/dist/graph/read.d.ts +73 -0
  319. package/dist/graph/read.js +325 -0
  320. package/dist/graph/rows.d.ts +45 -0
  321. package/dist/graph/rows.js +51 -0
  322. package/dist/graph/types.d.ts +83 -0
  323. package/dist/graph/types.js +11 -0
  324. package/dist/graph/write.d.ts +93 -0
  325. package/dist/{graph.js → graph/write.js} +6 -384
  326. package/dist/graph-extract.js +2 -1
  327. package/dist/graph-recall.d.ts +1 -1
  328. package/dist/graph-recall.js +2 -2
  329. package/dist/graph-stream.js +1 -1
  330. package/dist/graph-view.d.ts +1 -1
  331. package/dist/graph-view.js +1 -1
  332. package/dist/half-life-migration.d.ts +1 -1
  333. package/dist/half-life-migration.js +2 -1
  334. package/dist/hooks/codex-session.d.ts +8 -0
  335. package/dist/hooks/codex-session.js +76 -0
  336. package/dist/hooks/codex-wrapper.d.ts +55 -0
  337. package/dist/hooks/codex-wrapper.js +288 -0
  338. package/dist/hooks/json-hooks.d.ts +63 -0
  339. package/dist/hooks/json-hooks.js +356 -0
  340. package/dist/hooks/opencode.d.ts +50 -0
  341. package/dist/hooks/opencode.js +202 -0
  342. package/dist/hooks/shared.d.ts +54 -0
  343. package/dist/hooks/shared.js +77 -0
  344. package/dist/http-retry.d.ts +2 -0
  345. package/dist/http-retry.js +4 -3
  346. package/dist/http-util.d.ts +3 -0
  347. package/dist/http-util.js +10 -0
  348. package/dist/{importers.d.ts → importers/core.d.ts} +13 -17
  349. package/dist/importers/core.js +141 -0
  350. package/dist/importers/markdown-parse.d.ts +41 -0
  351. package/dist/importers/markdown-parse.js +132 -0
  352. package/dist/importers/markdown.d.ts +3 -0
  353. package/dist/importers/markdown.js +92 -0
  354. package/dist/importers/sources.d.ts +7 -0
  355. package/dist/importers/sources.js +229 -0
  356. package/dist/importers/vault.d.ts +11 -0
  357. package/dist/importers/vault.js +352 -0
  358. package/dist/incidents.d.ts +3 -0
  359. package/dist/incidents.js +52 -43
  360. package/dist/index.d.ts +25 -6
  361. package/dist/index.js +23 -6
  362. package/dist/invalidation.js +2 -1
  363. package/dist/judgment.js +2 -1
  364. package/dist/keyset.d.ts +13 -0
  365. package/dist/keyset.js +8 -0
  366. package/dist/local-embedding.d.ts +13 -0
  367. package/dist/local-embedding.js +165 -0
  368. package/dist/log.d.ts +7 -0
  369. package/dist/log.js +19 -1
  370. package/dist/mcp/admin-tools.d.ts +8 -0
  371. package/dist/mcp/admin-tools.js +116 -0
  372. package/dist/mcp/format.d.ts +27 -0
  373. package/dist/mcp/format.js +135 -0
  374. package/dist/mcp/memory-tools.d.ts +5 -0
  375. package/dist/mcp/memory-tools.js +83 -0
  376. package/dist/mcp/protocol.d.ts +83 -0
  377. package/dist/mcp/protocol.js +55 -0
  378. package/dist/mcp/recall-tools.d.ts +6 -0
  379. package/dist/mcp/recall-tools.js +320 -0
  380. package/dist/mcp/request.d.ts +10 -0
  381. package/dist/mcp/request.js +163 -0
  382. package/dist/mcp/server.d.ts +4 -75
  383. package/dist/mcp/server.js +7 -1190
  384. package/dist/mcp/session-state.d.ts +11 -0
  385. package/dist/mcp/session-state.js +28 -0
  386. package/dist/mcp/stdio.d.ts +8 -0
  387. package/dist/mcp/stdio.js +79 -0
  388. package/dist/mcp/tools.d.ts +11 -0
  389. package/dist/mcp/tools.js +247 -0
  390. package/dist/memory.d.ts +3 -0
  391. package/dist/memory.js +27 -1
  392. package/dist/multihop.d.ts +1 -1
  393. package/dist/multihop.js +2 -1
  394. package/dist/owner-validation.js +2 -1
  395. package/dist/physics-state.js +10 -7
  396. package/dist/policies.d.ts +3 -0
  397. package/dist/policies.js +93 -74
  398. package/dist/postinstall.js +3 -2
  399. package/dist/predictions/planning-fallacy.d.ts +100 -0
  400. package/dist/predictions/planning-fallacy.js +190 -0
  401. package/dist/{predictions.d.ts → predictions/store.d.ts} +7 -102
  402. package/dist/predictions/store.js +434 -0
  403. package/dist/processes.d.ts +3 -0
  404. package/dist/processes.js +94 -76
  405. package/dist/project-briefs.d.ts +3 -0
  406. package/dist/project-briefs.js +142 -113
  407. package/dist/project-identity.js +3 -2
  408. package/dist/project-merge.d.ts +12 -4
  409. package/dist/project-merge.js +132 -45
  410. package/dist/quarantine.d.ts +2 -1
  411. package/dist/quarantine.js +8 -5
  412. package/dist/raw-archive.js +1 -1
  413. package/dist/recall-history.js +3 -2
  414. package/dist/recall-pipeline.d.ts +2 -2
  415. package/dist/recall-pipeline.js +16 -8
  416. package/dist/recall-scope.js +1 -1
  417. package/dist/recall-trace.d.ts +1 -1
  418. package/dist/refine-llm.js +2 -1
  419. package/dist/reject-flow.js +6 -1
  420. package/dist/rerankers/clef.js +6 -5
  421. package/dist/rerankers/jev.d.ts +1 -1
  422. package/dist/rerankers/jev.js +4 -4
  423. package/dist/rerankers/llm.d.ts +4 -2
  424. package/dist/rerankers/llm.js +58 -38
  425. package/dist/rerankers/types.d.ts +1 -1
  426. package/dist/salience.js +1 -1
  427. package/dist/scheduler.d.ts +1 -0
  428. package/dist/scheduler.js +26 -4
  429. package/dist/scope.js +4 -3
  430. package/dist/search/as-of.d.ts +10 -0
  431. package/dist/search/as-of.js +22 -0
  432. package/dist/search/bm25-search.d.ts +14 -0
  433. package/dist/search/bm25-search.js +43 -0
  434. package/dist/search/bm25.d.ts +15 -0
  435. package/dist/search/bm25.js +54 -0
  436. package/dist/search/boosts.d.ts +54 -0
  437. package/dist/search/boosts.js +94 -0
  438. package/dist/search/breakdown.d.ts +7 -0
  439. package/dist/search/breakdown.js +20 -0
  440. package/dist/search/explain.d.ts +25 -0
  441. package/dist/search/explain.js +31 -0
  442. package/dist/search/finalize.d.ts +8 -0
  443. package/dist/search/finalize.js +52 -0
  444. package/dist/search/fusion.d.ts +27 -0
  445. package/dist/search/fusion.js +42 -0
  446. package/dist/search/hybrid-score.d.ts +20 -0
  447. package/dist/search/hybrid-score.js +73 -0
  448. package/dist/search/hybrid.d.ts +46 -0
  449. package/dist/search/hybrid.js +64 -0
  450. package/dist/search/physics-search.d.ts +29 -0
  451. package/dist/search/physics-search.js +162 -0
  452. package/dist/search/rerank.d.ts +10 -0
  453. package/dist/search/rerank.js +72 -0
  454. package/dist/search/temporal.d.ts +15 -0
  455. package/dist/search/temporal.js +45 -0
  456. package/dist/search/types.d.ts +91 -0
  457. package/dist/search/types.js +2 -0
  458. package/dist/search/vector.d.ts +30 -0
  459. package/dist/search/vector.js +71 -0
  460. package/dist/secret-detect.d.ts +2 -0
  461. package/dist/secret-detect.js +2 -1
  462. package/dist/server/auth.d.ts +52 -0
  463. package/dist/server/auth.js +221 -0
  464. package/dist/server/client-ip.d.ts +25 -0
  465. package/dist/server/client-ip.js +92 -0
  466. package/dist/server/cursor.d.ts +23 -0
  467. package/dist/server/cursor.js +58 -0
  468. package/dist/server/lifecycle.d.ts +7 -0
  469. package/dist/server/lifecycle.js +29 -0
  470. package/dist/server/mcp-http.d.ts +5 -0
  471. package/dist/server/mcp-http.js +199 -0
  472. package/dist/server/request.d.ts +33 -0
  473. package/dist/server/request.js +103 -0
  474. package/dist/server/routes/admin.d.ts +9 -0
  475. package/dist/server/routes/admin.js +158 -0
  476. package/dist/server/routes/customer-notes.d.ts +7 -0
  477. package/dist/server/routes/customer-notes.js +112 -0
  478. package/dist/server/routes/decisions.d.ts +7 -0
  479. package/dist/server/routes/decisions.js +133 -0
  480. package/dist/server/routes/incidents.d.ts +7 -0
  481. package/dist/server/routes/incidents.js +126 -0
  482. package/dist/server/routes/memories.d.ts +10 -0
  483. package/dist/server/routes/memories.js +179 -0
  484. package/dist/server/routes/policies.d.ts +8 -0
  485. package/dist/server/routes/policies.js +151 -0
  486. package/dist/server/routes/predictions.d.ts +7 -0
  487. package/dist/server/routes/predictions.js +164 -0
  488. package/dist/server/routes/processes.d.ts +7 -0
  489. package/dist/server/routes/processes.js +161 -0
  490. package/dist/server/routes/project-briefs.d.ts +8 -0
  491. package/dist/server/routes/project-briefs.js +136 -0
  492. package/dist/server/routes/recall.d.ts +8 -0
  493. package/dist/server/routes/recall.js +340 -0
  494. package/dist/server/routes/skills.d.ts +8 -0
  495. package/dist/server/routes/skills.js +150 -0
  496. package/dist/server/types.d.ts +56 -0
  497. package/dist/server/types.js +2 -0
  498. package/dist/server/validation.d.ts +14 -0
  499. package/dist/server/validation.js +91 -0
  500. package/dist/server.d.ts +7 -61
  501. package/dist/server.js +69 -2362
  502. package/dist/session-digest.d.ts +1 -1
  503. package/dist/session-digest.js +9 -2
  504. package/dist/shared.d.ts +12 -1
  505. package/dist/shared.js +33 -27
  506. package/dist/skills.d.ts +3 -0
  507. package/dist/skills.js +88 -70
  508. package/dist/stdin.js +2 -2
  509. package/dist/store/audit-event.d.ts +19 -0
  510. package/dist/store/audit-event.js +33 -0
  511. package/dist/store/candidates.d.ts +42 -0
  512. package/dist/store/candidates.js +152 -0
  513. package/dist/store/conflicts.d.ts +44 -0
  514. package/dist/store/conflicts.js +444 -0
  515. package/dist/store/delete-and-batch.d.ts +63 -0
  516. package/dist/store/delete-and-batch.js +310 -0
  517. package/dist/store/entry-reads.d.ts +92 -0
  518. package/dist/store/entry-reads.js +255 -0
  519. package/dist/store/entry-row.d.ts +67 -0
  520. package/dist/store/entry-row.js +208 -0
  521. package/dist/store/entry-writes.d.ts +46 -0
  522. package/dist/store/entry-writes.js +148 -0
  523. package/dist/store/handoffs.d.ts +26 -0
  524. package/dist/store/handoffs.js +184 -0
  525. package/dist/store/index-and-stats.d.ts +52 -0
  526. package/dist/store/index-and-stats.js +214 -0
  527. package/dist/store/markdown.d.ts +10 -0
  528. package/dist/store/markdown.js +108 -0
  529. package/dist/store/mirrors.d.ts +49 -0
  530. package/dist/store/mirrors.js +312 -0
  531. package/dist/store/open.d.ts +15 -0
  532. package/dist/store/open.js +223 -0
  533. package/dist/store/rows.d.ts +178 -0
  534. package/dist/store/rows.js +158 -0
  535. package/dist/store/search-rows.d.ts +86 -0
  536. package/dist/store/search-rows.js +260 -0
  537. package/dist/store/sessions.d.ts +83 -0
  538. package/dist/store/sessions.js +272 -0
  539. package/dist/store/summaries.d.ts +94 -0
  540. package/dist/store/summaries.js +377 -0
  541. package/dist/store/tenant-lookup.d.ts +12 -0
  542. package/dist/store/tenant-lookup.js +16 -0
  543. package/dist/store-cards.js +2 -1
  544. package/dist/summary-dirty.d.ts +4 -0
  545. package/dist/summary-dirty.js +32 -0
  546. package/dist/support-bundle.js +4 -3
  547. package/dist/tenant.js +2 -2
  548. package/dist/tokenize.d.ts +2 -0
  549. package/dist/tokenize.js +16 -0
  550. package/dist/transcript-tail.d.ts +7 -0
  551. package/dist/transcript-tail.js +48 -0
  552. package/dist/vector-store.d.ts +27 -0
  553. package/dist/vector-store.js +210 -0
  554. package/dist/version.d.ts +2 -2
  555. package/dist/version.js +2 -2
  556. package/dist/working-memory.js +1 -1
  557. package/dist/yaml.js +36 -11
  558. package/dist-ui/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
  559. package/dist-ui/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
  560. package/dist-ui/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
  561. package/dist-ui/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
  562. package/dist-ui/assets/ibm-plex-mono-latin-600-normal-BgSNZQsw.woff2 +0 -0
  563. package/dist-ui/assets/ibm-plex-mono-latin-600-normal-DWFSQ4vo.woff +0 -0
  564. package/dist-ui/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
  565. package/dist-ui/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
  566. package/dist-ui/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
  567. package/dist-ui/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff +0 -0
  568. package/dist-ui/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
  569. package/dist-ui/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
  570. package/dist-ui/assets/index-DPN7cP19.js +33 -0
  571. package/dist-ui/assets/index-dFloKRVr.css +1 -0
  572. package/dist-ui/index.html +3 -25
  573. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  574. package/extensions/openclaw-plugin/package.json +1 -1
  575. package/openclaw.plugin.json +1 -1
  576. package/package.json +1 -1
  577. package/dist/capture.d.ts +0 -155
  578. package/dist/capture.js +0 -1295
  579. package/dist/consolidate.d.ts +0 -58
  580. package/dist/consolidate.js +0 -1124
  581. package/dist/graph.d.ts +0 -245
  582. package/dist/hooks.d.ts +0 -208
  583. package/dist/hooks.js +0 -1076
  584. package/dist/importers.js +0 -900
  585. package/dist/predictions.js +0 -620
  586. package/dist/search.d.ts +0 -320
  587. package/dist/search.js +0 -970
  588. package/dist/store.d.ts +0 -776
  589. package/dist/store.js +0 -3473
  590. package/dist-ui/assets/d3-BiWEKnn4.js +0 -1
  591. package/dist-ui/assets/index-BhT8RvO6.js +0 -61
  592. package/dist-ui/assets/index-RoXXJ5dq.css +0 -1
  593. package/dist-ui/assets/three-BDgTxR1l.js +0 -4112
@@ -0,0 +1,260 @@
1
+ import { envForceLikePath } from '../env.js';
2
+ import { isFtsAvailable, closeHippoDb } from '../db.js';
3
+ import { tokenize } from '../tokenize.js';
4
+ import { RECALL_DEFAULT_DENY_SCOPES } from '../recall-scope.js';
5
+ import { RAREST_TERM_COUNT, rarestPromptTerms } from '../prompt-recall.js';
6
+ import { log } from '../log.js';
7
+ import { topVectorMatches } from '../vector-store.js';
8
+ import { MEMORY_SELECT_COLUMNS, MEMORY_SEARCH_COLUMNS, DEFAULT_SEARCH_CANDIDATE_LIMIT, rowToEntry, } from './rows.js';
9
+ import { openStore } from './open.js';
10
+ /** The recall scope rule for a table column prefix (`m.` or none); `passesScopeFilterForRecall` in recall-scope.ts is its JS twin. */
11
+ function recallScopeClause(col, scopeFilter) {
12
+ if (scopeFilter === undefined)
13
+ return { sql: '', params: [] };
14
+ if (scopeFilter.mode === 'exact')
15
+ return { sql: ` AND ${col}scope = ?`, params: [scopeFilter.value] };
16
+ // `IS NULL OR` admits NULL scopes, which NOT IN alone drops. NOT LIKE denies a superset of private scopes before the
17
+ // window cut so private rows cannot starve admitted ones; the anchored JS regex stays the exact post-filter.
18
+ const placeholders = RECALL_DEFAULT_DENY_SCOPES.map(() => '?').join(', ');
19
+ const admitted = `${col}scope IS NULL OR (${col}scope NOT IN (${placeholders}) AND ${col}scope NOT LIKE '%:private:%')`;
20
+ if (scopeFilter.mode === 'default-deny')
21
+ return { sql: ` AND (${admitted})`, params: [...RECALL_DEFAULT_DENY_SCOPES] };
22
+ // The trailing arm keeps a deliberately requested scope loadable, private or quarantined included.
23
+ return { sql: ` AND (${admitted} OR ${col}scope = ?)`, params: [...RECALL_DEFAULT_DENY_SCOPES, scopeFilter.value] };
24
+ }
25
+ // In SQL, not after the window cut, so other projects' matches cannot crowd the project's own rows out of the LIMIT.
26
+ function withProject(scope, col, originProject) {
27
+ if (originProject === undefined)
28
+ return scope;
29
+ return { sql: `${scope.sql} AND (${col}origin_project = '' OR ${col}origin_project = ?)`, params: [...scope.params, originProject] };
30
+ }
31
+ /** Scope rule for recall: none requested is default-deny; 'exact' narrows to the request; 'additive' adds it to the default set. */
32
+ export function recallScopeFilter(requestedScope, mode) {
33
+ if (!requestedScope)
34
+ return { mode: 'default-deny' };
35
+ return mode === 'additive' ? { mode: 'default-deny-or-exact', value: requestedScope } : { mode: 'exact', value: requestedScope };
36
+ }
37
+ const FTS_QUERY_SYNTAX_RE = /fts5: syntax error|unterminated string/i;
38
+ function loadSearchRows(db, query, limit, tenantId, scopeFilter, includeSuperseded = true, originProject) {
39
+ const p = searchPredicates(tenantId, scopeFilter, includeSuperseded, originProject);
40
+ const terms = Array.from(new Set(tokenize(query)));
41
+ if (terms.length === 0) {
42
+ // F3 (v1.7.0) self-review: empty-query path is the second uncapped
43
+ // path (codex diff-pass caught the full-store fallback at the bottom;
44
+ // this no-terms path had the same shape). Apply LIMIT so all four
45
+ // candidate paths honour the caller's cap when set.
46
+ return selectAllCandidates(db, p, limit);
47
+ }
48
+ // v1.7.1 — test/diagnostic hook: `HIPPO_FORCE_LIKE_PATH=1` forces the
49
+ // LIKE-fallback path here only. Gated at the read-call site so writes
50
+ // (`syncFtsRow`, `deleteFtsRow`, `raw-archive.ts::archiveRaw`) keep using
51
+ // `isFtsAvailable` honestly and never silently skip FTS index sync.
52
+ // Lets tests exercise the LIKE branch deterministically without
53
+ // poisoning the on-disk FTS state.
54
+ const forceLikePath = envForceLikePath();
55
+ if (!forceLikePath && isFtsAvailable(db)) {
56
+ const rows = selectFtsCandidates(db, terms, p, limit);
57
+ if (rows.length > 0)
58
+ return rows;
59
+ }
60
+ const rows = selectLikeCandidates(db, terms, p, limit);
61
+ if (rows.length > 0)
62
+ return rows;
63
+ // F3 (v1.7.0) codex P1: pre-v1.7.0 the full-store fallback ignored
64
+ // `limit` and could return the whole tenant store. With scorerWindow
65
+ // now reported on RecallResult, an unbounded fallback would lie about
66
+ // candidate-pool size. Apply LIMIT here so all four paths honour the
67
+ // caller's cap.
68
+ return selectAllCandidates(db, p, limit);
69
+ }
70
+ function searchPredicates(tenantId, scopeFilter, includeSuperseded, originProject) {
71
+ // tenantId undefined = no tenant filter (legacy callers / cross-deployment
72
+ // helpers). tenantId set = strict tenant isolation, leveraging the composite
73
+ // idx_memories_tenant_created (leading column tenant_id, O(log n) lookup).
74
+ const tenantPredicate = tenantId !== undefined ? ` AND m.tenant_id = ?` : '';
75
+ const tenantPredicateNoAlias = tenantId !== undefined ? ` AND tenant_id = ?` : '';
76
+ const tenantOnlyPredicate = tenantId !== undefined ? ` WHERE tenant_id = ?` : '';
77
+ const tenantParams = tenantId !== undefined ? [tenantId] : [];
78
+ // v1.12.6 — belt-and-suspenders against `kind='archived'` leaking into recall.
79
+ // `kind='archived'` is a transient sentinel inside `archiveRawMemory`'s
80
+ // SAVEPOINT (src/raw-archive.ts:56): UPDATE kind = 'archived' immediately
81
+ // followed by DELETE, both inside one savepoint that commits or rolls back
82
+ // atomically. SQLite atomicity guarantees no concurrent reader sees the
83
+ // intermediate state. This filter is defensive-only against:
84
+ // (a) future bugs that drop the SAVEPOINT,
85
+ // (b) future bugs that introduce kind='archived' as a persisted state,
86
+ // (c) external direct-SQL writes that bypass archiveRawMemory.
87
+ // tenantOnlyPredicate starts with " WHERE tenant_id = ?" when tenant is set;
88
+ // when unset, we have no WHERE yet, so the archived clause needs both AND
89
+ // and WHERE forms. The "tenant-only" path always has WHERE (from tenant or
90
+ // we synthesize one).
91
+ const archivedClauseAlias = ` AND m.kind != 'archived'`;
92
+ const archivedClauseNoAlias = ` AND kind != 'archived'`;
93
+ // For the "tenant-only" path: if no tenant set, tenantOnlyPredicate is '',
94
+ // so prepend WHERE; if tenant set, append AND. handled in each call site
95
+ // by always joining `tenantOnlyPredicate + archivedClauseTenantOnly` where
96
+ // the latter switches between " AND" and " WHERE" based on caller context.
97
+ const archivedClauseTenantOnly = tenantId !== undefined ? ` AND kind != 'archived'` : ` WHERE kind != 'archived'`;
98
+ const aliasScope = withProject(recallScopeClause('m.', scopeFilter), 'm.', originProject);
99
+ const plainScope = withProject(recallScopeClause('', scopeFilter), '', originProject);
100
+ const scopeParams = aliasScope.params;
101
+ const currentAlias = includeSuperseded ? '' : ' AND m.superseded_by IS NULL';
102
+ const currentNoAlias = includeSuperseded ? '' : ' AND superseded_by IS NULL';
103
+ return {
104
+ tenantPredicate, tenantPredicateNoAlias, tenantOnlyPredicate, tenantParams,
105
+ archivedClauseAlias, archivedClauseNoAlias, archivedClauseTenantOnly,
106
+ aliasScope, plainScope, scopeParams, currentAlias, currentNoAlias,
107
+ };
108
+ }
109
+ /** Every admitted row, oldest first; the no-terms path and the last-resort fallback share it. */
110
+ function selectAllCandidates(db, p, limit) {
111
+ const sql = `SELECT ${MEMORY_SELECT_COLUMNS} FROM memories${p.tenantOnlyPredicate}${p.archivedClauseTenantOnly}${p.plainScope.sql}${p.currentNoAlias} ORDER BY created ASC, id ASC LIMIT ?`;
112
+ // SAFETY: sql selects exactly MEMORY_SELECT_COLUMNS, whose column list
113
+ // matches MemoryRow's field set.
114
+ return db.prepare(sql).all(...p.tenantParams, ...p.scopeParams, limit);
115
+ }
116
+ /** FTS5 bm25 matches; empty when none match or FTS5 cannot run the query. */
117
+ function selectFtsCandidates(db, terms, p, limit) {
118
+ try {
119
+ const ftsQuery = terms.map((t) => `"${t.replace(/"/g, '""')}"`).join(' OR ');
120
+ // memories_fts virtual table has no tenant_id column; filter via the
121
+ // joined memories row (cheap with idx_memories_tenant_created leading
122
+ // on tenant_id).
123
+ // F1 (v1.7.0): MEMORY_SEARCH_COLUMNS adds bm25_score as the trailing
124
+ // result column. Every other column is m.<col> AS <col> so rowToEntry
125
+ // sees the same shape it always has.
126
+ // SAFETY: MEMORY_SEARCH_COLUMNS aliases every column to the same name
127
+ // MEMORY_SELECT_COLUMNS uses (plus bm25_score), matching MemoryRow.
128
+ return db.prepare(`
129
+ SELECT ${MEMORY_SEARCH_COLUMNS}
130
+ FROM memories m
131
+ JOIN memories_fts f ON f.id = m.id
132
+ WHERE memories_fts MATCH ?${p.tenantPredicate}${p.archivedClauseAlias}${p.aliasScope.sql}${p.currentAlias}
133
+ ORDER BY bm25(memories_fts), m.updated_at DESC, m.content ASC, m.id ASC
134
+ LIMIT ?
135
+ `).all(ftsQuery, ...p.tenantParams, ...p.scopeParams, limit);
136
+ }
137
+ catch (err) {
138
+ // A query FTS5 cannot parse is expected input; anything else means the index itself is broken.
139
+ const message = err instanceof Error ? err.message : String(err);
140
+ if (!FTS_QUERY_SYNTAX_RE.test(message))
141
+ log.once('fts-match-fallback', 'warn', `FTS search failed, using the slower LIKE match: ${message}`);
142
+ return [];
143
+ }
144
+ }
145
+ function selectLikeCandidates(db, terms, p, limit) {
146
+ const escapeLike = (term) => term.replace(/[%_\\]/g, '\\$&');
147
+ const where = terms.map(() => `(LOWER(content) LIKE ? ESCAPE '\\' OR LOWER(tags_json) LIKE ? ESCAPE '\\')`).join(' OR ');
148
+ const params = terms.flatMap((term) => {
149
+ const like = `%${escapeLike(term)}%`;
150
+ return [like, like];
151
+ });
152
+ // SAFETY: this query selects exactly MEMORY_SELECT_COLUMNS, matching
153
+ // MemoryRow's field set.
154
+ return db.prepare(`
155
+ SELECT ${MEMORY_SELECT_COLUMNS}
156
+ FROM memories
157
+ WHERE (${where})${p.tenantPredicateNoAlias}${p.archivedClauseNoAlias}${p.plainScope.sql}${p.currentNoAlias}
158
+ ORDER BY updated_at DESC, created DESC, content ASC, id ASC
159
+ LIMIT ?
160
+ `).all(...params, ...p.tenantParams, ...p.scopeParams, limit);
161
+ }
162
+ /**
163
+ * Load likely search candidates directly from SQLite.
164
+ * Uses FTS5 when available, falls back to LIKE matching, then full-store fallback.
165
+ *
166
+ * When `tenantId` is provided, every SELECT (FTS join, LIKE, fallback) filters
167
+ * by tenant_id. Cross-tenant memories never surface. Omitted = no filter.
168
+ */
169
+ export function loadSearchEntries(hippoRoot, query, limit = DEFAULT_SEARCH_CANDIDATE_LIMIT, tenantId) {
170
+ const db = openStore(hippoRoot);
171
+ try {
172
+ return loadSearchRows(db, query, limit, tenantId).map(rowToEntry);
173
+ }
174
+ finally {
175
+ closeHippoDb(db);
176
+ }
177
+ }
178
+ /**
179
+ * v1.7.1 — recall-mode loader. Pushes the recall-side scope predicate into
180
+ * SQL so `unknown:legacy` cannot leak via any consumer that hasn't remembered
181
+ * to re-filter (root-cause-over-patches: codex flagged this on v1.6.5 review).
182
+ *
183
+ * - `requestedScope` undefined / '': default-deny on `unknown:legacy`.
184
+ * - `requestedScope` non-empty string: exact match on `m.scope = requestedScope`.
185
+ *
186
+ * Private-scope (`<source>:private:*`) exclusion: SQL applies a conservative
187
+ * pre-window approximation (`NOT LIKE '%:private:%'`, v1.25.0 — codex P2:
188
+ * post-window-only filtering let private rows starve admitted candidates out
189
+ * of the LIMIT window); the exact anchored regex
190
+ * (`passesScopeFilterForRecall`) remains the authoritative JS post-filter in
191
+ * the recall consumers.
192
+ *
193
+ * Consumers: `api.recall` (v1.7.1+), `cmdRecall`/`cmdExplain` direct CLI paths
194
+ * and `searchBothHybrid` recall mode (v1.25.0). Background pipelines
195
+ * (`consolidate`, `embeddings`, `refine-llm`, ...) keep using
196
+ * `loadSearchEntries` so they can see quarantined rows when needed.
197
+ *
198
+ * `tenantId` widened to optional in v1.25.0 for the searchBothHybrid recall
199
+ * mode (its `tenantId` option is optional); `loadSearchRows` already treats
200
+ * undefined as "no tenant filter" for legacy callers.
201
+ */
202
+ export function loadRecallSearchEntries(hippoRoot, query, limit = DEFAULT_SEARCH_CANDIDATE_LIMIT, tenantId, requestedScope, explicitScopeMode = 'exact', includeSuperseded = true, originProject) {
203
+ const db = openStore(hippoRoot);
204
+ try {
205
+ return loadRecallSearchEntriesFromDb(db, query, limit, tenantId, requestedScope, explicitScopeMode, includeSuperseded, originProject);
206
+ }
207
+ finally {
208
+ closeHippoDb(db);
209
+ }
210
+ }
211
+ // Split out so callers with an already-open db (Z1 prompt-recall path) skip
212
+ // the initStore+open/close cycle per store per call.
213
+ export function loadRecallSearchEntriesFromDb(db, query, limit = DEFAULT_SEARCH_CANDIDATE_LIMIT, tenantId, requestedScope, explicitScopeMode = 'exact', includeSuperseded = true, originProject) {
214
+ return loadSearchRows(db, query, limit, tenantId, recallScopeFilter(requestedScope, explicitScopeMode), includeSuperseded, originProject).map(rowToEntry);
215
+ }
216
+ /** The rows nearest `queryVector` that pass `spec`, nearest first. */
217
+ export function loadVectorCandidateEntries(hippoRoot, queryVector, spec) {
218
+ const scope = recallScopeClause('m.', spec.scope);
219
+ const tenant = spec.tenantId !== undefined ? ' AND m.tenant_id = ?' : '';
220
+ const current = spec.includeSuperseded ? '' : ' AND m.superseded_by IS NULL';
221
+ const params = [...(spec.tenantId !== undefined ? [spec.tenantId] : []), ...scope.params];
222
+ const db = openStore(hippoRoot);
223
+ try {
224
+ const matches = topVectorMatches(db, queryVector, spec.limit ?? 50, `${tenant} AND m.kind != 'archived'${scope.sql}${current}`, params);
225
+ if (matches.length === 0)
226
+ return [];
227
+ // SAFETY: the SELECT names exactly MEMORY_SELECT_COLUMNS, matching MemoryRow's field set.
228
+ const rows = db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories WHERE id IN (${matches.map(() => '?').join(', ')})`)
229
+ .all(...matches.map((m) => m.id));
230
+ const byId = new Map(rows.map((r) => [r.id, rowToEntry(r)]));
231
+ return matches.flatMap((m) => byId.get(m.id) ?? []);
232
+ }
233
+ finally {
234
+ closeHippoDb(db);
235
+ }
236
+ }
237
+ /** Rarest-K prompt terms for this connection's FTS index, as a space-joined query string.
238
+ * Without FTS, returns the first 32 terms, as before rarest-term selection. */
239
+ export function pickRarestFtsQuery(db, terms, maxTerms = RAREST_TERM_COUNT) {
240
+ // The LIKE path has no bm25 ranking to bound, so it keeps the pre-rarest 32-term query.
241
+ if (!isFtsAvailable(db))
242
+ return terms.slice(0, 32).join(' ');
243
+ db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS temp.z1_rarest_vocab USING fts5vocab(main, 'memories_fts', 'row')`);
244
+ // unicode61 splits `journal_mode` into two vocab terms; a term's count is its rarest part's (an upper bound).
245
+ const partsOf = (t) => t.split(/[^\p{L}\p{N}]+/u).filter(Boolean);
246
+ const vocab = Array.from(new Set(terms.flatMap(partsOf)));
247
+ if (vocab.length === 0)
248
+ return '';
249
+ // SAFETY: rows' shape matches the two columns named in the SELECT.
250
+ const rows = db
251
+ .prepare(`SELECT term, doc FROM temp.z1_rarest_vocab WHERE term IN (${vocab.map(() => '?').join(', ')})`)
252
+ .all(...vocab);
253
+ const counts = new Map(rows.map((r) => [r.term, r.doc]));
254
+ const docCount = (t) => {
255
+ const parts = partsOf(t);
256
+ return parts.length === 0 ? 0 : Math.min(...parts.map((x) => counts.get(x) ?? 0));
257
+ };
258
+ return rarestPromptTerms(terms, docCount, maxTerms).join(' ');
259
+ }
260
+ //# sourceMappingURL=search-rows.js.map
@@ -0,0 +1,83 @@
1
+ import { type TaskSnapshot, type SessionEvent } from './rows.js';
2
+ export declare function saveActiveTaskSnapshot(hippoRoot: string, tenantId: string, snapshot: {
3
+ task: string;
4
+ summary: string;
5
+ next_step: string;
6
+ source?: string;
7
+ session_id?: string | null;
8
+ scope?: string | null;
9
+ }): TaskSnapshot;
10
+ export declare function loadActiveTaskSnapshot(hippoRoot: string, tenantId: string): TaskSnapshot | null;
11
+ /**
12
+ * Default freshness bound for AMBIENT active-task-snapshot reads (DF1,
13
+ * docs/plans/2026-08-23-df1-snapshot-lifecycle.md): 72h, chosen over 48h so
14
+ * a Friday-evening orphan still offers continuity on Monday morning.
15
+ * Exported so callers can override via `loadFreshActiveTaskSnapshot`'s
16
+ * `opts.maxAgeMs`; deliberately no env knob (Simplicity First).
17
+ */
18
+ export declare const SNAPSHOT_AMBIENT_MAX_AGE_MS: number;
19
+ /**
20
+ * Bounded read for AMBIENT active-task-snapshot surfaces (UserPromptSubmit
21
+ * hook context, MCP recall block) — the never-expires fix for DF1. A
22
+ * snapshot written by `hippo pre-compact` has no death path tied to the
23
+ * session that owns it, so an orphaned row would otherwise inject into
24
+ * every prompt of every later session forever. Wraps `loadActiveTaskSnapshot`
25
+ * (unchanged, still the source of truth for explicit continuity surfaces),
26
+ * then applies, in order:
27
+ *
28
+ * 1. Owner match — ONLY when both `opts.sessionId` and the snapshot's
29
+ * `session_id` are non-null, non-empty strings and strictly equal
30
+ * (`===`). Owner reads are unbounded: the session that owns the snapshot
31
+ * can always see its own working state, regardless of age.
32
+ * 2. Age check — everything else, including absent-vs-absent ids. A
33
+ * null/undefined/empty id on EITHER side never counts as an owner match;
34
+ * it falls through here instead. (`runPreCompact` can legitimately save a
35
+ * snapshot with `session_id = null`; a null-equals-null "match" would
36
+ * reopen indefinite ambient injection for exactly those rows.) Returns
37
+ * the snapshot only when `age(updated_at) <= maxAgeMs` (default
38
+ * `SNAPSHOT_AMBIENT_MAX_AGE_MS`); otherwise null.
39
+ *
40
+ * No SQL change — age derives from the existing `updated_at` column.
41
+ */
42
+ export declare function loadFreshActiveTaskSnapshot(hippoRoot: string, tenantId: string, opts?: {
43
+ maxAgeMs?: number;
44
+ sessionId?: string | null;
45
+ }): TaskSnapshot | null;
46
+ export declare function clearActiveTaskSnapshot(hippoRoot: string, tenantId: string, clearedStatus?: string): boolean;
47
+ /**
48
+ * Close the `active` task snapshot(s) owned by `sessionId`, for the T3
49
+ * session-end death path (DF1, docs/plans/2026-08-23-df1-snapshot-lifecycle.md).
50
+ * Only one `active` row exists per tenant in practice (supersession happens
51
+ * at save), but the WHERE clause scopes on `session_id` too — not just
52
+ * `status='active' AND tenant_id=?` — so an ending session can never close a
53
+ * different, newer session's active snapshot. Returns the number of rows
54
+ * closed (0 when no active row is owned by `sessionId`).
55
+ */
56
+ export declare function closeTaskSnapshotsForSession(hippoRoot: string, tenantId: string, sessionId: string, status?: string): number;
57
+ export declare function appendSessionEvent(hippoRoot: string, tenantId: string, event: {
58
+ session_id: string;
59
+ event_type: string;
60
+ content: string;
61
+ task?: string | null;
62
+ source?: string;
63
+ scope?: string | null;
64
+ metadata?: Record<string, unknown>;
65
+ }): SessionEvent;
66
+ export declare function listSessionEvents(hippoRoot: string, tenantId: string, options?: {
67
+ session_id?: string;
68
+ task?: string;
69
+ limit?: number;
70
+ }): SessionEvent[];
71
+ /**
72
+ * Return session_ids with a `session_complete` event newer than `sinceMs`.
73
+ * Used by the sleep auto-promotion pass to bound scanning to a fixed window.
74
+ */
75
+ export declare function findPromotableSessions(hippoRoot: string, tenantId: string, sinceMs: number): Array<{
76
+ session_id: string;
77
+ }>;
78
+ /**
79
+ * Idempotency guard — true if a trace-layer memory with this source_session_id
80
+ * already exists.
81
+ */
82
+ export declare function traceExistsForSession(hippoRoot: string, tenantId: string, session_id: string): boolean;
83
+ //# sourceMappingURL=sessions.d.ts.map
@@ -0,0 +1,272 @@
1
+ import { closeHippoDb } from '../db.js';
2
+ import { assertTenantId } from '../tenant.js';
3
+ import { redactSecretsStrict } from '../secret-detect.js';
4
+ import { rowToTaskSnapshot, rowToSessionEvent, } from './rows.js';
5
+ import { writeActiveTaskMirror, removeActiveTaskMirror, writeRecentSessionMirror } from './mirrors.js';
6
+ import { openStore } from './open.js';
7
+ export function saveActiveTaskSnapshot(hippoRoot, tenantId, snapshot) {
8
+ assertTenantId('saveActiveTaskSnapshot', tenantId);
9
+ const db = openStore(hippoRoot);
10
+ const now = new Date().toISOString();
11
+ try {
12
+ db.exec('BEGIN');
13
+ db.prepare(`UPDATE task_snapshots SET status = 'superseded', updated_at = ? WHERE status = 'active' AND tenant_id = ?`).run(now, tenantId);
14
+ const result = db.prepare(`
15
+ INSERT INTO task_snapshots(task, summary, next_step, status, source, session_id, scope, tenant_id, created_at, updated_at)
16
+ VALUES (?, ?, ?, 'active', ?, ?, ?, ?, ?, ?)
17
+ `).run(redactSecretsStrict(snapshot.task), redactSecretsStrict(snapshot.summary), redactSecretsStrict(snapshot.next_step), snapshot.source ?? 'cli', snapshot.session_id ?? null, snapshot.scope ?? null, tenantId, now, now);
18
+ db.exec('COMMIT');
19
+ const id = Number(result.lastInsertRowid ?? 0);
20
+ // SAFETY: row's shape matches the ten columns named in the SELECT above.
21
+ const row = db.prepare(`
22
+ SELECT id, task, summary, next_step, status, source, session_id, scope, created_at, updated_at
23
+ FROM task_snapshots
24
+ WHERE id = ?
25
+ `).get(id);
26
+ if (!row) {
27
+ throw new Error('Failed to reload saved active task snapshot');
28
+ }
29
+ const loaded = rowToTaskSnapshot(row);
30
+ writeActiveTaskMirror(hippoRoot, tenantId, loaded);
31
+ return loaded;
32
+ }
33
+ catch (error) {
34
+ try {
35
+ db.exec('ROLLBACK');
36
+ }
37
+ catch {
38
+ // Ignore nested rollback failures.
39
+ }
40
+ throw error;
41
+ }
42
+ finally {
43
+ closeHippoDb(db);
44
+ }
45
+ }
46
+ export function loadActiveTaskSnapshot(hippoRoot, tenantId) {
47
+ assertTenantId('loadActiveTaskSnapshot', tenantId);
48
+ const db = openStore(hippoRoot);
49
+ try {
50
+ // SAFETY: row's shape matches the ten columns named in the SELECT above.
51
+ const row = db.prepare(`
52
+ SELECT id, task, summary, next_step, status, source, session_id, scope, created_at, updated_at
53
+ FROM task_snapshots
54
+ WHERE status = 'active' AND tenant_id = ?
55
+ ORDER BY updated_at DESC, id DESC
56
+ LIMIT 1
57
+ `).get(tenantId);
58
+ if (!row) {
59
+ removeActiveTaskMirror(hippoRoot, tenantId);
60
+ return null;
61
+ }
62
+ const loaded = rowToTaskSnapshot(row);
63
+ writeActiveTaskMirror(hippoRoot, tenantId, loaded);
64
+ return loaded;
65
+ }
66
+ finally {
67
+ closeHippoDb(db);
68
+ }
69
+ }
70
+ /**
71
+ * Default freshness bound for AMBIENT active-task-snapshot reads (DF1,
72
+ * docs/plans/2026-08-23-df1-snapshot-lifecycle.md): 72h, chosen over 48h so
73
+ * a Friday-evening orphan still offers continuity on Monday morning.
74
+ * Exported so callers can override via `loadFreshActiveTaskSnapshot`'s
75
+ * `opts.maxAgeMs`; deliberately no env knob (Simplicity First).
76
+ */
77
+ export const SNAPSHOT_AMBIENT_MAX_AGE_MS = 72 * 60 * 60 * 1000;
78
+ /** A usable session id: non-null, non-empty string. Named predicate (not an
79
+ * inline `typeof` check) so the owner-match rule in
80
+ * `loadFreshActiveTaskSnapshot` states its contract once. */
81
+ function isNonEmptySessionId(value) {
82
+ return typeof value === 'string' && value.length > 0;
83
+ }
84
+ /**
85
+ * Bounded read for AMBIENT active-task-snapshot surfaces (UserPromptSubmit
86
+ * hook context, MCP recall block) — the never-expires fix for DF1. A
87
+ * snapshot written by `hippo pre-compact` has no death path tied to the
88
+ * session that owns it, so an orphaned row would otherwise inject into
89
+ * every prompt of every later session forever. Wraps `loadActiveTaskSnapshot`
90
+ * (unchanged, still the source of truth for explicit continuity surfaces),
91
+ * then applies, in order:
92
+ *
93
+ * 1. Owner match — ONLY when both `opts.sessionId` and the snapshot's
94
+ * `session_id` are non-null, non-empty strings and strictly equal
95
+ * (`===`). Owner reads are unbounded: the session that owns the snapshot
96
+ * can always see its own working state, regardless of age.
97
+ * 2. Age check — everything else, including absent-vs-absent ids. A
98
+ * null/undefined/empty id on EITHER side never counts as an owner match;
99
+ * it falls through here instead. (`runPreCompact` can legitimately save a
100
+ * snapshot with `session_id = null`; a null-equals-null "match" would
101
+ * reopen indefinite ambient injection for exactly those rows.) Returns
102
+ * the snapshot only when `age(updated_at) <= maxAgeMs` (default
103
+ * `SNAPSHOT_AMBIENT_MAX_AGE_MS`); otherwise null.
104
+ *
105
+ * No SQL change — age derives from the existing `updated_at` column.
106
+ */
107
+ export function loadFreshActiveTaskSnapshot(hippoRoot, tenantId, opts = {}) {
108
+ const snapshot = loadActiveTaskSnapshot(hippoRoot, tenantId);
109
+ if (!snapshot)
110
+ return null;
111
+ const callerSessionId = opts.sessionId;
112
+ const isOwnerMatch = isNonEmptySessionId(callerSessionId) &&
113
+ isNonEmptySessionId(snapshot.session_id) &&
114
+ callerSessionId === snapshot.session_id;
115
+ if (isOwnerMatch)
116
+ return snapshot;
117
+ const maxAgeMs = opts.maxAgeMs ?? SNAPSHOT_AMBIENT_MAX_AGE_MS;
118
+ const ageMs = Date.now() - Date.parse(snapshot.updated_at);
119
+ return ageMs <= maxAgeMs ? snapshot : null;
120
+ }
121
+ export function clearActiveTaskSnapshot(hippoRoot, tenantId, clearedStatus = 'cleared') {
122
+ assertTenantId('clearActiveTaskSnapshot', tenantId);
123
+ const db = openStore(hippoRoot);
124
+ const now = new Date().toISOString();
125
+ try {
126
+ // SAFETY: active's shape matches the single `id` column selected above.
127
+ const active = db.prepare(`SELECT id FROM task_snapshots WHERE status = 'active' AND tenant_id = ? ORDER BY updated_at DESC, id DESC LIMIT 1`).get(tenantId);
128
+ if (!active?.id) {
129
+ removeActiveTaskMirror(hippoRoot, tenantId);
130
+ return false;
131
+ }
132
+ db.prepare(`UPDATE task_snapshots SET status = ?, updated_at = ? WHERE id = ? AND tenant_id = ?`).run(clearedStatus, now, active.id, tenantId);
133
+ removeActiveTaskMirror(hippoRoot, tenantId);
134
+ return true;
135
+ }
136
+ finally {
137
+ closeHippoDb(db);
138
+ }
139
+ }
140
+ /**
141
+ * Close the `active` task snapshot(s) owned by `sessionId`, for the T3
142
+ * session-end death path (DF1, docs/plans/2026-08-23-df1-snapshot-lifecycle.md).
143
+ * Only one `active` row exists per tenant in practice (supersession happens
144
+ * at save), but the WHERE clause scopes on `session_id` too — not just
145
+ * `status='active' AND tenant_id=?` — so an ending session can never close a
146
+ * different, newer session's active snapshot. Returns the number of rows
147
+ * closed (0 when no active row is owned by `sessionId`).
148
+ */
149
+ export function closeTaskSnapshotsForSession(hippoRoot, tenantId, sessionId, status = 'session-ended') {
150
+ assertTenantId('closeTaskSnapshotsForSession', tenantId);
151
+ const db = openStore(hippoRoot);
152
+ const now = new Date().toISOString();
153
+ try {
154
+ const result = db.prepare(`UPDATE task_snapshots SET status = ?, updated_at = ? WHERE status = 'active' AND tenant_id = ? AND session_id = ?`).run(status, now, tenantId, sessionId);
155
+ return Number(result.changes ?? 0);
156
+ }
157
+ finally {
158
+ closeHippoDb(db);
159
+ }
160
+ }
161
+ export function appendSessionEvent(hippoRoot, tenantId, event) {
162
+ assertTenantId('appendSessionEvent', tenantId);
163
+ const db = openStore(hippoRoot);
164
+ const now = new Date().toISOString();
165
+ // v1.2: scope is wired through. Default-deny in api.recall + cmdRecall
166
+ // continuity reads applies to slack:private:* and 'unknown:legacy' rows.
167
+ try {
168
+ const result = db.prepare(`
169
+ INSERT INTO session_events(session_id, task, event_type, content, source, scope, metadata_json, tenant_id, created_at)
170
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
171
+ `).run(event.session_id, event.task ?? null, event.event_type, event.content, event.source ?? 'cli', event.scope ?? null, JSON.stringify(event.metadata ?? {}), tenantId, now);
172
+ const id = Number(result.lastInsertRowid ?? 0);
173
+ // SAFETY: row's shape matches the nine columns named in the SELECT
174
+ // above.
175
+ const row = db.prepare(`
176
+ SELECT id, session_id, task, event_type, content, source, scope, metadata_json, created_at
177
+ FROM session_events
178
+ WHERE id = ?
179
+ `).get(id);
180
+ if (!row) {
181
+ throw new Error('Failed to reload saved session event');
182
+ }
183
+ const loaded = rowToSessionEvent(row);
184
+ // SAFETY: recentRows' shape matches the nine columns named in the
185
+ // SELECT above.
186
+ const recentRows = db.prepare(`
187
+ SELECT id, session_id, task, event_type, content, source, scope, metadata_json, created_at
188
+ FROM session_events
189
+ WHERE session_id = ? AND tenant_id = ?
190
+ ORDER BY created_at DESC, id DESC
191
+ LIMIT ?
192
+ `).all(loaded.session_id, tenantId, 20);
193
+ const recent = recentRows.map(rowToSessionEvent).reverse();
194
+ writeRecentSessionMirror(hippoRoot, tenantId, recent);
195
+ return loaded;
196
+ }
197
+ finally {
198
+ closeHippoDb(db);
199
+ }
200
+ }
201
+ export function listSessionEvents(hippoRoot, tenantId, options = {}) {
202
+ assertTenantId('listSessionEvents', tenantId);
203
+ const db = openStore(hippoRoot);
204
+ try {
205
+ const clauses = ['tenant_id = ?'];
206
+ const params = [tenantId];
207
+ if (options.session_id) {
208
+ clauses.push('session_id = ?');
209
+ params.push(options.session_id);
210
+ }
211
+ if (options.task) {
212
+ clauses.push('task = ?');
213
+ params.push(options.task);
214
+ }
215
+ const limit = Math.max(1, Math.trunc(options.limit ?? 8));
216
+ params.push(limit);
217
+ const where = `WHERE ${clauses.join(' AND ')}`;
218
+ // SAFETY: rows' shape matches the nine columns named in the SELECT
219
+ // above.
220
+ const rows = db.prepare(`
221
+ SELECT id, session_id, task, event_type, content, source, scope, metadata_json, created_at
222
+ FROM session_events
223
+ ${where}
224
+ ORDER BY created_at DESC, id DESC
225
+ LIMIT ?
226
+ `).all(...params);
227
+ return rows.map(rowToSessionEvent).reverse();
228
+ }
229
+ finally {
230
+ closeHippoDb(db);
231
+ }
232
+ }
233
+ /**
234
+ * Return session_ids with a `session_complete` event newer than `sinceMs`.
235
+ * Used by the sleep auto-promotion pass to bound scanning to a fixed window.
236
+ */
237
+ export function findPromotableSessions(hippoRoot, tenantId, sinceMs) {
238
+ assertTenantId('findPromotableSessions', tenantId);
239
+ const db = openStore(hippoRoot);
240
+ try {
241
+ // SAFETY: rows' shape matches the single `session_id` column selected
242
+ // above.
243
+ const rows = db.prepare(`
244
+ SELECT DISTINCT session_id FROM session_events
245
+ WHERE event_type = 'session_complete' AND created_at >= ? AND tenant_id = ?
246
+ `).all(new Date(sinceMs).toISOString(), tenantId);
247
+ return rows;
248
+ }
249
+ finally {
250
+ closeHippoDb(db);
251
+ }
252
+ }
253
+ /**
254
+ * Idempotency guard — true if a trace-layer memory with this source_session_id
255
+ * already exists.
256
+ */
257
+ export function traceExistsForSession(hippoRoot, tenantId, session_id) {
258
+ assertTenantId('traceExistsForSession', tenantId);
259
+ const db = openStore(hippoRoot);
260
+ try {
261
+ const row = db.prepare(`
262
+ SELECT 1 FROM memories
263
+ WHERE source_session_id = ? AND layer = 'trace' AND tenant_id = ?
264
+ LIMIT 1
265
+ `).get(session_id, tenantId);
266
+ return !!row;
267
+ }
268
+ finally {
269
+ closeHippoDb(db);
270
+ }
271
+ }
272
+ //# sourceMappingURL=sessions.js.map