hippo-memory 1.70.0 → 1.71.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 (629) hide show
  1. package/README.md +1 -1
  2. package/dist/agent-memories/claude-code.d.ts +4 -2
  3. package/dist/agent-memories/claude-code.js +14 -5
  4. package/dist/agent-memories/files.js +23 -12
  5. package/dist/agent-memories/markdown.d.ts +1 -3
  6. package/dist/agent-memories/markdown.js +1 -3
  7. package/dist/agent-memories/report.js +2 -1
  8. package/dist/agent-memories/sync.d.ts +4 -2
  9. package/dist/agent-memories/sync.js +10 -5
  10. package/dist/api/assemble.d.ts +7 -44
  11. package/dist/api/assemble.js +2 -22
  12. package/dist/api/audit.d.ts +5 -1
  13. package/dist/api/audit.js +9 -1
  14. package/dist/api/auth.d.ts +13 -22
  15. package/dist/api/auth.js +34 -24
  16. package/dist/api/auto-sleep.js +2 -2
  17. package/dist/api/availability.d.ts +2 -15
  18. package/dist/api/availability.js +2 -15
  19. package/dist/api/context-select.js +3 -4
  20. package/dist/api/context-types.d.ts +10 -35
  21. package/dist/api/context.d.ts +5 -22
  22. package/dist/api/context.js +21 -38
  23. package/dist/api/dormant.d.ts +5 -21
  24. package/dist/api/dormant.js +7 -26
  25. package/dist/api/drill-down.d.ts +7 -46
  26. package/dist/api/drill-down.js +5 -26
  27. package/dist/api/forget.d.ts +5 -24
  28. package/dist/api/forget.js +5 -28
  29. package/dist/api/graph.d.ts +8 -0
  30. package/dist/api/graph.js +7 -0
  31. package/dist/api/index.d.ts +2 -0
  32. package/dist/api/index.js +2 -0
  33. package/dist/api/instruction-detect.js +16 -5
  34. package/dist/api/ledger-db.d.ts +2 -1
  35. package/dist/api/ledger-db.js +5 -3
  36. package/dist/api/memories.d.ts +5 -0
  37. package/dist/api/memories.js +7 -0
  38. package/dist/api/objects.d.ts +9 -0
  39. package/dist/api/objects.js +11 -0
  40. package/dist/api/on-store.js +5 -3
  41. package/dist/api/predictions.d.ts +9 -0
  42. package/dist/api/predictions.js +18 -0
  43. package/dist/api/promote.d.ts +13 -17
  44. package/dist/api/promote.js +11 -19
  45. package/dist/api/prompt-hook.d.ts +4 -4
  46. package/dist/api/prompt-hook.js +10 -9
  47. package/dist/api/recall-cli.d.ts +55 -0
  48. package/dist/api/recall-cli.js +94 -0
  49. package/dist/api/recall-core.js +14 -6
  50. package/dist/api/recall-finish.d.ts +53 -0
  51. package/dist/api/recall-finish.js +30 -0
  52. package/dist/api/recall-history.d.ts +17 -84
  53. package/dist/api/recall-history.js +15 -88
  54. package/dist/api/recall-pipeline.d.ts +2 -3
  55. package/dist/api/recall-pipeline.js +16 -9
  56. package/dist/api/recall-types.d.ts +64 -304
  57. package/dist/api/recall.d.ts +5 -33
  58. package/dist/api/recall.js +59 -60
  59. package/dist/api/refine.d.ts +7 -0
  60. package/dist/api/refine.js +10 -0
  61. package/dist/api/remember-local.d.ts +57 -0
  62. package/dist/api/remember-local.js +90 -0
  63. package/dist/api/remember.d.ts +18 -1
  64. package/dist/api/remember.js +13 -1
  65. package/dist/api/sleep-run.d.ts +1 -3
  66. package/dist/api/sleep-run.js +17 -21
  67. package/dist/api/sleep.d.ts +9 -28
  68. package/dist/api/tokens.d.ts +3 -10
  69. package/dist/api/tokens.js +3 -10
  70. package/dist/api/types.d.ts +6 -29
  71. package/dist/api/types.js +4 -22
  72. package/dist/capture/command.d.ts +4 -12
  73. package/dist/capture/command.js +6 -22
  74. package/dist/capture/compact.d.ts +4 -15
  75. package/dist/capture/compact.js +16 -25
  76. package/dist/capture/compaction-record.js +101 -69
  77. package/dist/capture/compaction-spool.d.ts +1 -1
  78. package/dist/capture/compaction-spool.js +1 -1
  79. package/dist/capture/session-digest.d.ts +1 -1
  80. package/dist/capture/session-digest.js +13 -7
  81. package/dist/capture/transcript.d.ts +2 -10
  82. package/dist/capture/transcript.js +4 -18
  83. package/dist/cli/api-context.d.ts +3 -0
  84. package/dist/cli/api-context.js +6 -0
  85. package/dist/cli/audit-prune.d.ts +6 -39
  86. package/dist/cli/audit-prune.js +6 -39
  87. package/dist/cli/audit.d.ts +1 -1
  88. package/dist/cli/audit.js +33 -34
  89. package/dist/cli/auth.d.ts +2 -2
  90. package/dist/cli/auth.js +57 -39
  91. package/dist/cli/briefs.d.ts +4 -4
  92. package/dist/cli/briefs.js +18 -22
  93. package/dist/cli/card.d.ts +2 -2
  94. package/dist/cli/card.js +31 -32
  95. package/dist/cli/client.d.ts +7 -27
  96. package/dist/cli/client.js +24 -43
  97. package/dist/cli/compact-resume-payload.js +3 -2
  98. package/dist/cli/context.d.ts +1 -2
  99. package/dist/cli/context.js +12 -8
  100. package/dist/cli/continuity.d.ts +6 -6
  101. package/dist/cli/continuity.js +62 -64
  102. package/dist/cli/correction-latency.d.ts +2 -14
  103. package/dist/cli/correction-latency.js +2 -14
  104. package/dist/cli/curate.d.ts +13 -17
  105. package/dist/cli/curate.js +68 -92
  106. package/dist/cli/dag.d.ts +4 -4
  107. package/dist/cli/dag.js +33 -27
  108. package/dist/cli/decisions.d.ts +4 -4
  109. package/dist/cli/decisions.js +33 -47
  110. package/dist/cli/eval.js +15 -13
  111. package/dist/cli/exit.d.ts +6 -0
  112. package/dist/cli/exit.js +11 -0
  113. package/dist/cli/explain.d.ts +1 -2
  114. package/dist/cli/explain.js +6 -4
  115. package/dist/cli/flag-values.d.ts +6 -1
  116. package/dist/cli/flag-values.js +27 -10
  117. package/dist/cli/flags.d.ts +1 -0
  118. package/dist/cli/flags.js +1 -1
  119. package/dist/cli/github.d.ts +14 -0
  120. package/dist/{connectors/github/cli-impl.js → cli/github.js} +43 -71
  121. package/dist/cli/goals.d.ts +2 -2
  122. package/dist/cli/goals.js +46 -50
  123. package/dist/cli/hook-runtime.d.ts +9 -27
  124. package/dist/cli/hook-runtime.js +15 -31
  125. package/dist/cli/init.d.ts +2 -2
  126. package/dist/cli/init.js +6 -12
  127. package/dist/cli/install-steps.js +3 -12
  128. package/dist/cli/last-sleep.d.ts +2 -1
  129. package/dist/cli/last-sleep.js +3 -0
  130. package/dist/cli/maintenance.d.ts +4 -4
  131. package/dist/cli/maintenance.js +14 -19
  132. package/dist/cli/object-verbs.js +4 -3
  133. package/dist/cli/owner-validation.d.ts +5 -28
  134. package/dist/cli/owner-validation.js +5 -28
  135. package/dist/cli/playbooks.d.ts +4 -4
  136. package/dist/cli/playbooks.js +23 -28
  137. package/dist/cli/print.d.ts +2 -5
  138. package/dist/cli/print.js +1 -4
  139. package/dist/cli/projects.d.ts +2 -2
  140. package/dist/cli/projects.js +1 -3
  141. package/dist/cli/provenance-coverage.d.ts +2 -6
  142. package/dist/cli/provenance-coverage.js +2 -6
  143. package/dist/cli/quality-repair-once.js +2 -2
  144. package/dist/cli/recall.d.ts +2 -4
  145. package/dist/cli/recall.js +55 -131
  146. package/dist/cli/refine-llm.d.ts +5 -31
  147. package/dist/cli/refine-llm.js +9 -36
  148. package/dist/cli/remember.d.ts +3 -3
  149. package/dist/cli/remember.js +122 -180
  150. package/dist/cli/scheduler.d.ts +2 -17
  151. package/dist/cli/scheduler.js +12 -18
  152. package/dist/cli/serve.js +21 -12
  153. package/dist/cli/session-hooks.d.ts +10 -18
  154. package/dist/cli/session-hooks.js +112 -113
  155. package/dist/cli/setup.d.ts +4 -4
  156. package/dist/cli/setup.js +19 -21
  157. package/dist/cli/shared.d.ts +9 -23
  158. package/dist/cli/shared.js +9 -32
  159. package/dist/cli/slack.d.ts +2 -2
  160. package/dist/cli/slack.js +19 -23
  161. package/dist/cli/sleep.d.ts +3 -2
  162. package/dist/cli/sleep.js +15 -16
  163. package/dist/cli/status.d.ts +9 -12
  164. package/dist/cli/status.js +55 -98
  165. package/dist/cli/stdin.d.ts +4 -6
  166. package/dist/cli/stdin.js +2 -3
  167. package/dist/cli/transfer.d.ts +9 -9
  168. package/dist/cli/transfer.js +66 -89
  169. package/dist/cli/usage.js +11 -5
  170. package/dist/cli.d.ts +66 -448
  171. package/dist/cli.js +87 -263
  172. package/dist/connectors/github/backfill.d.ts +5 -25
  173. package/dist/connectors/github/backfill.js +14 -49
  174. package/dist/connectors/github/deletion.d.ts +4 -18
  175. package/dist/connectors/github/deletion.js +2 -15
  176. package/dist/connectors/github/dlq.d.ts +8 -33
  177. package/dist/connectors/github/dlq.js +12 -29
  178. package/dist/connectors/github/ingest.d.ts +2 -6
  179. package/dist/connectors/github/ingest.js +4 -10
  180. package/dist/connectors/github/octokit-client.d.ts +4 -16
  181. package/dist/connectors/github/octokit-client.js +27 -24
  182. package/dist/connectors/github/ratelimit.d.ts +3 -14
  183. package/dist/connectors/github/ratelimit.js +3 -14
  184. package/dist/connectors/github/scope.d.ts +3 -5
  185. package/dist/connectors/github/scope.js +3 -5
  186. package/dist/connectors/github/signature.d.ts +4 -26
  187. package/dist/connectors/github/signature.js +4 -26
  188. package/dist/connectors/github/tenant-routing.d.ts +2 -24
  189. package/dist/connectors/github/tenant-routing.js +4 -26
  190. package/dist/connectors/github/transform.js +2 -16
  191. package/dist/connectors/github/types.d.ts +3 -15
  192. package/dist/connectors/github/types.js +2 -9
  193. package/dist/connectors/github/webhook.d.ts +2 -16
  194. package/dist/connectors/github/webhook.js +6 -22
  195. package/dist/connectors/slack/backfill.d.ts +4 -17
  196. package/dist/connectors/slack/backfill.js +4 -13
  197. package/dist/connectors/slack/dlq.d.ts +2 -19
  198. package/dist/connectors/slack/dlq.js +2 -19
  199. package/dist/connectors/slack/ingest.d.ts +2 -3
  200. package/dist/connectors/slack/ingest.js +2 -3
  201. package/dist/connectors/slack/scope.d.ts +2 -8
  202. package/dist/connectors/slack/scope.js +2 -8
  203. package/dist/connectors/slack/signature.d.ts +1 -6
  204. package/dist/connectors/slack/tenant-routing.d.ts +2 -19
  205. package/dist/connectors/slack/tenant-routing.js +2 -21
  206. package/dist/connectors/slack/transform.d.ts +2 -18
  207. package/dist/connectors/slack/transform.js +2 -18
  208. package/dist/connectors/slack/types.d.ts +3 -9
  209. package/dist/connectors/slack/types.js +2 -4
  210. package/dist/connectors/slack/web-client.js +33 -27
  211. package/dist/connectors/slack/webhook.d.ts +2 -19
  212. package/dist/connectors/slack/webhook.js +5 -26
  213. package/dist/connectors/slack/workspaces.d.ts +4 -24
  214. package/dist/connectors/slack/workspaces.js +4 -24
  215. package/dist/consolidate/conflicts.js +6 -14
  216. package/dist/consolidate/dag-summary.d.ts +8 -0
  217. package/dist/consolidate/dag-summary.js +41 -0
  218. package/dist/consolidate/dag.d.ts +5 -28
  219. package/dist/consolidate/dag.js +14 -75
  220. package/dist/consolidate/decay.js +7 -19
  221. package/dist/consolidate/dedupe.d.ts +6 -52
  222. package/dist/consolidate/dedupe.js +13 -71
  223. package/dist/consolidate/flush-units.d.ts +3 -4
  224. package/dist/consolidate/flush-units.js +3 -3
  225. package/dist/consolidate/half-life-migration.d.ts +3 -26
  226. package/dist/consolidate/half-life-migration.js +11 -28
  227. package/dist/consolidate/llm-passes.js +4 -21
  228. package/dist/consolidate/memory-value-weights.d.ts +2 -13
  229. package/dist/consolidate/memory-value-weights.js +2 -13
  230. package/dist/consolidate/memory-value.d.ts +11 -84
  231. package/dist/consolidate/memory-value.js +16 -104
  232. package/dist/consolidate/merge.js +10 -31
  233. package/dist/consolidate/merged-row.js +2 -1
  234. package/dist/consolidate/physics-pass.js +1 -3
  235. package/dist/consolidate/replay.d.ts +6 -38
  236. package/dist/consolidate/replay.js +14 -52
  237. package/dist/consolidate/run.js +1 -1
  238. package/dist/consolidate/sleep.d.ts +1 -8
  239. package/dist/consolidate/sleep.js +5 -17
  240. package/dist/consolidate/trace.d.ts +3 -18
  241. package/dist/consolidate/trace.js +3 -18
  242. package/dist/consolidate/traces.js +6 -22
  243. package/dist/core/ablation.d.ts +4 -91
  244. package/dist/core/ablation.js +4 -91
  245. package/dist/core/ambient.d.ts +1 -8
  246. package/dist/core/ambient.js +1 -8
  247. package/dist/core/capture-contract.d.ts +4 -2
  248. package/dist/core/capture-contract.js +4 -2
  249. package/dist/core/card.d.ts +4 -1
  250. package/dist/core/card.js +8 -0
  251. package/dist/core/compare.d.ts +11 -67
  252. package/dist/core/compare.js +9 -63
  253. package/dist/core/config.d.ts +10 -24
  254. package/dist/core/config.js +13 -14
  255. package/dist/core/handoff.d.ts +1 -7
  256. package/dist/core/handoff.js +1 -7
  257. package/dist/core/memory-quality.js +1 -1
  258. package/dist/core/memory.d.ts +41 -164
  259. package/dist/core/memory.js +51 -221
  260. package/dist/core/package-root.d.ts +3 -0
  261. package/dist/core/package-root.js +5 -0
  262. package/dist/core/physics-config.d.ts +1 -4
  263. package/dist/core/physics-config.js +3 -8
  264. package/dist/core/physics.d.ts +15 -61
  265. package/dist/core/physics.js +59 -122
  266. package/dist/core/project-identity.d.ts +17 -58
  267. package/dist/core/project-identity.js +17 -38
  268. package/dist/core/project-remote.js +13 -2
  269. package/dist/core/raw-append-only.d.ts +5 -0
  270. package/dist/core/raw-append-only.js +7 -0
  271. package/dist/core/salience.d.ts +1 -7
  272. package/dist/core/salience.js +1 -7
  273. package/dist/dashboard/dashboard-actions.js +2 -2
  274. package/dist/dashboard/dashboard-snapshot.d.ts +2 -1
  275. package/dist/dashboard/dashboard-snapshot.js +11 -2
  276. package/dist/dashboard/dashboard-types.d.ts +2 -1
  277. package/dist/dashboard/dashboard.d.ts +1 -0
  278. package/dist/dashboard/dashboard.js +50 -4
  279. package/dist/db/busy.d.ts +1 -1
  280. package/dist/db/busy.js +17 -8
  281. package/dist/db/connect.d.ts +1 -0
  282. package/dist/db/connect.js +3 -3
  283. package/dist/db/migrate.js +3 -3
  284. package/dist/db/migrations/types.d.ts +2 -5
  285. package/dist/db/migrations/v14.js +2 -3
  286. package/dist/db/migrations/v15.js +2 -8
  287. package/dist/db/migrations/v16.js +2 -3
  288. package/dist/db/migrations/v17.js +2 -3
  289. package/dist/db/migrations/v19.js +2 -5
  290. package/dist/db/migrations/v20.js +2 -7
  291. package/dist/db/migrations/v22.js +4 -17
  292. package/dist/db/migrations/v23.js +3 -14
  293. package/dist/db/migrations/v24.js +2 -4
  294. package/dist/db/migrations/v25.js +3 -8
  295. package/dist/db/migrations/v26.js +2 -13
  296. package/dist/db/migrations/v27.js +3 -11
  297. package/dist/db/migrations/v28.js +2 -14
  298. package/dist/db/migrations/v29.js +4 -18
  299. package/dist/db/migrations/v30.js +4 -16
  300. package/dist/db/migrations/v31.js +2 -15
  301. package/dist/db/migrations/v32.js +4 -22
  302. package/dist/db/migrations/v33.js +2 -15
  303. package/dist/db/migrations/v34.js +2 -11
  304. package/dist/db/migrations/v35.js +2 -11
  305. package/dist/db/migrations/v36.js +2 -11
  306. package/dist/db/migrations/v37.js +8 -33
  307. package/dist/db/migrations/v38.js +5 -38
  308. package/dist/db/migrations/v39.js +9 -20
  309. package/dist/db/migrations/v40.js +2 -9
  310. package/dist/db/migrations/v41.js +2 -24
  311. package/dist/db/migrations/v43.js +1 -1
  312. package/dist/db/migrations/v44.js +2 -8
  313. package/dist/db/migrations/v45.js +2 -7
  314. package/dist/db/migrations/v47.js +2 -3
  315. package/dist/db/migrations/v51.js +1 -1
  316. package/dist/db/open.d.ts +2 -0
  317. package/dist/db/open.js +17 -1
  318. package/dist/db/physics-state.d.ts +6 -22
  319. package/dist/db/physics-state.js +25 -36
  320. package/dist/db/raw-archive-mirror-cleanup.d.ts +2 -17
  321. package/dist/db/raw-archive-mirror-cleanup.js +2 -17
  322. package/dist/db/vector-store.d.ts +2 -0
  323. package/dist/db/vector-store.js +8 -1
  324. package/dist/doctor.js +74 -19
  325. package/dist/entry/session-text.js +2 -1
  326. package/dist/eval/eval-stats.d.ts +15 -53
  327. package/dist/eval/eval-stats.js +12 -42
  328. package/dist/eval/eval-suite.d.ts +2 -13
  329. package/dist/eval/eval-suite.js +74 -34
  330. package/dist/eval/eval.d.ts +6 -24
  331. package/dist/eval/eval.js +7 -34
  332. package/dist/eval/judgment.d.ts +0 -3
  333. package/dist/eval/judgment.js +19 -11
  334. package/dist/extensions/openclaw-plugin/index.js +1 -1
  335. package/dist/graph/extract.d.ts +5 -27
  336. package/dist/graph/extract.js +7 -33
  337. package/dist/graph/recall.d.ts +7 -20
  338. package/dist/graph/recall.js +14 -76
  339. package/dist/graph/stream.d.ts +7 -39
  340. package/dist/graph/stream.js +11 -34
  341. package/dist/graph/view.d.ts +9 -35
  342. package/dist/graph/view.js +11 -39
  343. package/dist/hooks/codex-wrapper.js +2 -2
  344. package/dist/hooks/copilot.js +2 -1
  345. package/dist/hooks/hook-blocks.d.ts +6 -2
  346. package/dist/hooks/hook-blocks.js +37 -124
  347. package/dist/hooks/json-hooks.d.ts +4 -36
  348. package/dist/hooks/json-hooks.js +18 -57
  349. package/dist/hooks/opencode.d.ts +0 -38
  350. package/dist/hooks/opencode.js +9 -76
  351. package/dist/hooks/shared.d.ts +8 -17
  352. package/dist/hooks/shared.js +29 -20
  353. package/dist/importers/core.d.ts +12 -37
  354. package/dist/importers/core.js +9 -27
  355. package/dist/importers/markdown-parse.d.ts +8 -22
  356. package/dist/importers/markdown-parse.js +8 -25
  357. package/dist/importers/markdown.js +3 -12
  358. package/dist/importers/sources.js +7 -35
  359. package/dist/importers/vault.d.ts +2 -8
  360. package/dist/importers/vault.js +25 -81
  361. package/dist/index.d.ts +6 -2
  362. package/dist/index.js +6 -2
  363. package/dist/learn/autolearn.d.ts +14 -41
  364. package/dist/learn/autolearn.js +14 -41
  365. package/dist/learn/extract.js +2 -4
  366. package/dist/learn/forward-claim-detector.d.ts +6 -30
  367. package/dist/learn/forward-claim-detector.js +14 -66
  368. package/dist/learn/invalidation.d.ts +6 -18
  369. package/dist/learn/invalidation.js +9 -26
  370. package/dist/mcp/admin-tools.js +3 -5
  371. package/dist/mcp/memory-tools.js +4 -9
  372. package/dist/mcp/protocol.d.ts +8 -26
  373. package/dist/mcp/protocol.js +3 -6
  374. package/dist/mcp/recall-tools.js +3 -3
  375. package/dist/mcp/request.d.ts +3 -11
  376. package/dist/mcp/request.js +10 -26
  377. package/dist/mcp/server.d.ts +3 -9
  378. package/dist/mcp/server.js +5 -16
  379. package/dist/mcp/session-state.d.ts +1 -1
  380. package/dist/mcp/session-state.js +5 -11
  381. package/dist/mcp/stdio.d.ts +2 -6
  382. package/dist/mcp/stdio.js +48 -12
  383. package/dist/mcp/tools.js +5 -3
  384. package/dist/objects/customer-notes.d.ts +7 -42
  385. package/dist/objects/customer-notes.js +7 -48
  386. package/dist/objects/decisions.d.ts +12 -50
  387. package/dist/objects/decisions.js +15 -53
  388. package/dist/objects/incidents.d.ts +7 -38
  389. package/dist/objects/incidents.js +7 -41
  390. package/dist/objects/policies.d.ts +11 -89
  391. package/dist/objects/policies.js +11 -98
  392. package/dist/objects/processes.d.ts +7 -52
  393. package/dist/objects/processes.js +7 -61
  394. package/dist/objects/project-briefs.d.ts +11 -55
  395. package/dist/objects/project-briefs.js +14 -75
  396. package/dist/objects/skills.d.ts +7 -42
  397. package/dist/objects/skills.js +8 -54
  398. package/dist/postinstall.js +6 -19
  399. package/dist/predictions/planning-fallacy.d.ts +11 -34
  400. package/dist/rerankers/clef.js +3 -31
  401. package/dist/rerankers/cross-encoder.js +4 -6
  402. package/dist/rerankers/jev.js +9 -6
  403. package/dist/rerankers/llm.d.ts +2 -11
  404. package/dist/rerankers/llm.js +14 -14
  405. package/dist/rerankers/outage-warning.d.ts +2 -1
  406. package/dist/rerankers/outage-warning.js +2 -1
  407. package/dist/rerankers/remote.d.ts +1 -0
  408. package/dist/rerankers/remote.js +2 -0
  409. package/dist/rerankers/types.d.ts +2 -14
  410. package/dist/search/boosts.d.ts +0 -2
  411. package/dist/search/boosts.js +2 -2
  412. package/dist/search/goal-boost.d.ts +23 -0
  413. package/dist/search/goal-boost.js +90 -0
  414. package/dist/search/hybrid.d.ts +2 -0
  415. package/dist/search/multihop.js +2 -3
  416. package/dist/search/path-context.d.ts +5 -18
  417. package/dist/search/path-context.js +5 -18
  418. package/dist/search/physics-search.js +11 -8
  419. package/dist/search/rrf.d.ts +7 -35
  420. package/dist/search/rrf.js +5 -30
  421. package/dist/search/vector.d.ts +7 -0
  422. package/dist/search/vector.js +35 -5
  423. package/dist/server/auth.d.ts +9 -28
  424. package/dist/server/auth.js +32 -25
  425. package/dist/server/boot.d.ts +2 -21
  426. package/dist/server/boot.js +63 -96
  427. package/dist/server/client-ip.d.ts +3 -19
  428. package/dist/server/client-ip.js +5 -28
  429. package/dist/server/defaults.d.ts +3 -0
  430. package/dist/server/defaults.js +4 -0
  431. package/dist/server/key-check-bounds.d.ts +2 -1
  432. package/dist/server/lifecycle.d.ts +5 -4
  433. package/dist/server/lifecycle.js +19 -4
  434. package/dist/server/mcp-http.js +10 -44
  435. package/dist/server/rate-limit.d.ts +5 -18
  436. package/dist/server/rate-limit.js +4 -13
  437. package/dist/server/request.d.ts +4 -8
  438. package/dist/server/request.js +9 -17
  439. package/dist/server/route-table.js +42 -49
  440. package/dist/server/routes/admin.js +22 -28
  441. package/dist/server/routes/customer-notes.js +7 -12
  442. package/dist/server/routes/decisions.js +10 -17
  443. package/dist/server/routes/incidents.js +12 -20
  444. package/dist/server/routes/memories.js +12 -32
  445. package/dist/server/routes/object-routes.d.ts +0 -5
  446. package/dist/server/routes/object-routes.js +7 -15
  447. package/dist/server/routes/policies.js +10 -18
  448. package/dist/server/routes/predictions.js +13 -25
  449. package/dist/server/routes/processes.js +16 -26
  450. package/dist/server/routes/project-briefs.js +9 -16
  451. package/dist/server/routes/recall.js +10 -35
  452. package/dist/server/routes/skills.js +8 -18
  453. package/dist/server/server-detect.d.ts +9 -53
  454. package/dist/server/server-detect.js +24 -90
  455. package/dist/server/sleep-offload.js +4 -1
  456. package/dist/server/types.d.ts +12 -10
  457. package/dist/server/validation.d.ts +3 -1
  458. package/dist/server/validation.js +10 -23
  459. package/dist/server.d.ts +2 -2
  460. package/dist/server.js +3 -2
  461. package/dist/sharing/global-store.d.ts +19 -0
  462. package/dist/sharing/global-store.js +75 -0
  463. package/dist/sharing/global-sync.d.ts +6 -0
  464. package/dist/sharing/global-sync.js +80 -0
  465. package/dist/sharing/project-merge.d.ts +4 -5
  466. package/dist/sharing/project-merge.js +9 -7
  467. package/dist/sharing/scope.d.ts +4 -11
  468. package/dist/sharing/scope.js +4 -11
  469. package/dist/sharing/search-both.d.ts +60 -0
  470. package/dist/sharing/search-both.js +138 -0
  471. package/dist/sharing/share.d.ts +38 -0
  472. package/dist/sharing/share.js +226 -0
  473. package/dist/store/ambient.js +4 -9
  474. package/dist/store/audit-event.d.ts +4 -12
  475. package/dist/store/audit-event.js +4 -12
  476. package/dist/store/audit.d.ts +2 -5
  477. package/dist/store/audit.js +4 -12
  478. package/dist/store/auth.d.ts +6 -6
  479. package/dist/store/auth.js +10 -9
  480. package/dist/store/candidates.d.ts +20 -3
  481. package/dist/store/candidates.js +77 -48
  482. package/dist/store/card-detail.d.ts +2 -1
  483. package/dist/store/card-detail.js +2 -1
  484. package/dist/store/cards.d.ts +14 -9
  485. package/dist/store/cards.js +72 -126
  486. package/dist/store/conflicts.d.ts +4 -21
  487. package/dist/store/conflicts.js +71 -150
  488. package/dist/store/connectors/github.d.ts +10 -10
  489. package/dist/store/connectors/github.js +10 -10
  490. package/dist/store/dashboard-reads.js +4 -8
  491. package/dist/store/delete-and-batch.d.ts +11 -31
  492. package/dist/store/delete-and-batch.js +48 -64
  493. package/dist/store/delivery-recorder.d.ts +8 -4
  494. package/dist/store/delivery-recorder.js +25 -15
  495. package/dist/store/diagnostics.js +6 -13
  496. package/dist/store/dormant.d.ts +7 -29
  497. package/dist/store/dormant.js +15 -56
  498. package/dist/store/embeddings/index.d.ts +11 -80
  499. package/dist/store/embeddings/index.js +71 -207
  500. package/dist/store/embeddings/local.js +15 -32
  501. package/dist/store/embeddings/provider.d.ts +16 -53
  502. package/dist/store/embeddings/provider.js +41 -69
  503. package/dist/store/entry-reads.d.ts +21 -57
  504. package/dist/store/entry-reads.js +65 -126
  505. package/dist/store/entry-row.d.ts +6 -35
  506. package/dist/store/entry-row.js +9 -37
  507. package/dist/store/entry-writes.d.ts +10 -16
  508. package/dist/store/entry-writes.js +17 -35
  509. package/dist/store/goals.d.ts +3 -40
  510. package/dist/store/goals.js +21 -160
  511. package/dist/store/graph-queue.d.ts +6 -22
  512. package/dist/store/graph-queue.js +14 -45
  513. package/dist/store/graph-reads.d.ts +11 -35
  514. package/dist/store/graph-reads.js +20 -58
  515. package/dist/store/graph-rows.d.ts +3 -6
  516. package/dist/store/graph-rows.js +6 -9
  517. package/dist/store/graph-view-rows.d.ts +2 -1
  518. package/dist/store/graph-view-rows.js +2 -1
  519. package/dist/store/graph-writes.d.ts +6 -31
  520. package/dist/store/graph-writes.js +13 -37
  521. package/dist/store/half-life.d.ts +2 -1
  522. package/dist/store/half-life.js +14 -16
  523. package/dist/store/handoffs.d.ts +5 -11
  524. package/dist/store/handoffs.js +16 -34
  525. package/dist/store/index-and-stats.d.ts +6 -19
  526. package/dist/store/index-and-stats.js +34 -82
  527. package/dist/store/markdown.d.ts +2 -6
  528. package/dist/store/markdown.js +21 -20
  529. package/dist/store/mirrors.d.ts +2 -6
  530. package/dist/store/mirrors.js +14 -23
  531. package/dist/store/open.js +6 -13
  532. package/dist/store/planning-fallacy-evidence.d.ts +2 -30
  533. package/dist/store/planning-fallacy-evidence.js +8 -37
  534. package/dist/store/port.d.ts +82 -79
  535. package/dist/store/predictions.d.ts +11 -51
  536. package/dist/store/predictions.js +38 -119
  537. package/dist/{cli → store}/quality-repair.js +15 -31
  538. package/dist/store/raw-archive.d.ts +4 -16
  539. package/dist/store/raw-archive.js +14 -29
  540. package/dist/store/recall-scope.d.ts +19 -79
  541. package/dist/store/recall-scope.js +21 -82
  542. package/dist/store/recall-trace.d.ts +10 -77
  543. package/dist/store/recall-trace.js +19 -95
  544. package/dist/store/rejected-values.js +7 -19
  545. package/dist/store/rejection.d.ts +12 -58
  546. package/dist/store/rejection.js +13 -65
  547. package/dist/store/report-reads.d.ts +6 -0
  548. package/dist/store/report-reads.js +29 -0
  549. package/dist/store/rows.d.ts +9 -19
  550. package/dist/store/rows.js +36 -34
  551. package/dist/store/rule-sql.d.ts +5 -0
  552. package/dist/store/rule-sql.js +37 -0
  553. package/dist/store/search-rows.d.ts +7 -38
  554. package/dist/store/search-rows.js +14 -50
  555. package/dist/store/sessions.d.ts +10 -47
  556. package/dist/store/sessions.js +17 -73
  557. package/dist/store/sqlite/connector-events-group.js +2 -2
  558. package/dist/store/sqlite/entry-writes-group.js +2 -2
  559. package/dist/store/sqlite/error-codec.js +4 -2
  560. package/dist/store/sqlite/executor.d.ts +2 -1
  561. package/dist/store/sqlite/executor.js +2 -1
  562. package/dist/store/sqlite/local.d.ts +3 -3
  563. package/dist/store/sqlite/local.js +1 -0
  564. package/dist/store/sqlite/object-rows.js +6 -3
  565. package/dist/store/sqlite/objects-group.js +4 -2
  566. package/dist/store/sqlite/quarantine-group.js +2 -2
  567. package/dist/store/sqlite/store.d.ts +1 -4
  568. package/dist/store/sqlite/store.js +2 -3
  569. package/dist/store/sqlite/vector-reads-group.js +2 -2
  570. package/dist/store/sqlite/worker-jobs.js +1 -1
  571. package/dist/store/sqlite/worker-ops.d.ts +13 -2
  572. package/dist/store/sqlite/worker-ops.js +13 -2
  573. package/dist/store/sqlite/worker-store.js +5 -2
  574. package/dist/store/summaries.d.ts +10 -62
  575. package/dist/store/summaries.js +34 -146
  576. package/dist/store/summary-dirty.js +1 -1
  577. package/dist/store/tenant-lookup.d.ts +6 -1
  578. package/dist/store/tenant-lookup.js +7 -0
  579. package/dist/store/tenant.d.ts +2 -16
  580. package/dist/store/tenant.js +4 -19
  581. package/dist/store/token-ledger.d.ts +13 -43
  582. package/dist/store/token-ledger.js +19 -50
  583. package/dist/store/usage-reports.js +5 -13
  584. package/dist/store/vector-index.d.ts +46 -0
  585. package/dist/store/vector-index.js +170 -0
  586. package/dist/store/working-memory.d.ts +6 -25
  587. package/dist/store/working-memory.js +18 -52
  588. package/dist/store/yaml.d.ts +1 -5
  589. package/dist/store/yaml.js +2 -6
  590. package/dist/support-bundle.js +7 -5
  591. package/dist/trust/reject-flow.js +1 -3
  592. package/dist/util/anthropic-messages.js +14 -2
  593. package/dist/util/atomic-write.d.ts +2 -1
  594. package/dist/util/atomic-write.js +35 -4
  595. package/dist/util/capped-json.d.ts +6 -0
  596. package/dist/util/capped-json.js +46 -0
  597. package/dist/util/crash-handlers.d.ts +8 -1
  598. package/dist/util/crash-handlers.js +52 -10
  599. package/dist/util/env.d.ts +13 -6
  600. package/dist/util/env.js +14 -7
  601. package/dist/util/home-path.d.ts +2 -1
  602. package/dist/util/home-path.js +4 -2
  603. package/dist/util/http-retry.d.ts +3 -1
  604. package/dist/util/http-retry.js +26 -5
  605. package/dist/util/log.d.ts +3 -2
  606. package/dist/util/log.js +25 -9
  607. package/dist/util/request-scope.d.ts +2 -1
  608. package/dist/util/request-scope.js +2 -1
  609. package/dist/util/secret-detect.d.ts +5 -30
  610. package/dist/util/secret-detect.js +13 -39
  611. package/dist/util/stored-json.d.ts +1 -1
  612. package/dist/util/stored-json.js +1 -1
  613. package/dist/util/token-text.d.ts +1 -4
  614. package/dist/util/token-text.js +1 -4
  615. package/dist/util/transcript-tail.d.ts +2 -0
  616. package/dist/util/transcript-tail.js +24 -23
  617. package/dist/util/version.d.ts +5 -20
  618. package/dist/util/version.js +5 -20
  619. package/extensions/openclaw-plugin/index.ts +1 -1
  620. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  621. package/extensions/openclaw-plugin/package.json +1 -1
  622. package/openclaw.plugin.json +1 -1
  623. package/package.json +1 -1
  624. package/dist/connectors/github/cli-impl.d.ts +0 -25
  625. package/dist/sharing/shared.d.ts +0 -187
  626. package/dist/sharing/shared.js +0 -563
  627. package/dist/store/vector-writes.d.ts +0 -13
  628. package/dist/store/vector-writes.js +0 -89
  629. /package/dist/{cli → store}/quality-repair.d.ts +0 -0
@@ -1,43 +1,19 @@
1
- /**
2
- * Rejected-value tombstone: core invariant.
3
- *
4
- * Exact-normalized-value semantics: a human who rejects a fact can refuse
5
- * byte-stable re-ingestion of the same value across remember/capture/import/
6
- * sync surfaces. Paraphrase/semantic matching is explicitly out of scope
7
- * (documented limitation, plan "Design").
8
- *
9
- * Kept db-agnostic (helpers take a `DatabaseSyncLike` handle) and does NOT
10
- * import from store.ts — store.ts imports from here, and the reverse would
11
- * be a cycle.
12
- */
1
+ /** Rejected-value tombstone: a human can refuse byte-stable re-ingestion of a rejected fact (exact normalized value); paraphrase matching is out of scope.
2
+ * db-agnostic (helpers take a `DatabaseSyncLike`) and imports nothing from the store layer above it, which imports this (the reverse is a cycle). */
13
3
  import { createHash } from 'node:crypto';
14
4
  import { BadRequestError } from '../core/api-errors.js';
15
5
  import { DIGEST_DISPLAY_CHARS } from '../util/token-text.js';
16
- /**
17
- * Normalize content for rejection-digest comparisons: Unicode NFC →
18
- * lowercase → collapse whitespace runs to a single space → trim. No
19
- * punctuation stripping — over-normalization creates false refusals, which
20
- * are worse than misses (plan §1).
21
- */
6
+ /** Normalize content for rejection digests: NFC, lowercase, collapse whitespace runs, trim. No punctuation stripping: over-normalizing causes false
7
+ * refusals, worse than misses. */
22
8
  export function normalizeValueForRejection(content) {
23
9
  return content.normalize('NFC').toLowerCase().replace(/\s+/g, ' ').trim();
24
10
  }
25
- /**
26
- * Full sha256 hex (64 chars) of the normalized content. Reuses the strong-
27
- * identity convention (importers.ts:814 content-hash tag), NOT the privacy-
28
- * lossy 16-char convention (recall-trace query hashing) — a tombstone lookup
29
- * key needs collision resistance, not redaction (plan §1).
30
- */
11
+ /** Full 64-char sha256 hex of the normalized content: a tombstone key needs collision resistance, not the 16-char redaction hash used for query hashing. */
31
12
  export function rejectionDigest(content) {
32
13
  return createHash('sha256').update(normalizeValueForRejection(content)).digest('hex');
33
14
  }
34
- /**
35
- * Thrown by the write-path guard (checkRejectionGuard, called from
36
- * upsertEntryRow) when an incoming write would introduce a value matching a
37
- * tombstoned digest. Carries enough context for the transaction-owner catch
38
- * blocks (writeEntry, api.supersede) to write a post-rollback
39
- * `reject_refusal` audit row via `auditRejectionRefusal` (plan §3).
40
- */
15
+ /** Thrown by the write-path guard (checkRejectionGuard, via upsertEntryRow) when a write would introduce a tombstoned value; carries what the
16
+ * transaction-owner catch blocks (writeEntry, api.supersede) need to write the post-rollback `reject_refusal` audit row via `auditRejectionRefusal`. */
41
17
  export class RejectedValueError extends BadRequestError {
42
18
  digest;
43
19
  tenantId;
@@ -66,10 +42,7 @@ function rowToRejectedValue(row) {
66
42
  normalizedChars: row.normalized_chars,
67
43
  };
68
44
  }
69
- /**
70
- * Look up a tombstone by tenant + digest. One indexed point query — the
71
- * guard's common-case cost, a miss ends the guard (plan §3).
72
- */
45
+ /** Look up a tombstone by tenant + digest: one indexed point query, the guard's common-case cost; a miss ends the guard. */
73
46
  export function findRejectedValue(db, tenantId, digest) {
74
47
  // SAFETY: row's shape matches the columns named in the SELECT above.
75
48
  const row = db
@@ -78,10 +51,7 @@ export function findRejectedValue(db, tenantId, digest) {
78
51
  .get(tenantId, digest);
79
52
  return row ? rowToRejectedValue(row) : null;
80
53
  }
81
- /**
82
- * Insert (or refresh) a tombstone row. Caller owns the transaction — used by
83
- * the `reject` verb and `resolveConflict`'s `rejectLoserValue` path.
84
- */
54
+ /** Insert (or refresh) a tombstone row; the caller owns the transaction (used by the `reject` verb and `resolveConflict`'s `rejectLoserValue`). */
85
55
  export function insertRejectedValue(db, opts) {
86
56
  db.prepare(`INSERT INTO rejected_values(tenant_id, digest, reason, rejected_by, rejected_at, source_memory_id, normalized_chars)
87
57
  VALUES (?, ?, ?, ?, ?, ?, ?)
@@ -92,10 +62,7 @@ export function insertRejectedValue(db, opts) {
92
62
  source_memory_id = excluded.source_memory_id,
93
63
  normalized_chars = excluded.normalized_chars`).run(opts.tenantId, opts.digest, opts.reason, opts.rejectedBy, opts.rejectedAt, opts.sourceMemoryId ?? null, opts.normalizedChars);
94
64
  }
95
- /**
96
- * Delete a tombstone by tenant + exact digest: the `unreject` verb, the
97
- * only escape hatch.
98
- */
65
+ /** Delete a tombstone by tenant + exact digest: the `unreject` verb, the only escape hatch. */
99
66
  export function deleteRejectedValue(db, tenantId, digest) {
100
67
  const result = db.prepare(`DELETE FROM rejected_values WHERE tenant_id = ? AND digest = ?`).run(tenantId, digest);
101
68
  return (result.changes ?? 0) > 0;
@@ -109,33 +76,14 @@ export function listRejectedValues(db, tenantId) {
109
76
  .all(tenantId);
110
77
  return rows.map(rowToRejectedValue);
111
78
  }
112
- /**
113
- * The write-path guard's check helper, called from `upsertEntryRow`
114
- * (store.ts). Fires when the incoming content's digest matches a tombstone
115
- * AND the write *introduces* that content: the row is new, OR the stored
116
- * row's content digest differs from the incoming one — an UPSERT editing a
117
- * same-id row TO a rejected value is a content introduction and must be
118
- * refused. Unchanged same-id re-persists (recall boost, decay, star toggle)
119
- * are exempt by construction (plan §3).
120
- *
121
- * Ordering minimizes queries on the common (miss) path: (a) caller has
122
- * already computed nothing yet — this does the digest + point lookup first;
123
- * (b) a miss returns immediately (ONE indexed point query); (c) only on a
124
- * tombstone hit does it SELECT the stored row's content to classify
125
- * new-row vs content-introduction (+1 query, rare path).
126
- */
79
+ /** Write-path guard check: fires when the digest matches a tombstone AND the write introduces that content (a new row, or a same-id UPSERT changing it).
80
+ * Unchanged same-id re-persists (recall boost, decay, star toggle) are exempt. A miss costs ONE indexed point query; only a hit SELECTs the stored row. */
127
81
  export function checkRejectionGuard(db, tenantId, entryId, content) {
128
82
  const incomingDigest = rejectionDigest(content);
129
83
  const tombstone = findRejectedValue(db, tenantId, incomingDigest);
130
84
  if (!tombstone)
131
85
  return; // miss ends the guard — the overwhelmingly common case
132
- // Deliberately id-only (no tenant filter): memory ids are globally unique
133
- // ULIDs, this lookup only classifies new-row vs same-id re-persist for the
134
- // id the caller is already writing, and the tombstone lookup above is the
135
- // tenant-scoped decision. Matches deleteEntry's own by-id SELECT.
136
- //
137
- // Also read tenant_id: a same-id upsert that only changes tenantId introduces the
138
- // content into the destination tenant, exactly as if the row were new there.
86
+ // Id-only on purpose (ids are global ULIDs; the tombstone lookup is tenant-scoped); tenant_id is read as a tenantId-only upsert introduces content there.
139
87
  // SAFETY: storedRow's shape matches the two columns named in the SELECT above.
140
88
  const storedRow = db.prepare(`SELECT content, tenant_id FROM memories WHERE id = ?`).get(entryId);
141
89
  const isNewRow = storedRow === undefined;
@@ -0,0 +1,6 @@
1
+ import type { MemoryEntry } from '../core/memory.js';
2
+ /** Every superseded row, the row that replaced it and that row's extraction source, in loadAllEntries' order: all a correction-latency report reads. */
3
+ export declare function loadCorrectionEntries(hippoRoot: string): MemoryEntry[];
4
+ /** The kind='raw' rows in loadAllEntries' order: all a provenance-coverage report reads. */
5
+ export declare function loadRawEntries(hippoRoot: string): MemoryEntry[];
6
+ //# sourceMappingURL=report-reads.d.ts.map
@@ -0,0 +1,29 @@
1
+ import { MEMORY_SELECT_COLUMNS, rowToEntry } from './rows.js';
2
+ import { onHandle, openStore } from './open.js';
3
+ /** Every superseded row, the row that replaced it and that row's extraction source, in loadAllEntries' order: all a correction-latency report reads. */
4
+ export function loadCorrectionEntries(hippoRoot) {
5
+ return onHandle(hippoRoot, (db) => {
6
+ const superseded = `superseded_by IS NOT NULL AND superseded_by != ''`;
7
+ // SAFETY: selects exactly MEMORY_SELECT_COLUMNS, matching MemoryRow's field set.
8
+ const rows = db.prepare(`
9
+ SELECT ${MEMORY_SELECT_COLUMNS} FROM memories
10
+ WHERE (${superseded})
11
+ OR id IN (SELECT superseded_by FROM memories WHERE ${superseded})
12
+ OR id IN (
13
+ SELECT extracted_from FROM memories
14
+ WHERE extracted_from IS NOT NULL AND id IN (SELECT superseded_by FROM memories WHERE ${superseded})
15
+ )
16
+ ORDER BY created ASC, id ASC
17
+ `).all();
18
+ return rows.map(rowToEntry);
19
+ }, openStore);
20
+ }
21
+ /** The kind='raw' rows in loadAllEntries' order: all a provenance-coverage report reads. */
22
+ export function loadRawEntries(hippoRoot) {
23
+ return onHandle(hippoRoot, (db) => {
24
+ // SAFETY: selects exactly MEMORY_SELECT_COLUMNS, matching MemoryRow's field set.
25
+ const rows = db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories WHERE kind = 'raw' ORDER BY created ASC, id ASC`).all();
26
+ return rows.map(rowToEntry);
27
+ }, openStore);
28
+ }
29
+ //# sourceMappingURL=report-reads.js.map
@@ -1,5 +1,6 @@
1
1
  import { Layer, type MemoryEntry, type ConfidenceLevel } from '../core/memory.js';
2
2
  import { type JsonValue } from '../util/json.js';
3
+ import { type StoredJsonSite } from '../util/stored-json.js';
3
4
  export interface IndexEntry {
4
5
  id: string;
5
6
  file: string;
@@ -134,27 +135,16 @@ export interface SessionEvent {
134
135
  created_at: string;
135
136
  }
136
137
  export declare const INDEX_VERSION = 3;
137
- export declare const MEMORY_SELECT_COLUMNS = "id, created, last_retrieved, retrieval_count, strength, half_life_days, layer, tags_json, emotional_valence, schema_fit, source, outcome_score, outcome_positive, outcome_negative, conflicts_with_json, pinned, confidence, content, parents_json, starred, trace_outcome, source_session_id, valid_from, superseded_by, extracted_from, dag_level, dag_parent_id, kind, scope, owner, artifact_ref, tenant_id, origin_project, descendant_count, earliest_at, latest_at, summary_dirty, last_rebuilt_at, rebuild_count, dag_level_3_built_at";
138
- export declare const MEMORY_SEARCH_COLUMNS = "m.id AS id, m.created AS created, m.last_retrieved AS last_retrieved, m.retrieval_count AS retrieval_count, m.strength AS strength, m.half_life_days AS half_life_days, m.layer AS layer, m.tags_json AS tags_json, m.emotional_valence AS emotional_valence, m.schema_fit AS schema_fit, m.source AS source, m.outcome_score AS outcome_score, m.outcome_positive AS outcome_positive, m.outcome_negative AS outcome_negative, m.conflicts_with_json AS conflicts_with_json, m.pinned AS pinned, m.confidence AS confidence, m.content AS content, m.parents_json AS parents_json, m.starred AS starred, m.trace_outcome AS trace_outcome, m.source_session_id AS source_session_id, m.valid_from AS valid_from, m.superseded_by AS superseded_by, m.extracted_from AS extracted_from, m.dag_level AS dag_level, m.dag_parent_id AS dag_parent_id, m.kind AS kind, m.scope AS scope, m.owner AS owner, m.artifact_ref AS artifact_ref, m.tenant_id AS tenant_id, m.origin_project AS origin_project, m.descendant_count AS descendant_count, m.earliest_at AS earliest_at, m.latest_at AS latest_at, m.summary_dirty AS summary_dirty, m.last_rebuilt_at AS last_rebuilt_at, m.rebuild_count AS rebuild_count, m.dag_level_3_built_at AS dag_level_3_built_at, bm25(memories_fts) AS bm25_score";
139
- /**
140
- * Default candidate-pool size for `loadSearchEntries` when called with
141
- * `limit === undefined`. Single source of truth; `api.recall` imports
142
- * this for `RecallResult.windowSize` reporting so the two cannot drift.
143
- */
138
+ export declare const MEMORY_SELECT_COLUMNS: string;
139
+ export declare const MEMORY_SEARCH_COLUMNS: string;
140
+ /** Default candidate-pool size for `loadSearchEntries` when `limit` is undefined; `api.recall` imports it for `RecallResult.windowSize` so the two cannot
141
+ * drift. */
144
142
  export declare const DEFAULT_SEARCH_CANDIDATE_LIMIT = 200;
145
143
  export declare function rowToEntry(row: MemoryRow): MemoryEntry;
146
- export declare function parseJsonArray(raw: string | null | undefined): string[];
147
- /**
148
- * Strict parse for the `last_trace_id` meta value.
149
- * A bare Number(raw) would turn '', whitespace, or garbage into a
150
- * usable-looking 0/NaN — a consumer INSERTing recall_trace_outcomes with
151
- * trace_id=0 would hit a masked FK violation (row id 0 never exists).
152
- * Require a clean positive integer string; anything else is treated as
153
- * unset. This is the ONE place that decides "clean" — every consumer of
154
- * `HippoIndex.last_trace_id` (outcomeForLastRecall, tests) reads the
155
- * already-validated value out of `buildIndexFromDb`'s result and never
156
- * re-parses the raw meta string itself.
157
- */
144
+ /** A column that is not JSON reads as empty. With `site` the row is named at warn once; without it no row is known and the line stays at debug. */
145
+ export declare function parseJsonArray(raw: string | null | undefined, site?: StoredJsonSite): string[];
146
+ /** Strict parse for `last_trace_id`: Number(raw) turns '' or garbage into 0/NaN (a masked FK violation); require a clean positive integer string, else unset.
147
+ * The ONE place that decides 'clean'; consumers read the validated value from `buildIndexFromDb`'s result and never re-parse. */
158
148
  export declare function parseLastTraceId(raw: string | null | undefined): string | null;
159
149
  export declare function rowToTaskSnapshot(row: TaskSnapshotRow): TaskSnapshot;
160
150
  export declare function rowToMemoryConflict(row: MemoryConflictRow): MemoryConflict;
@@ -1,22 +1,29 @@
1
+ import { DEFAULT_TENANT_ID } from '../util/env.js';
1
2
  import { FALLBACK_HALF_LIFE_DAYS, DEFAULT_SCHEMA_FIT } from '../core/memory.js';
2
3
  import { errorMessage, log } from '../util/log.js';
3
4
  import { isJsonObject } from '../util/json.js';
5
+ import { warnDamagedColumn } from '../util/stored-json.js';
4
6
  export const INDEX_VERSION = 3;
5
- export const MEMORY_SELECT_COLUMNS = `id, created, last_retrieved, retrieval_count, strength, half_life_days, layer, tags_json, emotional_valence, schema_fit, source, outcome_score, outcome_positive, outcome_negative, conflicts_with_json, pinned, confidence, content, parents_json, starred, trace_outcome, source_session_id, valid_from, superseded_by, extracted_from, dag_level, dag_parent_id, kind, scope, owner, artifact_ref, tenant_id, origin_project, descendant_count, earliest_at, latest_at, summary_dirty, last_rebuilt_at, rebuild_count, dag_level_3_built_at`;
6
- // FTS-join columns for loadSearchRows: each is `m.<col> AS <col>` so rowToEntry's unqualified
7
- // reads still work, and the trailing bm25(memories_fts) AS bm25_score carries the FTS rank.
8
- export const MEMORY_SEARCH_COLUMNS = `m.id AS id, m.created AS created, m.last_retrieved AS last_retrieved, m.retrieval_count AS retrieval_count, m.strength AS strength, m.half_life_days AS half_life_days, m.layer AS layer, m.tags_json AS tags_json, m.emotional_valence AS emotional_valence, m.schema_fit AS schema_fit, m.source AS source, m.outcome_score AS outcome_score, m.outcome_positive AS outcome_positive, m.outcome_negative AS outcome_negative, m.conflicts_with_json AS conflicts_with_json, m.pinned AS pinned, m.confidence AS confidence, m.content AS content, m.parents_json AS parents_json, m.starred AS starred, m.trace_outcome AS trace_outcome, m.source_session_id AS source_session_id, m.valid_from AS valid_from, m.superseded_by AS superseded_by, m.extracted_from AS extracted_from, m.dag_level AS dag_level, m.dag_parent_id AS dag_parent_id, m.kind AS kind, m.scope AS scope, m.owner AS owner, m.artifact_ref AS artifact_ref, m.tenant_id AS tenant_id, m.origin_project AS origin_project, m.descendant_count AS descendant_count, m.earliest_at AS earliest_at, m.latest_at AS latest_at, m.summary_dirty AS summary_dirty, m.last_rebuilt_at AS last_rebuilt_at, m.rebuild_count AS rebuild_count, m.dag_level_3_built_at AS dag_level_3_built_at, bm25(memories_fts) AS bm25_score`;
9
- /**
10
- * Default candidate-pool size for `loadSearchEntries` when called with
11
- * `limit === undefined`. Single source of truth; `api.recall` imports
12
- * this for `RecallResult.windowSize` reporting so the two cannot drift.
13
- */
7
+ const MEMORY_COLUMN_NAMES = [
8
+ 'id', 'created', 'last_retrieved', 'retrieval_count', 'strength', 'half_life_days', 'layer', 'tags_json',
9
+ 'emotional_valence', 'schema_fit', 'source', 'outcome_score', 'outcome_positive', 'outcome_negative',
10
+ 'conflicts_with_json', 'pinned', 'confidence', 'content', 'parents_json', 'starred', 'trace_outcome',
11
+ 'source_session_id', 'valid_from', 'superseded_by', 'extracted_from', 'dag_level', 'dag_parent_id', 'kind', 'scope',
12
+ 'owner', 'artifact_ref', 'tenant_id', 'origin_project', 'descendant_count', 'earliest_at', 'latest_at',
13
+ 'summary_dirty', 'last_rebuilt_at', 'rebuild_count', 'dag_level_3_built_at',
14
+ ];
15
+ // FTS-join columns for loadSearchRows: `m.<col> AS <col>` keeps rowToEntry's unqualified reads working.
16
+ export const MEMORY_SELECT_COLUMNS = MEMORY_COLUMN_NAMES.join(', ');
17
+ export const MEMORY_SEARCH_COLUMNS = [
18
+ ...MEMORY_COLUMN_NAMES.map((c) => `m.${c} AS ${c}`),
19
+ 'bm25(memories_fts) AS bm25_score',
20
+ ].join(', ');
21
+ /** Default candidate-pool size for `loadSearchEntries` when `limit` is undefined; `api.recall` imports it for `RecallResult.windowSize` so the two cannot
22
+ * drift. */
14
23
  export const DEFAULT_SEARCH_CANDIDATE_LIMIT = 200;
15
24
  function rowToRetrievalFields(row) {
16
- // SAFETY: every `as X` below narrows a SQLite column value to an
17
- // enum/union member of MemoryEntry; `row` comes from MEMORY_SELECT_COLUMNS
18
- // / MEMORY_SEARCH_COLUMNS, which are the only queries producing MemoryRow,
19
- // and the DB layer only ever writes these columns from the same enums.
25
+ // SAFETY: every `as X` narrows a SQLite column to a MemoryEntry enum/union member; `row` comes from MEMORY_SELECT_COLUMNS / MEMORY_SEARCH_COLUMNS,
26
+ // the only queries producing MemoryRow, and the DB layer writes these columns only from the same enums.
20
27
  return {
21
28
  id: row.id,
22
29
  created: row.created,
@@ -25,18 +32,18 @@ function rowToRetrievalFields(row) {
25
32
  strength: Number(row.strength ?? 1),
26
33
  half_life_days: Number(row.half_life_days ?? FALLBACK_HALF_LIFE_DAYS),
27
34
  layer: row.layer,
28
- tags: parseJsonArray(row.tags_json),
35
+ tags: parseJsonArray(row.tags_json, { table: 'memories', id: row.id, column: 'tags_json' }),
29
36
  emotional_valence: row.emotional_valence ?? 'neutral',
30
37
  schema_fit: Number(row.schema_fit ?? DEFAULT_SCHEMA_FIT),
31
38
  source: row.source ?? 'cli',
32
39
  outcome_score: row.outcome_score === null || row.outcome_score === undefined ? null : Number(row.outcome_score),
33
40
  outcome_positive: Number(row.outcome_positive ?? 0),
34
41
  outcome_negative: Number(row.outcome_negative ?? 0),
35
- conflicts_with: parseJsonArray(row.conflicts_with_json),
42
+ conflicts_with: parseJsonArray(row.conflicts_with_json, { table: 'memories', id: row.id, column: 'conflicts_with_json' }),
36
43
  pinned: Boolean(row.pinned),
37
44
  confidence: row.confidence ?? 'observed',
38
45
  content: row.content,
39
- parents: parseJsonArray(row.parents_json),
46
+ parents: parseJsonArray(row.parents_json, { table: 'memories', id: row.id, column: 'parents_json' }),
40
47
  starred: Boolean(row.starred),
41
48
  trace_outcome: row.trace_outcome ?? null,
42
49
  };
@@ -54,7 +61,7 @@ function rowToPlacementFields(row) {
54
61
  scope: row.scope ?? null,
55
62
  owner: row.owner ?? null,
56
63
  artifact_ref: row.artifact_ref ?? null,
57
- tenantId: row.tenant_id ?? 'default',
64
+ tenantId: row.tenant_id ?? DEFAULT_TENANT_ID,
58
65
  origin_project: row.origin_project ?? null,
59
66
  descendant_count: Number(row.descendant_count ?? 0),
60
67
  earliest_at: row.earliest_at ?? null,
@@ -74,7 +81,8 @@ export function rowToEntry(row) {
74
81
  }
75
82
  return entry;
76
83
  }
77
- export function parseJsonArray(raw) {
84
+ /** A column that is not JSON reads as empty. With `site` the row is named at warn once; without it no row is known and the line stays at debug. */
85
+ export function parseJsonArray(raw, site) {
78
86
  if (!raw)
79
87
  return [];
80
88
  try {
@@ -82,28 +90,22 @@ export function parseJsonArray(raw) {
82
90
  return Array.isArray(parsed) ? parsed.map((item) => String(item)) : [];
83
91
  }
84
92
  catch (err) {
85
- log.debug(`store: corrupt JSON array column read as empty: ${errorMessage(err)}`);
93
+ if (site)
94
+ warnDamagedColumn(site, 'not valid JSON');
95
+ else
96
+ log.debug(`store: corrupt JSON array column read as empty: ${errorMessage(err)}`);
86
97
  return [];
87
98
  }
88
99
  }
89
- /**
90
- * Strict parse for the `last_trace_id` meta value.
91
- * A bare Number(raw) would turn '', whitespace, or garbage into a
92
- * usable-looking 0/NaN — a consumer INSERTing recall_trace_outcomes with
93
- * trace_id=0 would hit a masked FK violation (row id 0 never exists).
94
- * Require a clean positive integer string; anything else is treated as
95
- * unset. This is the ONE place that decides "clean" — every consumer of
96
- * `HippoIndex.last_trace_id` (outcomeForLastRecall, tests) reads the
97
- * already-validated value out of `buildIndexFromDb`'s result and never
98
- * re-parses the raw meta string itself.
99
- */
100
+ /** Strict parse for `last_trace_id`: Number(raw) turns '' or garbage into 0/NaN (a masked FK violation); require a clean positive integer string, else unset.
101
+ * The ONE place that decides 'clean'; consumers read the validated value from `buildIndexFromDb`'s result and never re-parse. */
100
102
  export function parseLastTraceId(raw) {
101
103
  const trimmed = (raw ?? '').trim();
102
104
  if (!/^\d+$/.test(trimmed) || Number(trimmed) <= 0)
103
105
  return null;
104
106
  return trimmed;
105
107
  }
106
- function parseJsonObject(raw) {
108
+ function parseJsonObject(raw, site) {
107
109
  if (!raw)
108
110
  return {};
109
111
  try {
@@ -113,8 +115,8 @@ function parseJsonObject(raw) {
113
115
  }
114
116
  return {};
115
117
  }
116
- catch (err) {
117
- log.debug(`store: corrupt JSON object column read as empty: ${errorMessage(err)}`);
118
+ catch {
119
+ warnDamagedColumn(site, 'not valid JSON');
118
120
  return {};
119
121
  }
120
122
  }
@@ -153,7 +155,7 @@ export function rowToSessionEvent(row) {
153
155
  content: row.content,
154
156
  source: row.source,
155
157
  scope: row.scope ?? null,
156
- metadata: parseJsonObject(row.metadata_json),
158
+ metadata: parseJsonObject(row.metadata_json, { table: 'session_events', id: row.id, column: 'metadata_json' }),
157
159
  created_at: row.created_at,
158
160
  };
159
161
  }
@@ -0,0 +1,5 @@
1
+ /** calculateStrength's clock-basis formula as SQL over `memories` columns, flags and multipliers baked in; keep in step.
2
+ * An unparseable date scores NULL here and 0 in JS, so sums agree. */
3
+ export declare function strengthSql(now: Date): string;
4
+ export declare const AUTO_DELETABLE_SQL: string;
5
+ //# sourceMappingURL=rule-sql.d.ts.map
@@ -0,0 +1,37 @@
1
+ // The SQL twins of the model's strength and keep rules (src/core/memory.ts); keep in step with calculateStrength and canAutoDelete.
2
+ import { DAY_MS } from '../util/time.js';
3
+ import { isDecayAblated, isOutcomeSlowAblated, isRecallBoostAblated } from '../core/ablation.js';
4
+ import { DECAY_BASE, EMOTIONAL_MULTIPLIERS, FALLBACK_HALF_LIFE_DAYS, KEEP_PAIRS, MAX_WRONG_HALVINGS, RETRIEVAL_BOOST_SLOPE, REWARD_SLOPE, applyLossAversionRatio, } from '../core/memory.js';
5
+ const UNIX_EPOCH_JULIAN_DAY = 2440587.5;
6
+ /** calculateStrength's clock-basis formula as SQL over `memories` columns, flags and multipliers baked in; keep in step.
7
+ * An unparseable date scores NULL here and 0 in JS, so sums agree. */
8
+ export function strengthSql(now) {
9
+ const num = (n) => (Number.isInteger(n) ? n.toFixed(1) : String(n));
10
+ const pos = 'COALESCE(outcome_positive, 0)';
11
+ const neg = 'COALESCE(outcome_negative, 0)';
12
+ const wrong = isOutcomeSlowAblated() || isDecayAblated() ? '0' : `MAX(0, ${neg} - ${pos})`;
13
+ const reward = isOutcomeSlowAblated()
14
+ ? '1.0'
15
+ : `(CASE WHEN ${pos} = 0 AND ${neg} = 0 THEN 1.0 ELSE 1.0 + ${REWARD_SLOPE} * (${pos} - ${neg}) / (${pos} + ${neg} + 1.0) END)`;
16
+ const halfLife = `(COALESCE(half_life_days, ${FALLBACK_HALF_LIFE_DAYS}) * ${reward})`;
17
+ const anchor = isRecallBoostAblated() ? 'created' : 'last_retrieved';
18
+ const nowJulian = num(now.getTime() / DAY_MS + UNIX_EPOCH_JULIAN_DAY);
19
+ const decay = isDecayAblated() ? '1.0' : `pow(${DECAY_BASE}, (${nowJulian} - julianday(${anchor})) / ${halfLife})`;
20
+ const boost = isRecallBoostAblated()
21
+ ? '1.0'
22
+ : `(CASE WHEN ${wrong} > 0 THEN 1.0 ELSE 1.0 + ${RETRIEVAL_BOOST_SLOPE} * log2(COALESCE(retrieval_count, 0) + 1) END)`;
23
+ const valences = /* SAFETY: a Record keyed by EmotionalValence */ Object.keys(EMOTIONAL_MULTIPLIERS);
24
+ const emotion = `(CASE COALESCE(emotional_valence, 'neutral') ${valences
25
+ .map((v) => `WHEN '${v}' THEN ${num(applyLossAversionRatio(v, EMOTIONAL_MULTIPLIERS[v]))}`)
26
+ .join(' ')} ELSE 1.0 END)`;
27
+ const penalty = `pow(${DECAY_BASE}, MIN(${wrong}, ${MAX_WRONG_HALVINGS}))`;
28
+ return `(CASE WHEN pinned THEN ${penalty} WHEN ${halfLife} <= 0 THEN 0.0
29
+ ELSE MIN(1.0, MAX(0.0, ${decay} * ${boost} * ${emotion})) * ${penalty} END)`;
30
+ }
31
+ const sqlText = (s) => `'${s.replace(/'/g, "''")}'`;
32
+ // json_each matches the tag as a whole element; substr, not LIKE, keeps the prefix case-sensitive like startsWith.
33
+ const keepPairSql = (p) => `(COALESCE(superseded_by, '') = '' AND EXISTS (SELECT 1 FROM json_each(CASE WHEN json_valid(tags_json) THEN tags_json ELSE '[]' END) WHERE value = ${sqlText(p.tag)}) AND substr(source, 1, ${p.sourcePrefix.length}) = ${sqlText(p.sourcePrefix)})`;
34
+ // Pinned and kept rows stay (a superseded row is not kept: its successor carries the tag and
35
+ // source); raw rows leave only through archiveRawMemory. The SQL twin guards the DELETE itself.
36
+ export const AUTO_DELETABLE_SQL = `pinned = 0 AND kind != 'raw'${KEEP_PAIRS.map((p) => ` AND NOT ${keepPairSql(p)}`).join('')}`;
37
+ //# sourceMappingURL=rule-sql.js.map
@@ -1,18 +1,7 @@
1
1
  import type { MemoryEntry } from '../core/memory.js';
2
2
  import { type DatabaseSyncLike } from '../db/index.js';
3
- /**
4
- * Recall-mode scope filter shape, exported so callers and tests can name it. Three modes:
5
- * - 'default-deny': exclude scopes in `RECALL_DEFAULT_DENY_SCOPES`.
6
- * - 'exact': exact match on `m.scope = value` (api.recall's explicit-scope request semantics).
7
- * - 'default-deny-or-exact': the default-admitted set PLUS rows whose scope equals `value` (CLI `--scope`).
8
- * The flag began as a tag-boost hint, so narrowing would return zero rows for tag-scoped workflows.
9
- *
10
- * Background pipelines (`consolidate`, `embeddings`, `refine-llm`, ...) call
11
- * `loadSearchEntries` (no scopeFilter arg) and see all rows including
12
- * quarantine.
13
- */
14
- /** @internal Internal SQL-builder shape; not on the public API
15
- * surface (not re-exported from `src/index.ts`). Subject to change. */
3
+ /** Recall scope filter: 'default-deny' (exclude RECALL_DEFAULT_DENY_SCOPES), 'exact' (m.scope = value), 'default-deny-or-exact' (both; CLI `--scope`).
4
+ * @internal Internal SQL-builder shape; not re-exported from `src/index.ts`. Subject to change. */
16
5
  export type RecallScopeFilter = {
17
6
  mode: 'default-deny';
18
7
  ownScope?: string;
@@ -26,35 +15,15 @@ export type RecallScopeFilter = {
26
15
  };
27
16
  /** One project name, or every name a project's rows carry. */
28
17
  export type OriginFilter = string | readonly string[];
29
- /** Scope rule for recall: none requested is default-deny; 'exact' narrows to the request; 'additive' adds it to the default set, unless it is personal, which only `ownScope` opens. */
18
+ /** Scope rule for recall: none requested is default-deny; 'exact' narrows to the request; 'additive' adds it to the default set, unless it is personal,
19
+ * which only `ownScope` opens. */
30
20
  export declare function recallScopeFilter(requestedScope: string | undefined, mode: 'exact' | 'additive', ownScope?: string): RecallScopeFilter;
31
21
  /** Sends term queries down the LIKE path on a build that has FTS. Only tests call it. */
32
22
  export declare function _forceLikePathForTests(on: boolean): void;
33
- /**
34
- * Load likely search candidates directly from SQLite.
35
- * Uses FTS5 when available, falls back to LIKE matching, then full-store fallback.
36
- *
37
- * When `tenantId` is provided, every SELECT (FTS join, LIKE, fallback) filters
38
- * by tenant_id. Cross-tenant memories never surface. Omitted = no filter.
39
- */
23
+ /** Load likely search candidates: FTS5 when available, else LIKE, then full-store fallback. With `tenantId` every SELECT filters by it; omitted = no filter. */
40
24
  export declare function loadSearchEntries(hippoRoot: string, query: string, limit?: number, tenantId?: string): MemoryEntry[];
41
- /**
42
- * Recall-mode loader. Pushes the recall-side scope predicate into SQL so
43
- * `unknown:legacy` cannot leak via any consumer that hasn't remembered to re-filter.
44
- *
45
- * - `requestedScope` undefined / '': default-deny on `unknown:legacy`, admitting `ownScope`, the caller's personal scope.
46
- * - `requestedScope` non-empty string: exact match on `m.scope = requestedScope`.
47
- *
48
- * Private scopes: SQL applies a conservative `NOT LIKE '%:private:%'` before the LIMIT window so private
49
- * rows cannot starve admitted ones; `passesScopeFilterForRecall` stays the exact JS post-filter.
50
- *
51
- * Consumers: `api.recall`, `cmdRecall`/`cmdExplain` direct CLI paths
52
- * and `searchBothHybrid` recall mode. Background pipelines
53
- * (`consolidate`, `embeddings`, `refine-llm`, ...) keep using
54
- * `loadSearchEntries` so they can see quarantined rows when needed.
55
- *
56
- * `tenantId` is optional because searchBothHybrid's is; undefined means no tenant filter.
57
- */
25
+ /** Recall-mode loader: scope predicate in SQL so `unknown:legacy` cannot leak. Empty `requestedScope` default-denies (admits `ownScope`); else exact match.
26
+ * SQL `NOT LIKE '%:private:%'` runs before the LIMIT so private rows cannot starve admitted ones; `passesScopeFilterForRecall` is the exact post-filter. */
58
27
  export declare function loadRecallSearchEntries(hippoRoot: string, query: string, limit?: number, tenantId?: string, requestedScope?: string, explicitScopeMode?: 'exact' | 'additive', includeSuperseded?: boolean, originProjects?: OriginFilter, ownScope?: string): MemoryEntry[];
59
28
  export interface RecallSearchEntriesOptions {
60
29
  readonly limit?: number;
@@ -6,7 +6,7 @@ import { errorMessage, log } from '../util/log.js';
6
6
  import { originInSql } from '../core/project-identity.js';
7
7
  import { topVectorMatches } from '../db/vector-store.js';
8
8
  import { MEMORY_SELECT_COLUMNS, MEMORY_SEARCH_COLUMNS, DEFAULT_SEARCH_CANDIDATE_LIMIT, rowToEntry, } from './rows.js';
9
- import { openStore } from './open.js';
9
+ import { onHandle, openStore } from './open.js';
10
10
  import { escapeLike } from '../util/escape.js';
11
11
  /** The recall scope rule for a table column prefix (`m.` or none); `passesScopeFilterForRecall` in recall-scope.ts is its JS twin. */
12
12
  function recallScopeClause(col, scopeFilter) {
@@ -28,7 +28,8 @@ function withProject(scope, col, origin) {
28
28
  const originProjects = [origin].flat();
29
29
  return { sql: `${scope.sql} AND (${col}origin_project = '' OR ${originInSql(originProjects, `${col}origin_project`)})`, params: [...scope.params, ...originProjects] };
30
30
  }
31
- /** Scope rule for recall: none requested is default-deny; 'exact' narrows to the request; 'additive' adds it to the default set, unless it is personal, which only `ownScope` opens. */
31
+ /** Scope rule for recall: none requested is default-deny; 'exact' narrows to the request; 'additive' adds it to the default set, unless it is personal,
32
+ * which only `ownScope` opens. */
32
33
  export function recallScopeFilter(requestedScope, mode, ownScope) {
33
34
  if (!requestedScope || (mode === 'additive' && isPersonalScope(requestedScope)))
34
35
  return { mode: 'default-deny', ownScope };
@@ -62,19 +63,14 @@ function loadSearchRows(db, query, limit, tenantId, options = {}) {
62
63
  return selectAllCandidates(db, p, limit);
63
64
  }
64
65
  function searchPredicates(tenantId, scopeFilter, includeSuperseded, originProjects) {
65
- // tenantId undefined = no tenant filter (legacy callers / cross-deployment
66
- // helpers). tenantId set = strict tenant isolation, leveraging the composite
67
- // idx_memories_tenant_created (leading column tenant_id, O(log n) lookup).
66
+ // tenantId undefined = no tenant filter (legacy callers / cross-deployment helpers); set = strict isolation via the composite idx_memories_tenant_created.
68
67
  const tenantPredicate = tenantId !== undefined ? ` AND m.tenant_id = ?` : '';
69
68
  const tenantOnlyPredicate = tenantId !== undefined ? ` WHERE tenant_id = ?` : '';
70
69
  const tenantParams = tenantId !== undefined ? [tenantId] : [];
71
70
  // Defensive: kind='archived' is a transient sentinel inside archiveRawMemory's SAVEPOINT, so this only
72
71
  // guards against a dropped SAVEPOINT, a persisted 'archived' state, or direct-SQL writes.
73
72
  const archivedClauseAlias = ` AND m.kind != 'archived'`;
74
- // For the "tenant-only" path: if no tenant set, tenantOnlyPredicate is '',
75
- // so prepend WHERE; if tenant set, append AND. handled in each call site
76
- // by always joining `tenantOnlyPredicate + archivedClauseTenantOnly` where
77
- // the latter switches between " AND" and " WHERE" based on caller context.
73
+ // Tenant-only path: with no tenant `tenantOnlyPredicate` is '', so the archived clause switches between ' AND' and ' WHERE' by caller context.
78
74
  const archivedClauseTenantOnly = tenantId !== undefined ? ` AND kind != 'archived'` : ` WHERE kind != 'archived'`;
79
75
  const aliasScope = withProject(recallScopeClause('m.', scopeFilter), 'm.', originProjects);
80
76
  const plainScope = withProject(recallScopeClause('', scopeFilter), '', originProjects);
@@ -98,11 +94,8 @@ function selectAllCandidates(db, p, limit) {
98
94
  function selectFtsCandidates(db, terms, p, limit) {
99
95
  try {
100
96
  const ftsQuery = terms.map((t) => `"${t.replace(/"/g, '""')}"`).join(' OR ');
101
- // memories_fts virtual table has no tenant_id column; filter via the
102
- // joined memories row (cheap with idx_memories_tenant_created leading
103
- // on tenant_id).
104
- // SAFETY: MEMORY_SEARCH_COLUMNS aliases every column to the same name
105
- // MEMORY_SELECT_COLUMNS uses (plus bm25_score), matching MemoryRow.
97
+ // memories_fts has no tenant_id column; filter via the joined memories row (cheap with idx_memories_tenant_created).
98
+ // SAFETY: MEMORY_SEARCH_COLUMNS aliases every column like MEMORY_SELECT_COLUMNS (plus bm25_score), matching MemoryRow.
106
99
  return db.prepare(`
107
100
  SELECT ${MEMORY_SEARCH_COLUMNS}
108
101
  FROM memories m
@@ -146,47 +139,18 @@ function selectLikeCandidates(db, terms, p, limit) {
146
139
  LIMIT ?
147
140
  `).all(...p.tenantParams, ...p.scopeParams, Math.max(limit, LIKE_WINDOW_ROWS), ...params, limit);
148
141
  }
149
- /**
150
- * Load likely search candidates directly from SQLite.
151
- * Uses FTS5 when available, falls back to LIKE matching, then full-store fallback.
152
- *
153
- * When `tenantId` is provided, every SELECT (FTS join, LIKE, fallback) filters
154
- * by tenant_id. Cross-tenant memories never surface. Omitted = no filter.
155
- */
142
+ /** Load likely search candidates: FTS5 when available, else LIKE, then full-store fallback. With `tenantId` every SELECT filters by it; omitted = no filter. */
156
143
  export function loadSearchEntries(hippoRoot, query, limit = DEFAULT_SEARCH_CANDIDATE_LIMIT, tenantId) {
157
- const db = openStore(hippoRoot);
158
- try {
144
+ return onHandle(hippoRoot, (db) => {
159
145
  return loadSearchRows(db, query, limit, tenantId).map(rowToEntry);
160
- }
161
- finally {
162
- closeHippoDb(db);
163
- }
146
+ }, openStore);
164
147
  }
165
- /**
166
- * Recall-mode loader. Pushes the recall-side scope predicate into SQL so
167
- * `unknown:legacy` cannot leak via any consumer that hasn't remembered to re-filter.
168
- *
169
- * - `requestedScope` undefined / '': default-deny on `unknown:legacy`, admitting `ownScope`, the caller's personal scope.
170
- * - `requestedScope` non-empty string: exact match on `m.scope = requestedScope`.
171
- *
172
- * Private scopes: SQL applies a conservative `NOT LIKE '%:private:%'` before the LIMIT window so private
173
- * rows cannot starve admitted ones; `passesScopeFilterForRecall` stays the exact JS post-filter.
174
- *
175
- * Consumers: `api.recall`, `cmdRecall`/`cmdExplain` direct CLI paths
176
- * and `searchBothHybrid` recall mode. Background pipelines
177
- * (`consolidate`, `embeddings`, `refine-llm`, ...) keep using
178
- * `loadSearchEntries` so they can see quarantined rows when needed.
179
- *
180
- * `tenantId` is optional because searchBothHybrid's is; undefined means no tenant filter.
181
- */
148
+ /** Recall-mode loader: scope predicate in SQL so `unknown:legacy` cannot leak. Empty `requestedScope` default-denies (admits `ownScope`); else exact match.
149
+ * SQL `NOT LIKE '%:private:%'` runs before the LIMIT so private rows cannot starve admitted ones; `passesScopeFilterForRecall` is the exact post-filter. */
182
150
  export function loadRecallSearchEntries(hippoRoot, query, limit = DEFAULT_SEARCH_CANDIDATE_LIMIT, tenantId, requestedScope, explicitScopeMode = 'exact', includeSuperseded = true, originProjects, ownScope) {
183
- const db = openStore(hippoRoot);
184
- try {
151
+ return onHandle(hippoRoot, (db) => {
185
152
  return loadRecallSearchEntriesFromDb(db, query, { limit, tenantId, requestedScope, explicitScopeMode, includeSuperseded, originProjects, ownScope });
186
- }
187
- finally {
188
- closeHippoDb(db);
189
- }
153
+ }, openStore);
190
154
  }
191
155
  // Split out so callers with an already-open db (the prompt-recall path) skip
192
156
  // the initStore+open/close cycle per store per call.