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
@@ -1,4 +1,4 @@
1
- import { type SessionTurn } from './capture.js';
1
+ import { type SessionTurn } from './capture/transcript.js';
2
2
  import { type MemoryEntry } from './memory.js';
3
3
  export declare const SESSION_DIGEST_TAG = "session-digest";
4
4
  /** Five-word runs are stock phrases; six in a row is a copied clause. */
@@ -2,15 +2,22 @@
2
2
  import { createHash } from 'crypto';
3
3
  import * as fs from 'fs';
4
4
  import * as path from 'path';
5
- import { collectSessionTurns, errorMessage, readTranscriptTail, splitSentences, } from './capture.js';
5
+ import { collectSessionTurns } from './capture/transcript.js';
6
+ import { splitSentences } from './capture/extract.js';
6
7
  import { isObjectLike, isStringValue } from './capture-contract.js';
7
8
  import { PATCH_SUCCESS_LINE, patchPaths, shellPatch } from './codex-patch.js';
8
9
  import { loadConfig } from './config.js';
10
+ import { errorMessage } from './log.js';
9
11
  import { createMemory, Layer } from './memory.js';
10
12
  import { RejectedValueError } from './rejection.js';
11
13
  import { maskEmails, redactSecretsStrict } from './secret-detect.js';
12
- import { SNAPSHOT_AMBIENT_MAX_AGE_MS, isInitialized, loadAllEntries, loadLatestHandoff, writeEntry } from './store.js';
14
+ import { isInitialized } from './store/open.js';
15
+ import { writeEntry } from './store/entry-writes.js';
16
+ import { loadAllEntries } from './store/entry-reads.js';
17
+ import { SNAPSHOT_AMBIENT_MAX_AGE_MS } from './store/sessions.js';
18
+ import { loadLatestHandoff } from './store/handoffs.js';
13
19
  import { isSyntheticMessage } from './token-ledger.js';
20
+ import { readTranscriptTail } from './transcript-tail.js';
14
21
  export const SESSION_DIGEST_TAG = 'session-digest';
15
22
  /** Five-word runs are stock phrases; six in a row is a copied clause. */
16
23
  export const ECHO_WINDOW = 6;
package/dist/shared.d.ts CHANGED
@@ -5,7 +5,9 @@
5
5
  * Local .hippo/ stores are per-project.
6
6
  */
7
7
  import { MemoryEntry } from './memory.js';
8
- import { SearchResult, type ResultCost } from './search.js';
8
+ import type { SearchResult, ResultCost } from './search/types.js';
9
+ import type { HybridVectorCandidates } from './search/vector.js';
10
+ import type { DatabaseSyncLike } from './db.js';
9
11
  /**
10
12
  * Returns the path to the global Hippo store.
11
13
  * Resolution order: $HIPPO_HOME > $XDG_DATA_HOME/hippo > ~/.hippo/
@@ -23,6 +25,7 @@ export declare function initGlobal(): void;
23
25
  export declare function promoteToGlobal(localRoot: string, id: string, opts?: {
24
26
  actor?: string;
25
27
  tenantId?: string;
28
+ afterWrite?: (db: DatabaseSyncLike, globalId: string) => void;
26
29
  }): MemoryEntry;
27
30
  export interface SearchOptions {
28
31
  budget?: number;
@@ -91,6 +94,14 @@ export interface HybridSearchOptions extends SearchOptions {
91
94
  * Async version of searchBoth that calls hybridSearch instead of search.
92
95
  */
93
96
  export declare function searchBothHybrid(query: string, localRoot: string, globalRoot: string, options?: HybridSearchOptions): Promise<SearchResult[]>;
97
+ /** Hybrid ranking of rows already loaded from each store: the local bump, one copy per text, then the shared budget. */
98
+ export declare function rankBothStores(query: string, roots: {
99
+ local: string;
100
+ global: string;
101
+ }, entries: {
102
+ local: MemoryEntry[];
103
+ global: MemoryEntry[];
104
+ }, vectorCandidates: HybridVectorCandidates, options?: HybridSearchOptions): Promise<SearchResult[]>;
94
105
  /** Tags whose rows only a hand-run share or promote may copy to the global store; derived rows inherit them. */
95
106
  export declare const NEVER_AUTO_SHARE_TAGS: ReadonlySet<string>;
96
107
  export declare function neverAutoShareTags(sources: readonly MemoryEntry[]): string[];
package/dist/shared.js CHANGED
@@ -9,9 +9,16 @@ import * as fs from 'fs';
9
9
  import * as path from 'path';
10
10
  import { generateId, COMPACTION_MEMORY_TAG } from './memory.js';
11
11
  import { AGENT_MEMORY_SOURCE_PREFIX, AGENT_MEMORY_TAGS } from './agent-memories/tools.js';
12
- import { initStore, loadAllEntries, loadIndex, loadSearchEntries, loadRecallSearchEntries, tallySources, writeEntry, readEntry, } from './store.js';
12
+ import { initStore } from './store/open.js';
13
+ import { writeEntry } from './store/entry-writes.js';
14
+ import { loadAllEntries, readEntry } from './store/entry-reads.js';
15
+ import { loadSearchEntries, loadRecallSearchEntries, recallScopeFilter } from './store/search-rows.js';
16
+ import { tallySources } from './store/candidates.js';
17
+ import { loadIndex } from './store/index-and-stats.js';
13
18
  import { passesScopeFilterForRecall, passesCliRecallScopeFilter } from './recall-scope.js';
14
- import { search, hybridSearch, fitBudget } from './search.js';
19
+ import { search } from './search/bm25-search.js';
20
+ import { hybridSearch } from './search/hybrid.js';
21
+ import { fitBudget } from './search/finalize.js';
15
22
  import { evalNow } from './ablation.js';
16
23
  import { deriveOriginProject, classifyOriginProject, resolveGlobalRootDir } from './project-identity.js';
17
24
  import { detectSecret } from './secret-detect.js';
@@ -77,7 +84,7 @@ export function promoteToGlobal(localRoot, id, opts) {
77
84
  source: `promoted:${localRoot}`,
78
85
  origin_project: entry.origin_project ?? deriveOriginProject(path.dirname(path.resolve(localRoot))),
79
86
  };
80
- writeEntry(globalRoot, globalEntry, { actor: opts?.actor });
87
+ writeEntry(globalRoot, globalEntry, { actor: opts?.actor, afterWrite: opts?.afterWrite });
81
88
  // Fire-and-forget: embedMemory gates on availability and never rejects.
82
89
  void embedMemory(globalRoot, globalEntry);
83
90
  return globalEntry;
@@ -141,13 +148,10 @@ export function searchBoth(query, localRoot, globalRoot, options = {}) {
141
148
  * Async version of searchBoth that calls hybridSearch instead of search.
142
149
  */
143
150
  export async function searchBothHybrid(query, localRoot, globalRoot, options = {}) {
144
- const { budget = 4000, now = evalNow(), embeddingWeight, explain, mmr, mmrLambda, localBump = 1.2, minResults, cost, scope, includeSuperseded, asOf, tenantId, summaryDeboost, summaryFreshness, entryFilter, recallScope } = options;
151
+ const { includeSuperseded, asOf, tenantId, entryFilter, recallScope } = options;
145
152
  // When an admission filter is active, lift the per-store candidate cap
146
153
  // (default 200): excluded rows matching the query could otherwise fill the
147
154
  // window before any admitted row is even loaded (codex gating round 6).
148
- // Only ambient-context query mode sets entryFilter, and that path is
149
- // interactive - never the per-turn pinned-only hook - so ranking the full
150
- // match set is acceptable.
151
155
  // 5000 = 25x the default 200-row window: large enough that exclusion
152
156
  // crowding is a non-issue on real stores, bounded so a common query term
153
157
  // on a 100k-row store cannot stall an interactive call by ranking every
@@ -166,27 +170,29 @@ export async function searchBothHybrid(query, localRoot, globalRoot, options = {
166
170
  ? loadRecallSearchEntries(root, query, searchWindow, tenantId, recallScope.requested, recallScope.additive ? 'additive' : 'exact', Boolean(includeSuperseded) || Boolean(asOf))
167
171
  : loadSearchEntries(root, query, searchWindow, tenantId);
168
172
  };
169
- let localEntries = loadEntries(localRoot);
170
- let globalEntries = loadEntries(globalRoot);
171
- if (recallScope) {
172
- const passes = (e) => recallScope.additive
173
- ? passesCliRecallScopeFilter(e.scope ?? null, recallScope.requested)
174
- : passesScopeFilterForRecall(e.scope ?? null, recallScope.requested);
175
- localEntries = localEntries.filter(passes);
176
- globalEntries = globalEntries.filter(passes);
177
- }
178
- if (entryFilter) {
179
- localEntries = localEntries.filter(entryFilter);
180
- globalEntries = globalEntries.filter(entryFilter);
181
- }
182
- if (localEntries.length === 0 && globalEntries.length === 0)
173
+ const passesScope = (e) => !recallScope || (recallScope.additive
174
+ ? passesCliRecallScopeFilter(e.scope ?? null, recallScope.requested)
175
+ : passesScopeFilterForRecall(e.scope ?? null, recallScope.requested));
176
+ const admit = (e) => passesScope(e) && (!entryFilter || entryFilter(e));
177
+ const localEntries = loadEntries(localRoot).filter(admit);
178
+ const globalEntries = loadEntries(globalRoot).filter(admit);
179
+ // The vector arm loads under the same SQL rules as loadEntries, then the same JS admission.
180
+ const vectorCandidates = {
181
+ tenantId,
182
+ scope: recallScope ? recallScopeFilter(recallScope.requested, recallScope.additive ? 'additive' : 'exact') : undefined,
183
+ includeSuperseded: !recallScope || Boolean(includeSuperseded) || Boolean(asOf),
184
+ admit,
185
+ };
186
+ return rankBothStores(query, { local: localRoot, global: globalRoot }, { local: localEntries, global: globalEntries }, vectorCandidates, options);
187
+ }
188
+ /** Hybrid ranking of rows already loaded from each store: the local bump, one copy per text, then the shared budget. */
189
+ export async function rankBothStores(query, roots, entries, vectorCandidates, options = {}) {
190
+ const { budget = 4000, now = evalNow(), embeddingWeight, explain, mmr, mmrLambda, localBump = 1.2, minResults, cost, scope, includeSuperseded, asOf, summaryDeboost, summaryFreshness } = options;
191
+ if (entries.local.length === 0 && entries.global.length === 0)
183
192
  return [];
184
- const localResults = await hybridSearch(query, localEntries, {
185
- budget, now, hippoRoot: localRoot, embeddingWeight, explain, mmr, mmrLambda, minResults, cost, scope, includeSuperseded, asOf, summaryDeboost, summaryFreshness,
186
- });
187
- const globalResults = await hybridSearch(query, globalEntries, {
188
- budget, now, hippoRoot: globalRoot, embeddingWeight, explain, mmr, mmrLambda, minResults, cost, scope, includeSuperseded, asOf, summaryDeboost, summaryFreshness,
189
- });
193
+ const shared = { budget, now, embeddingWeight, explain, mmr, mmrLambda, minResults, cost, scope, includeSuperseded, asOf, summaryDeboost, summaryFreshness, vectorCandidates };
194
+ const localResults = await hybridSearch(query, entries.local, { ...shared, hippoRoot: roots.local });
195
+ const globalResults = await hybridSearch(query, entries.global, { ...shared, hippoRoot: roots.global });
190
196
  // Tag global results. Local memories get a configurable priority bump.
191
197
  const tagged = [
192
198
  ...localResults.map((r) => ({
package/dist/skills.d.ts CHANGED
@@ -21,6 +21,7 @@
21
21
  * Lifecycle: active -> superseded (a newer version replaces it) or active ->
22
22
  * closed (retired). Export renders ACTIVE skills only.
23
23
  */
24
+ import { type KeysetPosition } from './keyset.js';
24
25
  export type SkillStatus = 'active' | 'superseded' | 'closed';
25
26
  export declare const VALID_SKILL_STATES: ReadonlySet<SkillStatus>;
26
27
  /** Field caps (untrusted at the HTTP/SDK boundary). instructions is a body, so a
@@ -66,6 +67,8 @@ export interface SaveSkillOpts {
66
67
  export interface ListSkillsOpts {
67
68
  status?: SkillStatus;
68
69
  limit?: number;
70
+ /** Resume after this row: the position the previous page ended on. */
71
+ after?: KeysetPosition;
69
72
  }
70
73
  /**
71
74
  * Create a skill (or a new version that supersedes an existing one). Writes the
package/dist/skills.js CHANGED
@@ -23,11 +23,12 @@
23
23
  */
24
24
  import { BadRequestError, ConflictError, NotFoundError } from './api-errors.js';
25
25
  import { openHippoDb, closeHippoDb } from './db.js';
26
- import { writeEntry } from './store.js';
26
+ import { writeEntry } from './store/entry-writes.js';
27
27
  import { assertTenantId } from './tenant.js';
28
28
  import { createMemory, Layer } from './memory.js';
29
29
  import { appendAuditEvent } from './audit.js';
30
30
  import { objectHalfLifeDays } from './half-life-migration.js';
31
+ import { keysetAfter } from './keyset.js';
31
32
  export const VALID_SKILL_STATES = new Set([
32
33
  'active',
33
34
  'superseded',
@@ -110,9 +111,76 @@ function buildSkillContent(skillName, instructions, trigger) {
110
111
  content += `\n\n${instructions}`;
111
112
  return content;
112
113
  }
113
- // ---------------------------------------------------------------------------
114
- // Public API
115
- // ---------------------------------------------------------------------------
114
+ // Preflight the supersede target BEFORE inserting the new row (so the new
115
+ // autoincrement id can never be its own supersede target); read the
116
+ // predecessor version in the same SELECT for server-derived versioning.
117
+ // Mirrors saveProcess / savePolicy (codex P1 2026-05-28).
118
+ function preflightSkillSupersede(db, tenantId, supersedesId) {
119
+ // SAFETY: row shape matches the `status, version` columns named in the SELECT below.
120
+ const pred = db.prepare(`SELECT status, version FROM skills WHERE id = ? AND tenant_id = ?`).get(supersedesId, tenantId);
121
+ if (!pred) {
122
+ throw new NotFoundError(`saveSkill: skill ${supersedesId} to supersede not found for tenant ${tenantId}`);
123
+ }
124
+ if (pred.status !== 'active') {
125
+ throw new ConflictError(`saveSkill: skill ${supersedesId} is not active (status='${pred.status}'); only active skills can be superseded.`);
126
+ }
127
+ return pred.version + 1;
128
+ }
129
+ function insertSkillRow(db, memoryId, w, version) {
130
+ const result = db.prepare(`
131
+ INSERT INTO skills(
132
+ memory_id, tenant_id, skill_name, instructions, trigger_text, version,
133
+ status, superseded_by, superseded_at, change_summary, closed_at, created_at
134
+ ) VALUES (?, ?, ?, ?, ?, ?, 'active', NULL, NULL, ?, NULL, ?)
135
+ `).run(memoryId, w.tenantId, w.name, w.instructions, w.trigger, version, w.changeSummary, w.now);
136
+ return Number(result.lastInsertRowid ?? 0);
137
+ }
138
+ function supersedeSkillRow(db, w, supersedesId, skillId, version) {
139
+ const sup = db.prepare(`
140
+ UPDATE skills
141
+ SET status = 'superseded', superseded_by = ?, superseded_at = ?
142
+ WHERE id = ? AND tenant_id = ? AND status = 'active' AND id != ?
143
+ `).run(skillId, w.now, supersedesId, w.tenantId, skillId);
144
+ if (sup.changes === 0) {
145
+ throw new ConflictError(`saveSkill: skill ${supersedesId} could not be superseded (no longer active or self-reference).`);
146
+ }
147
+ appendAuditEvent(db, {
148
+ tenantId: w.tenantId,
149
+ actor: w.actor,
150
+ op: 'skill_supersede',
151
+ targetId: String(supersedesId),
152
+ metadata: {
153
+ skill_id: supersedesId,
154
+ superseded_by: skillId,
155
+ new_version: version,
156
+ },
157
+ });
158
+ }
159
+ /** The afterWrite body: preflight, INSERT, supersede, reload, create audit, all in one SAVEPOINT. */
160
+ function writeSkillRow(db, memoryId, w) {
161
+ const version = w.supersedesId !== undefined ? preflightSkillSupersede(db, w.tenantId, w.supersedesId) : 1;
162
+ const skillId = insertSkillRow(db, memoryId, w, version);
163
+ if (w.supersedesId !== undefined)
164
+ supersedeSkillRow(db, w, w.supersedesId, skillId, version);
165
+ // SAFETY: row's shape matches the columns named in SKILL_COLS above.
166
+ const row = db.prepare(`SELECT ${SKILL_COLS} FROM skills WHERE id = ?`)
167
+ .get(skillId);
168
+ if (!row)
169
+ throw new Error('saveSkill: failed to reload saved skill row');
170
+ // GDPR-light metadata: ids + flags only, no skill text.
171
+ appendAuditEvent(db, {
172
+ tenantId: w.tenantId,
173
+ actor: w.actor,
174
+ op: 'skill_create',
175
+ targetId: String(skillId),
176
+ metadata: {
177
+ skill_id: skillId,
178
+ version,
179
+ has_trigger: w.trigger !== null,
180
+ },
181
+ });
182
+ return row;
183
+ }
116
184
  /**
117
185
  * Create a skill (or a new version that supersedes an existing one). Writes the
118
186
  * memory mirror + the skills row atomically inside writeEntry's SAVEPOINT. When
@@ -136,72 +204,21 @@ export function saveSkill(hippoRoot, tenantId, opts, actor = 'cli') {
136
204
  baseHalfLifeDays: objectHalfLifeDays(hippoRoot),
137
205
  tenantId,
138
206
  });
207
+ const w = {
208
+ tenantId,
209
+ actor,
210
+ name,
211
+ instructions: opts.instructions,
212
+ trigger,
213
+ changeSummary,
214
+ supersedesId: opts.supersedesSkillId,
215
+ now,
216
+ };
139
217
  let savedRow;
140
218
  writeEntry(hippoRoot, mem, {
141
219
  actor,
142
220
  afterWrite: (db, memoryId) => {
143
- // Preflight the supersede target BEFORE inserting the new row (so the new
144
- // autoincrement id can never be its own supersede target); read the
145
- // predecessor version in the same SELECT for server-derived versioning.
146
- // Mirrors saveProcess / savePolicy (codex P1 2026-05-28).
147
- let version = 1;
148
- if (opts.supersedesSkillId !== undefined) {
149
- // SAFETY: row shape matches the `status, version` columns named in the SELECT below.
150
- const pred = db.prepare(`SELECT status, version FROM skills WHERE id = ? AND tenant_id = ?`).get(opts.supersedesSkillId, tenantId);
151
- if (!pred) {
152
- throw new NotFoundError(`saveSkill: skill ${opts.supersedesSkillId} to supersede not found for tenant ${tenantId}`);
153
- }
154
- if (pred.status !== 'active') {
155
- throw new ConflictError(`saveSkill: skill ${opts.supersedesSkillId} is not active (status='${pred.status}'); only active skills can be superseded.`);
156
- }
157
- version = pred.version + 1;
158
- }
159
- const result = db.prepare(`
160
- INSERT INTO skills(
161
- memory_id, tenant_id, skill_name, instructions, trigger_text, version,
162
- status, superseded_by, superseded_at, change_summary, closed_at, created_at
163
- ) VALUES (?, ?, ?, ?, ?, ?, 'active', NULL, NULL, ?, NULL, ?)
164
- `).run(memoryId, tenantId, name, opts.instructions, trigger, version, changeSummary, now);
165
- const skillId = Number(result.lastInsertRowid ?? 0);
166
- if (opts.supersedesSkillId !== undefined) {
167
- const sup = db.prepare(`
168
- UPDATE skills
169
- SET status = 'superseded', superseded_by = ?, superseded_at = ?
170
- WHERE id = ? AND tenant_id = ? AND status = 'active' AND id != ?
171
- `).run(skillId, now, opts.supersedesSkillId, tenantId, skillId);
172
- if (sup.changes === 0) {
173
- throw new ConflictError(`saveSkill: skill ${opts.supersedesSkillId} could not be superseded (no longer active or self-reference).`);
174
- }
175
- appendAuditEvent(db, {
176
- tenantId,
177
- actor,
178
- op: 'skill_supersede',
179
- targetId: String(opts.supersedesSkillId),
180
- metadata: {
181
- skill_id: opts.supersedesSkillId,
182
- superseded_by: skillId,
183
- new_version: version,
184
- },
185
- });
186
- }
187
- // SAFETY: row's shape matches the columns named in SKILL_COLS above.
188
- const row = db.prepare(`SELECT ${SKILL_COLS} FROM skills WHERE id = ?`)
189
- .get(skillId);
190
- if (!row)
191
- throw new Error('saveSkill: failed to reload saved skill row');
192
- savedRow = row;
193
- // GDPR-light metadata: ids + flags only, no skill text.
194
- appendAuditEvent(db, {
195
- tenantId,
196
- actor,
197
- op: 'skill_create',
198
- targetId: String(skillId),
199
- metadata: {
200
- skill_id: skillId,
201
- version,
202
- has_trigger: trigger !== null,
203
- },
204
- });
221
+ savedRow = writeSkillRow(db, memoryId, w);
205
222
  },
206
223
  });
207
224
  if (!savedRow) {
@@ -278,6 +295,7 @@ export function loadSkillById(hippoRoot, tenantId, id) {
278
295
  export function loadSkills(hippoRoot, tenantId, opts = {}) {
279
296
  assertTenantId('loadSkills', tenantId);
280
297
  const limit = opts.limit ?? 100;
298
+ const after = keysetAfter('created_at', 'id', opts.after);
281
299
  const db = openHippoDb(hippoRoot);
282
300
  try {
283
301
  let rows;
@@ -288,19 +306,19 @@ export function loadSkills(hippoRoot, tenantId, opts = {}) {
288
306
  // SAFETY: rows' shape matches the columns named in SKILL_COLS above.
289
307
  rows = db.prepare(`
290
308
  SELECT ${SKILL_COLS} FROM skills
291
- WHERE tenant_id = ? AND status = ?
309
+ WHERE tenant_id = ? AND status = ?${after.sql}
292
310
  ORDER BY created_at DESC, id DESC
293
311
  LIMIT ?
294
- `).all(tenantId, opts.status, limit);
312
+ `).all(tenantId, opts.status, ...after.params, limit);
295
313
  }
296
314
  else {
297
315
  // SAFETY: rows' shape matches the columns named in SKILL_COLS above.
298
316
  rows = db.prepare(`
299
317
  SELECT ${SKILL_COLS} FROM skills
300
- WHERE tenant_id = ?
318
+ WHERE tenant_id = ?${after.sql}
301
319
  ORDER BY created_at DESC, id DESC
302
320
  LIMIT ?
303
- `).all(tenantId, limit);
321
+ `).all(tenantId, ...after.params, limit);
304
322
  }
305
323
  return rows.map(rowToSkill);
306
324
  }
package/dist/stdin.js CHANGED
@@ -1,6 +1,6 @@
1
+ import { envStdinWaitMs } from './env.js';
1
2
  function defaultWaitMs() {
2
- const parsed = Number.parseInt(process.env.HIPPO_STDIN_WAIT_MS ?? '', 10);
3
- return parsed > 0 ? parsed : 1000;
3
+ return envStdinWaitMs() ?? 1000;
4
4
  }
5
5
  /** Never blocks: a TTY resolves at once, otherwise waits up to `waitMs` of
6
6
  * idle (default 1000ms, or `HIPPO_STDIN_WAIT_MS`), refreshed on each chunk
@@ -0,0 +1,19 @@
1
+ import { openHippoDb } from '../db.js';
2
+ import { type AuditOp } from '../audit.js';
3
+ import { RejectedValueError } from '../rejection.js';
4
+ import type { JsonValue } from './rows.js';
5
+ /**
6
+ * Emit an audit event for a mutation against `db`. Wrapped so a broken audit
7
+ * log can never crash the surrounding mutation — the SQLite store is still the
8
+ * source of truth and audit failures are diagnosable from the missing rows.
9
+ */
10
+ export declare function audit(db: ReturnType<typeof openHippoDb>, op: AuditOp, targetId?: string, metadata?: Record<string, JsonValue>, actor?: string, tenantId?: string): void;
11
+ /**
12
+ * Refusal audit for the AT1 rejection guard (plan §3). Written by the
13
+ * transaction OWNER post-rollback — writeEntry's catch (no outer tx exists
14
+ * there, so this lands in a fresh implicit transaction) and api.supersede's
15
+ * catch (after its own ROLLBACK) — never inside a scope the caller's own
16
+ * rollback could claw back. Best-effort `audit()` semantics: never throws.
17
+ */
18
+ export declare function auditRejectionRefusal(db: ReturnType<typeof openHippoDb>, err: RejectedValueError, actor: string): void;
19
+ //# sourceMappingURL=audit-event.d.ts.map
@@ -0,0 +1,33 @@
1
+ import { resolveTenantId } from '../tenant.js';
2
+ import { appendAuditEvent, reportAuditWriteFailure } from '../audit.js';
3
+ /**
4
+ * Emit an audit event for a mutation against `db`. Wrapped so a broken audit
5
+ * log can never crash the surrounding mutation — the SQLite store is still the
6
+ * source of truth and audit failures are diagnosable from the missing rows.
7
+ */
8
+ export function audit(db, op, targetId, metadata, actor = 'cli', tenantId) {
9
+ try {
10
+ appendAuditEvent(db, {
11
+ tenantId: tenantId ?? resolveTenantId({}),
12
+ actor,
13
+ op,
14
+ targetId,
15
+ metadata,
16
+ });
17
+ }
18
+ catch (error) {
19
+ // The mutation has already succeeded; a broken audit table must not undo it.
20
+ reportAuditWriteFailure(op, String(error), targetId);
21
+ }
22
+ }
23
+ /**
24
+ * Refusal audit for the AT1 rejection guard (plan §3). Written by the
25
+ * transaction OWNER post-rollback — writeEntry's catch (no outer tx exists
26
+ * there, so this lands in a fresh implicit transaction) and api.supersede's
27
+ * catch (after its own ROLLBACK) — never inside a scope the caller's own
28
+ * rollback could claw back. Best-effort `audit()` semantics: never throws.
29
+ */
30
+ export function auditRejectionRefusal(db, err, actor) {
31
+ audit(db, 'reject_refusal', err.entryId, { digest: err.digest, reason: err.reason }, actor, err.tenantId);
32
+ }
33
+ //# sourceMappingURL=audit-event.js.map
@@ -0,0 +1,42 @@
1
+ import type { MemoryEntry, StrengthInputs } from '../memory.js';
2
+ export interface AmbientRecallRequest {
3
+ terms: string[];
4
+ limit: number;
5
+ }
6
+ export interface AmbientLoadResult {
7
+ entries: MemoryEntry[];
8
+ recall?: MemoryEntry[];
9
+ }
10
+ /** Exported so the plan test runs the exact SQL; idx_memories_pinned (db.ts v51) serves it. */
11
+ export declare const AMBIENT_PINNED_WHERE = "pinned = 1 AND superseded_by IS NULL AND tenant_id = ? ORDER BY created ASC, id ASC";
12
+ /** Exported so the plan test runs the exact SQL; idx_memories_created_drift (db.ts v51) serves it. */
13
+ export declare const AMBIENT_DRIFT_SQL = "SELECT 1 FROM memories WHERE superseded_by IS NULL AND tenant_id = ? AND (length(created) <> 24 OR created NOT LIKE '%Z') LIMIT 1";
14
+ export declare function loadAmbientCandidates(hippoRoot: string, tenantId: string, recentNeeded: number, admit: (e: MemoryEntry) => boolean, recall?: AmbientRecallRequest): AmbientLoadResult;
15
+ /** The rows a non-pinned context read may admit; each predicate is one getContext's admission applies again in JS. */
16
+ export interface ContextCandidateFilter {
17
+ /** Envelope scope asked for by name; absent applies recall's default deny. */
18
+ exactScope?: string;
19
+ /** Rows of this project and user-global rows pass; absent admits every origin. */
20
+ project?: string;
21
+ /** Most rows returned; past it, the rows decay has worn least win. */
22
+ cap: number;
23
+ now: Date;
24
+ }
25
+ /** Live tenant rows passing `filter`, at most `filter.cap`, in loadAllEntries' order; below the cap, every such row. */
26
+ export declare function loadContextCandidates(hippoRoot: string, tenantId: string, filter: ContextCandidateFilter): MemoryEntry[];
27
+ /** A row's strength inputs and tags, without its text or the JSON lists a full row parses. */
28
+ export type StrengthRow = StrengthInputs & Pick<MemoryEntry, 'tags'>;
29
+ /** Every tenant row as a StrengthRow, for whole-store health numbers; defaults match rowToEntry's. */
30
+ export declare function loadStrengthRows(hippoRoot: string, tenantId: string): StrengthRow[];
31
+ /** Text and source of tenant rows holding any of `words`; a row equal to a text apart from spacing holds its every word. */
32
+ export declare function loadTextsHoldingWords(hippoRoot: string, tenantId: string, words: readonly string[]): Array<Pick<MemoryEntry, 'content' | 'source'>>;
33
+ export interface SourceTally {
34
+ source: string;
35
+ count: number;
36
+ latest: string;
37
+ /** `created`, a unit separator, then `id` of the source's first row in loadAllEntries' order. */
38
+ first: string;
39
+ }
40
+ /** Row count and newest `created` per source, for peer listings that need no row; all tenants when `tenantId` is absent. */
41
+ export declare function tallySources(hippoRoot: string, tenantId?: string): SourceTally[];
42
+ //# sourceMappingURL=candidates.d.ts.map
@@ -0,0 +1,152 @@
1
+ import { closeHippoDb } from '../db.js';
2
+ import { RECALL_DEFAULT_DENY_SCOPES } from '../recall-scope.js';
3
+ import { MEMORY_SELECT_COLUMNS, rowToEntry, parseJsonArray } from './rows.js';
4
+ import { openStore } from './open.js';
5
+ import { pickRarestFtsQuery, loadRecallSearchEntriesFromDb } from './search-rows.js';
6
+ const AMBIENT_SCOPED = 'superseded_by IS NULL AND tenant_id = ?';
7
+ /** Exported so the plan test runs the exact SQL; idx_memories_pinned (db.ts v51) serves it. */
8
+ export const AMBIENT_PINNED_WHERE = `pinned = 1 AND ${AMBIENT_SCOPED} ORDER BY created ASC, id ASC`;
9
+ /** Exported so the plan test runs the exact SQL; idx_memories_created_drift (db.ts v51) serves it. */
10
+ export const AMBIENT_DRIFT_SQL = `SELECT 1 FROM memories WHERE ${AMBIENT_SCOPED} AND (length(created) <> 24 OR created NOT LIKE '%Z') LIMIT 1`;
11
+ // The pins plus the `recentNeeded` newest rows that pass `admit`, for ambient
12
+ // injection. One connection; `recall` piggybacks the Z1 FTS query on it too.
13
+ export function loadAmbientCandidates(hippoRoot, tenantId, recentNeeded, admit, recall) {
14
+ // A SQL LIMIT takes an integer; the Array.slice this replaced truncated one,
15
+ // and include_recent is any non-negative finite number at the HTTP edge.
16
+ const needed = Math.trunc(recentNeeded);
17
+ const db = openStore(hippoRoot);
18
+ try {
19
+ // SAFETY: every `where` below starts from MEMORY_SELECT_COLUMNS' table.
20
+ const run = (where, params) => db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories WHERE ${where}`).all(...params).map(rowToEntry);
21
+ const byId = new Map();
22
+ const scoped = AMBIENT_SCOPED;
23
+ for (const e of run(AMBIENT_PINNED_WHERE, [tenantId])) {
24
+ if (admit(e))
25
+ byId.set(e.id, e);
26
+ }
27
+ if (needed > 0) {
28
+ // Text order is chronological only for canonical UTC ISO (memory.ts).
29
+ const drifted = db.prepare(AMBIENT_DRIFT_SQL).get(tenantId) !== undefined;
30
+ // `id DESC` mirrors getContext's comparator, not loadFreshRawMemories'
31
+ // cross-ingest-stable order: that would change what the hook injects.
32
+ const window = Math.max(needed * 4, 32);
33
+ const windowed = drifted
34
+ ? []
35
+ : run(`${scoped} ORDER BY created DESC, id DESC LIMIT ?`, [tenantId, window]);
36
+ let kept = windowed.filter(admit);
37
+ if (drifted || (kept.length < needed && windowed.length === window)) {
38
+ kept = run(`${scoped} ORDER BY created DESC, id DESC`, [tenantId]).filter(admit);
39
+ }
40
+ for (const e of kept)
41
+ byId.set(e.id, e);
42
+ }
43
+ // loadAllEntries' order: rankedPinned's comparator can tie and Array.sort
44
+ // is stable, so input order is load-bearing downstream.
45
+ const entries = [...byId.values()].sort((a, b) => {
46
+ const byCreated = a.created.localeCompare(b.created);
47
+ return byCreated !== 0 ? byCreated : a.id.localeCompare(b.id);
48
+ });
49
+ if (!recall)
50
+ return { entries };
51
+ const ftsQuery = pickRarestFtsQuery(db, recall.terms);
52
+ const recallEntries = ftsQuery
53
+ ? loadRecallSearchEntriesFromDb(db, ftsQuery, recall.limit, tenantId, undefined, 'exact', false)
54
+ : [];
55
+ return { entries, recall: recallEntries };
56
+ }
57
+ finally {
58
+ closeHippoDb(db);
59
+ }
60
+ }
61
+ // calculateStrength's decay exponent with its reward factor, pins first: the strongest rows, without scoring each one in JS.
62
+ const DECAY_RANK_SQL = `pinned DESC,
63
+ CASE WHEN half_life_days > 0 THEN (julianday(?) - julianday(last_retrieved))
64
+ / (half_life_days * (1.0 + 0.5 * (COALESCE(outcome_positive, 0) - COALESCE(outcome_negative, 0))
65
+ / (COALESCE(outcome_positive, 0) + COALESCE(outcome_negative, 0) + 1.0))) END ASC NULLS LAST,
66
+ id ASC`;
67
+ /** Live tenant rows passing `filter`, at most `filter.cap`, in loadAllEntries' order; below the cap, every such row. */
68
+ export function loadContextCandidates(hippoRoot, tenantId, filter) {
69
+ const where = ['tenant_id = ?', `COALESCE(superseded_by, '') = ''`];
70
+ const params = [tenantId];
71
+ if (filter.exactScope) {
72
+ where.push('scope = ?');
73
+ params.push(filter.exactScope);
74
+ }
75
+ else {
76
+ // isRestrictedScope's rule; NOT LIKE folds ASCII case as its /:private:/i does.
77
+ where.push(`(scope IS NULL OR (scope NOT IN (${RECALL_DEFAULT_DENY_SCOPES.map(() => '?').join(', ')}) AND scope NOT LIKE '%:private:%'))`);
78
+ params.push(...RECALL_DEFAULT_DENY_SCOPES);
79
+ }
80
+ if (filter.project !== undefined) {
81
+ where.push(`(origin_project = '' OR origin_project = ?)`);
82
+ params.push(filter.project);
83
+ }
84
+ const db = openStore(hippoRoot);
85
+ try {
86
+ // SAFETY: the outer SELECT names exactly MEMORY_SELECT_COLUMNS, matching MemoryRow's field set; the rank sort carries ids only.
87
+ const rows = db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories WHERE id IN (
88
+ SELECT id FROM memories WHERE ${where.join(' AND ')} ORDER BY ${DECAY_RANK_SQL} LIMIT ?
89
+ ) ORDER BY created ASC, id ASC`).all(...params, filter.now.toISOString(), Math.max(0, Math.trunc(filter.cap)));
90
+ return rows.map(rowToEntry);
91
+ }
92
+ finally {
93
+ closeHippoDb(db);
94
+ }
95
+ }
96
+ /** Every tenant row as a StrengthRow, for whole-store health numbers; defaults match rowToEntry's. */
97
+ export function loadStrengthRows(hippoRoot, tenantId) {
98
+ const db = openStore(hippoRoot);
99
+ try {
100
+ // SAFETY: rows' shape matches the columns named in the SELECT below.
101
+ const rows = db.prepare(`SELECT pinned, created, last_retrieved, half_life_days, retrieval_count, emotional_valence, outcome_positive, outcome_negative, tags_json
102
+ FROM memories WHERE tenant_id = ?`).all(tenantId);
103
+ return rows.map((row) => ({
104
+ pinned: Boolean(row.pinned),
105
+ created: row.created,
106
+ last_retrieved: row.last_retrieved,
107
+ half_life_days: Number(row.half_life_days ?? 7),
108
+ retrieval_count: Number(row.retrieval_count ?? 0),
109
+ emotional_valence: row.emotional_valence ?? 'neutral',
110
+ outcome_positive: Number(row.outcome_positive ?? 0),
111
+ outcome_negative: Number(row.outcome_negative ?? 0),
112
+ tags: parseJsonArray(row.tags_json),
113
+ }));
114
+ }
115
+ finally {
116
+ closeHippoDb(db);
117
+ }
118
+ }
119
+ /** Text and source of tenant rows holding any of `words`; a row equal to a text apart from spacing holds its every word. */
120
+ export function loadTextsHoldingWords(hippoRoot, tenantId, words) {
121
+ const unique = [...new Set(words)];
122
+ const out = [];
123
+ const db = openStore(hippoRoot);
124
+ try {
125
+ // Chunked so one statement stays far under SQLite's bound-parameter limit.
126
+ for (let i = 0; i < unique.length; i += 200) {
127
+ const chunk = unique.slice(i, i + 200);
128
+ // SAFETY: rows' shape matches the two columns named in the SELECT below.
129
+ const rows = db.prepare(`SELECT content, source FROM memories WHERE tenant_id = ? AND (${chunk.map(() => 'instr(content, ?) > 0').join(' OR ')})`).all(tenantId, ...chunk);
130
+ for (const row of rows)
131
+ out.push({ content: row.content, source: row.source ?? 'cli' });
132
+ }
133
+ return out;
134
+ }
135
+ finally {
136
+ closeHippoDb(db);
137
+ }
138
+ }
139
+ /** Row count and newest `created` per source, for peer listings that need no row; all tenants when `tenantId` is absent. */
140
+ export function tallySources(hippoRoot, tenantId) {
141
+ const db = openStore(hippoRoot);
142
+ try {
143
+ const where = tenantId !== undefined ? 'WHERE tenant_id = ?' : '';
144
+ // SAFETY: rows' shape matches the four aliased columns in the SELECT below.
145
+ return db.prepare(`SELECT COALESCE(source, 'cli') AS source, COUNT(*) AS count, MAX(created) AS latest, MIN(created || char(31) || id) AS first
146
+ FROM memories ${where} GROUP BY COALESCE(source, 'cli')`).all(...(tenantId !== undefined ? [tenantId] : []));
147
+ }
148
+ finally {
149
+ closeHippoDb(db);
150
+ }
151
+ }
152
+ //# sourceMappingURL=candidates.js.map