hippo-memory 1.44.0 → 1.45.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 (528) hide show
  1. package/README.md +12 -10
  2. package/bin/hippo.js +3 -1
  3. package/dist/api.d.ts +21 -21
  4. package/dist/api.js +69 -42
  5. package/dist/audit.d.ts +1 -1
  6. package/dist/audit.js +9 -0
  7. package/dist/autolearn.d.ts +1 -1
  8. package/dist/autolearn.js +2 -1
  9. package/dist/cli.d.ts +3 -0
  10. package/dist/cli.js +151 -72
  11. package/dist/client.d.ts +4 -21
  12. package/dist/client.js +3 -112
  13. package/dist/config.js +2 -1
  14. package/dist/consolidate.d.ts +3 -0
  15. package/dist/consolidate.js +44 -42
  16. package/dist/dag.d.ts +1 -0
  17. package/dist/dag.js +10 -5
  18. package/dist/dashboard.js +7 -3
  19. package/dist/db.js +12 -23
  20. package/dist/dedupe.d.ts +1 -0
  21. package/dist/dedupe.js +4 -7
  22. package/dist/embedding-provider.js +2 -1
  23. package/dist/embeddings.js +81 -8
  24. package/dist/extract.d.ts +2 -0
  25. package/dist/extract.js +9 -4
  26. package/dist/mcp/server.js +21 -36
  27. package/dist/memory.d.ts +3 -0
  28. package/dist/memory.js +7 -1
  29. package/dist/refine-llm.js +3 -2
  30. package/dist/rerankers/jev.js +3 -2
  31. package/dist/rerankers/llm.js +3 -2
  32. package/dist/search.js +3 -3
  33. package/dist/server.d.ts +5 -0
  34. package/dist/server.js +39 -29
  35. package/dist/shared.js +1 -1
  36. package/dist/store.d.ts +18 -11
  37. package/dist/store.js +144 -63
  38. package/dist/version.d.ts +4 -6
  39. package/dist/version.js +4 -7
  40. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  41. package/extensions/openclaw-plugin/package.json +1 -1
  42. package/openclaw.plugin.json +1 -1
  43. package/package.json +6 -3
  44. package/dist/ablation.d.ts.map +0 -1
  45. package/dist/ablation.js.map +0 -1
  46. package/dist/ambient.d.ts.map +0 -1
  47. package/dist/ambient.js.map +0 -1
  48. package/dist/api.d.ts.map +0 -1
  49. package/dist/api.js.map +0 -1
  50. package/dist/audit-prune.d.ts.map +0 -1
  51. package/dist/audit-prune.js.map +0 -1
  52. package/dist/audit.d.ts.map +0 -1
  53. package/dist/audit.js.map +0 -1
  54. package/dist/auth.d.ts.map +0 -1
  55. package/dist/auth.js.map +0 -1
  56. package/dist/autolearn.d.ts.map +0 -1
  57. package/dist/autolearn.js.map +0 -1
  58. package/dist/availability.d.ts.map +0 -1
  59. package/dist/availability.js.map +0 -1
  60. package/dist/benchmarks/e1.3/incident-recall-eval.js +0 -78
  61. package/dist/benchmarks/e1.3/incident-recall-eval.js.map +0 -1
  62. package/dist/benchmarks/e1.3/slack-1000-event-smoke.js +0 -103
  63. package/dist/benchmarks/e1.3/slack-1000-event-smoke.js.map +0 -1
  64. package/dist/capture.d.ts.map +0 -1
  65. package/dist/capture.js.map +0 -1
  66. package/dist/card-detail.d.ts.map +0 -1
  67. package/dist/card-detail.js.map +0 -1
  68. package/dist/card.d.ts.map +0 -1
  69. package/dist/card.js.map +0 -1
  70. package/dist/cli.d.ts.map +0 -1
  71. package/dist/cli.js.map +0 -1
  72. package/dist/client.d.ts.map +0 -1
  73. package/dist/client.js.map +0 -1
  74. package/dist/compare.d.ts.map +0 -1
  75. package/dist/compare.js.map +0 -1
  76. package/dist/config.d.ts.map +0 -1
  77. package/dist/config.js.map +0 -1
  78. package/dist/connectors/github/backfill.d.ts.map +0 -1
  79. package/dist/connectors/github/backfill.js.map +0 -1
  80. package/dist/connectors/github/cli-impl.d.ts.map +0 -1
  81. package/dist/connectors/github/cli-impl.js.map +0 -1
  82. package/dist/connectors/github/deletion.d.ts.map +0 -1
  83. package/dist/connectors/github/deletion.js.map +0 -1
  84. package/dist/connectors/github/dlq.d.ts.map +0 -1
  85. package/dist/connectors/github/dlq.js.map +0 -1
  86. package/dist/connectors/github/idempotency.d.ts.map +0 -1
  87. package/dist/connectors/github/idempotency.js.map +0 -1
  88. package/dist/connectors/github/ingest.d.ts.map +0 -1
  89. package/dist/connectors/github/ingest.js.map +0 -1
  90. package/dist/connectors/github/octokit-client.d.ts.map +0 -1
  91. package/dist/connectors/github/octokit-client.js.map +0 -1
  92. package/dist/connectors/github/ratelimit.d.ts.map +0 -1
  93. package/dist/connectors/github/ratelimit.js.map +0 -1
  94. package/dist/connectors/github/scope.d.ts.map +0 -1
  95. package/dist/connectors/github/scope.js.map +0 -1
  96. package/dist/connectors/github/signature.d.ts.map +0 -1
  97. package/dist/connectors/github/signature.js.map +0 -1
  98. package/dist/connectors/github/tenant-routing.d.ts.map +0 -1
  99. package/dist/connectors/github/tenant-routing.js.map +0 -1
  100. package/dist/connectors/github/transform.d.ts.map +0 -1
  101. package/dist/connectors/github/transform.js.map +0 -1
  102. package/dist/connectors/github/types.d.ts.map +0 -1
  103. package/dist/connectors/github/types.js.map +0 -1
  104. package/dist/connectors/slack/backfill.d.ts.map +0 -1
  105. package/dist/connectors/slack/backfill.js.map +0 -1
  106. package/dist/connectors/slack/deletion.d.ts.map +0 -1
  107. package/dist/connectors/slack/deletion.js.map +0 -1
  108. package/dist/connectors/slack/dlq.d.ts.map +0 -1
  109. package/dist/connectors/slack/dlq.js.map +0 -1
  110. package/dist/connectors/slack/idempotency.d.ts.map +0 -1
  111. package/dist/connectors/slack/idempotency.js.map +0 -1
  112. package/dist/connectors/slack/ingest.d.ts.map +0 -1
  113. package/dist/connectors/slack/ingest.js.map +0 -1
  114. package/dist/connectors/slack/ratelimit.d.ts.map +0 -1
  115. package/dist/connectors/slack/ratelimit.js.map +0 -1
  116. package/dist/connectors/slack/scope.d.ts.map +0 -1
  117. package/dist/connectors/slack/scope.js.map +0 -1
  118. package/dist/connectors/slack/signature.d.ts.map +0 -1
  119. package/dist/connectors/slack/signature.js.map +0 -1
  120. package/dist/connectors/slack/tenant-routing.d.ts.map +0 -1
  121. package/dist/connectors/slack/tenant-routing.js.map +0 -1
  122. package/dist/connectors/slack/transform.d.ts.map +0 -1
  123. package/dist/connectors/slack/transform.js.map +0 -1
  124. package/dist/connectors/slack/types.d.ts.map +0 -1
  125. package/dist/connectors/slack/types.js.map +0 -1
  126. package/dist/connectors/slack/web-client.d.ts.map +0 -1
  127. package/dist/connectors/slack/web-client.js.map +0 -1
  128. package/dist/connectors/slack/workspaces.d.ts.map +0 -1
  129. package/dist/connectors/slack/workspaces.js.map +0 -1
  130. package/dist/consolidate.d.ts.map +0 -1
  131. package/dist/consolidate.js.map +0 -1
  132. package/dist/correction-latency.d.ts.map +0 -1
  133. package/dist/correction-latency.js.map +0 -1
  134. package/dist/customer-notes.d.ts.map +0 -1
  135. package/dist/customer-notes.js.map +0 -1
  136. package/dist/dag.d.ts.map +0 -1
  137. package/dist/dag.js.map +0 -1
  138. package/dist/dashboard.d.ts.map +0 -1
  139. package/dist/dashboard.js.map +0 -1
  140. package/dist/db.d.ts.map +0 -1
  141. package/dist/db.js.map +0 -1
  142. package/dist/decisions.d.ts.map +0 -1
  143. package/dist/decisions.js.map +0 -1
  144. package/dist/dedupe.d.ts.map +0 -1
  145. package/dist/dedupe.js.map +0 -1
  146. package/dist/embedding-provider.d.ts.map +0 -1
  147. package/dist/embedding-provider.js.map +0 -1
  148. package/dist/embeddings.d.ts.map +0 -1
  149. package/dist/embeddings.js.map +0 -1
  150. package/dist/eval-suite.d.ts.map +0 -1
  151. package/dist/eval-suite.js.map +0 -1
  152. package/dist/eval.d.ts.map +0 -1
  153. package/dist/eval.js.map +0 -1
  154. package/dist/extensions/openclaw-plugin/index.js.map +0 -1
  155. package/dist/extract.d.ts.map +0 -1
  156. package/dist/extract.js.map +0 -1
  157. package/dist/forward-claim-detector.d.ts.map +0 -1
  158. package/dist/forward-claim-detector.js.map +0 -1
  159. package/dist/goals.d.ts.map +0 -1
  160. package/dist/goals.js.map +0 -1
  161. package/dist/graph-extract.d.ts.map +0 -1
  162. package/dist/graph-extract.js.map +0 -1
  163. package/dist/graph-recall.d.ts.map +0 -1
  164. package/dist/graph-recall.js.map +0 -1
  165. package/dist/graph-stream.d.ts.map +0 -1
  166. package/dist/graph-stream.js.map +0 -1
  167. package/dist/graph-view.d.ts.map +0 -1
  168. package/dist/graph-view.js.map +0 -1
  169. package/dist/graph.d.ts.map +0 -1
  170. package/dist/graph.js.map +0 -1
  171. package/dist/handoff.d.ts.map +0 -1
  172. package/dist/handoff.js.map +0 -1
  173. package/dist/hooks.d.ts.map +0 -1
  174. package/dist/hooks.js.map +0 -1
  175. package/dist/importers.d.ts.map +0 -1
  176. package/dist/importers.js.map +0 -1
  177. package/dist/incidents.d.ts.map +0 -1
  178. package/dist/incidents.js.map +0 -1
  179. package/dist/index.d.ts.map +0 -1
  180. package/dist/index.js.map +0 -1
  181. package/dist/invalidation.d.ts.map +0 -1
  182. package/dist/invalidation.js.map +0 -1
  183. package/dist/mcp/framing.d.ts.map +0 -1
  184. package/dist/mcp/framing.js.map +0 -1
  185. package/dist/mcp/server.d.ts.map +0 -1
  186. package/dist/mcp/server.js.map +0 -1
  187. package/dist/memory-value-weights.d.ts.map +0 -1
  188. package/dist/memory-value-weights.js.map +0 -1
  189. package/dist/memory-value.d.ts.map +0 -1
  190. package/dist/memory-value.js.map +0 -1
  191. package/dist/memory.d.ts.map +0 -1
  192. package/dist/memory.js.map +0 -1
  193. package/dist/multihop.d.ts.map +0 -1
  194. package/dist/multihop.js.map +0 -1
  195. package/dist/owner-validation.d.ts.map +0 -1
  196. package/dist/owner-validation.js.map +0 -1
  197. package/dist/path-context.d.ts.map +0 -1
  198. package/dist/path-context.js.map +0 -1
  199. package/dist/physics-config.d.ts.map +0 -1
  200. package/dist/physics-config.js.map +0 -1
  201. package/dist/physics-state.d.ts.map +0 -1
  202. package/dist/physics-state.js.map +0 -1
  203. package/dist/physics.d.ts.map +0 -1
  204. package/dist/physics.js.map +0 -1
  205. package/dist/policies.d.ts.map +0 -1
  206. package/dist/policies.js.map +0 -1
  207. package/dist/postinstall.d.ts.map +0 -1
  208. package/dist/postinstall.js.map +0 -1
  209. package/dist/predictions.d.ts.map +0 -1
  210. package/dist/predictions.js.map +0 -1
  211. package/dist/processes.d.ts.map +0 -1
  212. package/dist/processes.js.map +0 -1
  213. package/dist/project-briefs.d.ts.map +0 -1
  214. package/dist/project-briefs.js.map +0 -1
  215. package/dist/project-identity.d.ts.map +0 -1
  216. package/dist/project-identity.js.map +0 -1
  217. package/dist/provenance-coverage.d.ts.map +0 -1
  218. package/dist/provenance-coverage.js.map +0 -1
  219. package/dist/rate-limit.d.ts.map +0 -1
  220. package/dist/rate-limit.js.map +0 -1
  221. package/dist/raw-archive-mirror-cleanup.d.ts.map +0 -1
  222. package/dist/raw-archive-mirror-cleanup.js.map +0 -1
  223. package/dist/raw-archive.d.ts.map +0 -1
  224. package/dist/raw-archive.js.map +0 -1
  225. package/dist/recall-history.d.ts.map +0 -1
  226. package/dist/recall-history.js.map +0 -1
  227. package/dist/recall-scope.d.ts.map +0 -1
  228. package/dist/recall-scope.js.map +0 -1
  229. package/dist/recall-trace.d.ts.map +0 -1
  230. package/dist/recall-trace.js.map +0 -1
  231. package/dist/refine-llm.d.ts.map +0 -1
  232. package/dist/refine-llm.js.map +0 -1
  233. package/dist/reject-flow.d.ts.map +0 -1
  234. package/dist/reject-flow.js.map +0 -1
  235. package/dist/rejection.d.ts.map +0 -1
  236. package/dist/rejection.js.map +0 -1
  237. package/dist/replay.d.ts.map +0 -1
  238. package/dist/replay.js.map +0 -1
  239. package/dist/rerankers/cross-encoder.d.ts.map +0 -1
  240. package/dist/rerankers/cross-encoder.js.map +0 -1
  241. package/dist/rerankers/index.d.ts.map +0 -1
  242. package/dist/rerankers/index.js.map +0 -1
  243. package/dist/rerankers/jev.d.ts.map +0 -1
  244. package/dist/rerankers/jev.js.map +0 -1
  245. package/dist/rerankers/llm.d.ts.map +0 -1
  246. package/dist/rerankers/llm.js.map +0 -1
  247. package/dist/rerankers/types.d.ts.map +0 -1
  248. package/dist/rerankers/types.js.map +0 -1
  249. package/dist/rrf.d.ts.map +0 -1
  250. package/dist/rrf.js.map +0 -1
  251. package/dist/salience.d.ts.map +0 -1
  252. package/dist/salience.js.map +0 -1
  253. package/dist/scheduler.d.ts.map +0 -1
  254. package/dist/scheduler.js.map +0 -1
  255. package/dist/scope.d.ts.map +0 -1
  256. package/dist/scope.js.map +0 -1
  257. package/dist/search.d.ts.map +0 -1
  258. package/dist/search.js.map +0 -1
  259. package/dist/secret-detect.d.ts.map +0 -1
  260. package/dist/secret-detect.js.map +0 -1
  261. package/dist/server-detect.d.ts.map +0 -1
  262. package/dist/server-detect.js.map +0 -1
  263. package/dist/server.d.ts.map +0 -1
  264. package/dist/server.js.map +0 -1
  265. package/dist/shared.d.ts.map +0 -1
  266. package/dist/shared.js.map +0 -1
  267. package/dist/skills.d.ts.map +0 -1
  268. package/dist/skills.js.map +0 -1
  269. package/dist/sleep-redact.d.ts +0 -58
  270. package/dist/sleep-redact.d.ts.map +0 -1
  271. package/dist/sleep-redact.js +0 -80
  272. package/dist/sleep-redact.js.map +0 -1
  273. package/dist/src/ablation.js +0 -138
  274. package/dist/src/ablation.js.map +0 -1
  275. package/dist/src/ambient.js +0 -148
  276. package/dist/src/ambient.js.map +0 -1
  277. package/dist/src/api.js +0 -2109
  278. package/dist/src/api.js.map +0 -1
  279. package/dist/src/audit-prune.js +0 -109
  280. package/dist/src/audit-prune.js.map +0 -1
  281. package/dist/src/audit.js +0 -213
  282. package/dist/src/audit.js.map +0 -1
  283. package/dist/src/auth.js +0 -97
  284. package/dist/src/auth.js.map +0 -1
  285. package/dist/src/autolearn.js +0 -174
  286. package/dist/src/autolearn.js.map +0 -1
  287. package/dist/src/availability.js +0 -94
  288. package/dist/src/availability.js.map +0 -1
  289. package/dist/src/capture.js +0 -1346
  290. package/dist/src/capture.js.map +0 -1
  291. package/dist/src/card-detail.js +0 -15
  292. package/dist/src/card-detail.js.map +0 -1
  293. package/dist/src/card.js +0 -19
  294. package/dist/src/card.js.map +0 -1
  295. package/dist/src/cli.js +0 -9387
  296. package/dist/src/cli.js.map +0 -1
  297. package/dist/src/client.js +0 -237
  298. package/dist/src/client.js.map +0 -1
  299. package/dist/src/compare.js +0 -122
  300. package/dist/src/compare.js.map +0 -1
  301. package/dist/src/config.js +0 -135
  302. package/dist/src/config.js.map +0 -1
  303. package/dist/src/connectors/github/backfill.js +0 -281
  304. package/dist/src/connectors/github/backfill.js.map +0 -1
  305. package/dist/src/connectors/github/cli-impl.js +0 -234
  306. package/dist/src/connectors/github/cli-impl.js.map +0 -1
  307. package/dist/src/connectors/github/deletion.js +0 -85
  308. package/dist/src/connectors/github/deletion.js.map +0 -1
  309. package/dist/src/connectors/github/dlq.js +0 -190
  310. package/dist/src/connectors/github/dlq.js.map +0 -1
  311. package/dist/src/connectors/github/idempotency.js +0 -27
  312. package/dist/src/connectors/github/idempotency.js.map +0 -1
  313. package/dist/src/connectors/github/ingest.js +0 -156
  314. package/dist/src/connectors/github/ingest.js.map +0 -1
  315. package/dist/src/connectors/github/octokit-client.js +0 -70
  316. package/dist/src/connectors/github/octokit-client.js.map +0 -1
  317. package/dist/src/connectors/github/ratelimit.js +0 -31
  318. package/dist/src/connectors/github/ratelimit.js.map +0 -1
  319. package/dist/src/connectors/github/scope.js +0 -13
  320. package/dist/src/connectors/github/scope.js.map +0 -1
  321. package/dist/src/connectors/github/signature.js +0 -81
  322. package/dist/src/connectors/github/signature.js.map +0 -1
  323. package/dist/src/connectors/github/tenant-routing.js +0 -69
  324. package/dist/src/connectors/github/tenant-routing.js.map +0 -1
  325. package/dist/src/connectors/github/transform.js +0 -103
  326. package/dist/src/connectors/github/transform.js.map +0 -1
  327. package/dist/src/connectors/github/types.js +0 -100
  328. package/dist/src/connectors/github/types.js.map +0 -1
  329. package/dist/src/connectors/slack/backfill.js +0 -78
  330. package/dist/src/connectors/slack/backfill.js.map +0 -1
  331. package/dist/src/connectors/slack/deletion.js +0 -59
  332. package/dist/src/connectors/slack/deletion.js.map +0 -1
  333. package/dist/src/connectors/slack/dlq.js +0 -224
  334. package/dist/src/connectors/slack/dlq.js.map +0 -1
  335. package/dist/src/connectors/slack/idempotency.js +0 -31
  336. package/dist/src/connectors/slack/idempotency.js.map +0 -1
  337. package/dist/src/connectors/slack/ingest.js +0 -109
  338. package/dist/src/connectors/slack/ingest.js.map +0 -1
  339. package/dist/src/connectors/slack/ratelimit.js +0 -18
  340. package/dist/src/connectors/slack/ratelimit.js.map +0 -1
  341. package/dist/src/connectors/slack/scope.js +0 -13
  342. package/dist/src/connectors/slack/scope.js.map +0 -1
  343. package/dist/src/connectors/slack/signature.js +0 -27
  344. package/dist/src/connectors/slack/signature.js.map +0 -1
  345. package/dist/src/connectors/slack/tenant-routing.js +0 -41
  346. package/dist/src/connectors/slack/tenant-routing.js.map +0 -1
  347. package/dist/src/connectors/slack/transform.js +0 -47
  348. package/dist/src/connectors/slack/transform.js.map +0 -1
  349. package/dist/src/connectors/slack/types.js +0 -35
  350. package/dist/src/connectors/slack/types.js.map +0 -1
  351. package/dist/src/connectors/slack/web-client.js +0 -43
  352. package/dist/src/connectors/slack/web-client.js.map +0 -1
  353. package/dist/src/connectors/slack/workspaces.js +0 -62
  354. package/dist/src/connectors/slack/workspaces.js.map +0 -1
  355. package/dist/src/consolidate.js +0 -978
  356. package/dist/src/consolidate.js.map +0 -1
  357. package/dist/src/correction-latency.js +0 -74
  358. package/dist/src/correction-latency.js.map +0 -1
  359. package/dist/src/customer-notes.js +0 -325
  360. package/dist/src/customer-notes.js.map +0 -1
  361. package/dist/src/dag.js +0 -352
  362. package/dist/src/dag.js.map +0 -1
  363. package/dist/src/dashboard.js +0 -258
  364. package/dist/src/dashboard.js.map +0 -1
  365. package/dist/src/db.js +0 -2731
  366. package/dist/src/db.js.map +0 -1
  367. package/dist/src/decisions.js +0 -304
  368. package/dist/src/decisions.js.map +0 -1
  369. package/dist/src/dedupe.js +0 -141
  370. package/dist/src/dedupe.js.map +0 -1
  371. package/dist/src/embedding-provider.js +0 -314
  372. package/dist/src/embedding-provider.js.map +0 -1
  373. package/dist/src/embeddings.js +0 -543
  374. package/dist/src/embeddings.js.map +0 -1
  375. package/dist/src/eval-suite.js +0 -294
  376. package/dist/src/eval-suite.js.map +0 -1
  377. package/dist/src/eval.js +0 -187
  378. package/dist/src/eval.js.map +0 -1
  379. package/dist/src/extract.js +0 -117
  380. package/dist/src/extract.js.map +0 -1
  381. package/dist/src/forward-claim-detector.js +0 -117
  382. package/dist/src/forward-claim-detector.js.map +0 -1
  383. package/dist/src/goals.js +0 -399
  384. package/dist/src/goals.js.map +0 -1
  385. package/dist/src/graph-extract.js +0 -314
  386. package/dist/src/graph-extract.js.map +0 -1
  387. package/dist/src/graph-recall.js +0 -277
  388. package/dist/src/graph-recall.js.map +0 -1
  389. package/dist/src/graph-stream.js +0 -176
  390. package/dist/src/graph-stream.js.map +0 -1
  391. package/dist/src/graph-view.js +0 -310
  392. package/dist/src/graph-view.js.map +0 -1
  393. package/dist/src/graph.js +0 -762
  394. package/dist/src/graph.js.map +0 -1
  395. package/dist/src/handoff.js +0 -65
  396. package/dist/src/handoff.js.map +0 -1
  397. package/dist/src/hooks.js +0 -926
  398. package/dist/src/hooks.js.map +0 -1
  399. package/dist/src/importers.js +0 -881
  400. package/dist/src/importers.js.map +0 -1
  401. package/dist/src/incidents.js +0 -336
  402. package/dist/src/incidents.js.map +0 -1
  403. package/dist/src/index.js +0 -32
  404. package/dist/src/index.js.map +0 -1
  405. package/dist/src/invalidation.js +0 -129
  406. package/dist/src/invalidation.js.map +0 -1
  407. package/dist/src/mcp/framing.js +0 -45
  408. package/dist/src/mcp/framing.js.map +0 -1
  409. package/dist/src/mcp/server.js +0 -1298
  410. package/dist/src/mcp/server.js.map +0 -1
  411. package/dist/src/memory-value-weights.js +0 -31
  412. package/dist/src/memory-value-weights.js.map +0 -1
  413. package/dist/src/memory-value.js +0 -261
  414. package/dist/src/memory-value.js.map +0 -1
  415. package/dist/src/memory.js +0 -425
  416. package/dist/src/memory.js.map +0 -1
  417. package/dist/src/multihop.js +0 -35
  418. package/dist/src/multihop.js.map +0 -1
  419. package/dist/src/owner-validation.js +0 -56
  420. package/dist/src/owner-validation.js.map +0 -1
  421. package/dist/src/path-context.js +0 -48
  422. package/dist/src/path-context.js.map +0 -1
  423. package/dist/src/physics-config.js +0 -26
  424. package/dist/src/physics-config.js.map +0 -1
  425. package/dist/src/physics-state.js +0 -172
  426. package/dist/src/physics-state.js.map +0 -1
  427. package/dist/src/physics.js +0 -378
  428. package/dist/src/physics.js.map +0 -1
  429. package/dist/src/policies.js +0 -414
  430. package/dist/src/policies.js.map +0 -1
  431. package/dist/src/postinstall.js +0 -101
  432. package/dist/src/postinstall.js.map +0 -1
  433. package/dist/src/predictions.js +0 -629
  434. package/dist/src/predictions.js.map +0 -1
  435. package/dist/src/processes.js +0 -349
  436. package/dist/src/processes.js.map +0 -1
  437. package/dist/src/project-briefs.js +0 -492
  438. package/dist/src/project-briefs.js.map +0 -1
  439. package/dist/src/project-identity.js +0 -200
  440. package/dist/src/project-identity.js.map +0 -1
  441. package/dist/src/provenance-coverage.js +0 -23
  442. package/dist/src/provenance-coverage.js.map +0 -1
  443. package/dist/src/rate-limit.js +0 -60
  444. package/dist/src/rate-limit.js.map +0 -1
  445. package/dist/src/raw-archive-mirror-cleanup.js +0 -55
  446. package/dist/src/raw-archive-mirror-cleanup.js.map +0 -1
  447. package/dist/src/raw-archive.js +0 -91
  448. package/dist/src/raw-archive.js.map +0 -1
  449. package/dist/src/recall-history.js +0 -235
  450. package/dist/src/recall-history.js.map +0 -1
  451. package/dist/src/recall-scope.js +0 -89
  452. package/dist/src/recall-scope.js.map +0 -1
  453. package/dist/src/recall-trace.js +0 -186
  454. package/dist/src/recall-trace.js.map +0 -1
  455. package/dist/src/refine-llm.js +0 -156
  456. package/dist/src/refine-llm.js.map +0 -1
  457. package/dist/src/reject-flow.js +0 -209
  458. package/dist/src/reject-flow.js.map +0 -1
  459. package/dist/src/rejection.js +0 -160
  460. package/dist/src/rejection.js.map +0 -1
  461. package/dist/src/replay.js +0 -122
  462. package/dist/src/replay.js.map +0 -1
  463. package/dist/src/rerankers/cross-encoder.js +0 -137
  464. package/dist/src/rerankers/cross-encoder.js.map +0 -1
  465. package/dist/src/rerankers/index.js +0 -20
  466. package/dist/src/rerankers/index.js.map +0 -1
  467. package/dist/src/rerankers/jev.js +0 -119
  468. package/dist/src/rerankers/jev.js.map +0 -1
  469. package/dist/src/rerankers/llm.js +0 -80
  470. package/dist/src/rerankers/llm.js.map +0 -1
  471. package/dist/src/rerankers/types.js +0 -2
  472. package/dist/src/rerankers/types.js.map +0 -1
  473. package/dist/src/rrf.js +0 -61
  474. package/dist/src/rrf.js.map +0 -1
  475. package/dist/src/salience.js +0 -74
  476. package/dist/src/salience.js.map +0 -1
  477. package/dist/src/scheduler.js +0 -77
  478. package/dist/src/scheduler.js.map +0 -1
  479. package/dist/src/scope.js +0 -35
  480. package/dist/src/scope.js.map +0 -1
  481. package/dist/src/search.js +0 -1003
  482. package/dist/src/search.js.map +0 -1
  483. package/dist/src/secret-detect.js +0 -95
  484. package/dist/src/secret-detect.js.map +0 -1
  485. package/dist/src/server-detect.js +0 -231
  486. package/dist/src/server-detect.js.map +0 -1
  487. package/dist/src/server.js +0 -3255
  488. package/dist/src/server.js.map +0 -1
  489. package/dist/src/shared.js +0 -502
  490. package/dist/src/shared.js.map +0 -1
  491. package/dist/src/skills.js +0 -346
  492. package/dist/src/skills.js.map +0 -1
  493. package/dist/src/sleep-redact.js +0 -80
  494. package/dist/src/sleep-redact.js.map +0 -1
  495. package/dist/src/sso.js +0 -22
  496. package/dist/src/sso.js.map +0 -1
  497. package/dist/src/stdin.js +0 -41
  498. package/dist/src/stdin.js.map +0 -1
  499. package/dist/src/store.js +0 -3749
  500. package/dist/src/store.js.map +0 -1
  501. package/dist/src/tenant.js +0 -17
  502. package/dist/src/tenant.js.map +0 -1
  503. package/dist/src/trace.js +0 -72
  504. package/dist/src/trace.js.map +0 -1
  505. package/dist/src/version.js +0 -40
  506. package/dist/src/version.js.map +0 -1
  507. package/dist/src/working-memory.js +0 -157
  508. package/dist/src/working-memory.js.map +0 -1
  509. package/dist/src/yaml.js +0 -107
  510. package/dist/src/yaml.js.map +0 -1
  511. package/dist/sso.d.ts +0 -13
  512. package/dist/sso.d.ts.map +0 -1
  513. package/dist/sso.js +0 -22
  514. package/dist/sso.js.map +0 -1
  515. package/dist/stdin.d.ts.map +0 -1
  516. package/dist/stdin.js.map +0 -1
  517. package/dist/store.d.ts.map +0 -1
  518. package/dist/store.js.map +0 -1
  519. package/dist/tenant.d.ts.map +0 -1
  520. package/dist/tenant.js.map +0 -1
  521. package/dist/trace.d.ts.map +0 -1
  522. package/dist/trace.js.map +0 -1
  523. package/dist/version.d.ts.map +0 -1
  524. package/dist/version.js.map +0 -1
  525. package/dist/working-memory.d.ts.map +0 -1
  526. package/dist/working-memory.js.map +0 -1
  527. package/dist/yaml.d.ts.map +0 -1
  528. package/dist/yaml.js.map +0 -1
package/dist/src/graph.js DELETED
@@ -1,762 +0,0 @@
1
- /**
2
- * E3.3 graph layer over consolidated state - the graph-on-consolidated guard.
3
- * (docs/plans/2026-06-01-e3-graph-guard.md).
4
- *
5
- * A graph of canonical `entities` (person/project/customer/system/policy/decision) and
6
- * `relations` (owns/supersedes/depends-on/blocked-by/references) sits ON TOP OF
7
- * consolidated memories. The hard rule: the graph NEVER indexes the raw layer - every
8
- * entity and relation references a memory whose `kind IN ('distilled','superseded')`,
9
- * never `kind='raw'`. Enforced at the DB level (CHECK on source_kind/kind + BEFORE
10
- * INSERT and BEFORE UPDATE triggers that tie source_kind/kind to the FK'd memory's
11
- * actual kind and enforce tenant-match - relations also reject cross-tenant edges), so
12
- * the forbidden state is unrepresentable regardless of code path. These helpers
13
- * surface the same guard as clear throws BEFORE hitting the trigger backstop.
14
- *
15
- * Scope (E3.3 first slice): the substrate + the guard + a thin insert/load/enqueue
16
- * API. The `graph_extraction_queue` is the interface the deferred `hippo sleep`
17
- * enqueue-hook + E3.1 entity extraction will call. No operator surface (CLI/HTTP/SDK)
18
- * until E3.2 multi-hop recall.
19
- */
20
- import { openHippoDb, closeHippoDb } from './db.js';
21
- import { assertTenantId } from './store.js';
22
- const SOURCE_OBJECT_TABLE = {
23
- decision: 'decisions',
24
- policy: 'policies',
25
- customer: 'customer_notes',
26
- project: 'project_briefs',
27
- };
28
- export const GRAPH_ENTITY_TYPES = new Set([
29
- 'person', 'project', 'customer', 'system', 'policy', 'decision',
30
- ]);
31
- export const GRAPH_RELATION_TYPES = new Set([
32
- 'owns', 'supersedes', 'depends-on', 'blocked-by', 'references',
33
- ]);
34
- export const VALID_QUEUE_STATES = new Set([
35
- 'pending', 'processed', 'skipped',
36
- ]);
37
- export const MAX_ENTITY_NAME_LEN = 512;
38
- function rowToEntity(row) {
39
- // SAFETY: entity_type/source_kind/source_object_type are DB CHECK-constrained
40
- // (see db.ts CREATE TABLE entities) to exactly the EntityType/SourceKind/
41
- // SourceObjectType enum values, so the row's column values match those types.
42
- return {
43
- id: row.id,
44
- tenantId: row.tenant_id,
45
- entityType: row.entity_type,
46
- name: row.name,
47
- memoryId: row.memory_id,
48
- sourceKind: row.source_kind,
49
- sourceObjectType: row.source_object_type === null ? undefined : row.source_object_type,
50
- sourceObjectId: row.source_object_id === null ? undefined : row.source_object_id,
51
- createdAt: row.created_at,
52
- };
53
- }
54
- function rowToRelation(row) {
55
- // SAFETY: rel_type/source_kind/source_object_type are DB CHECK-constrained
56
- // (see db.ts CREATE TABLE relations) to exactly the RelationType/SourceKind/
57
- // SourceObjectType enum values, so the row's column values match those types.
58
- return {
59
- id: row.id,
60
- tenantId: row.tenant_id,
61
- fromEntityId: row.from_entity_id,
62
- toEntityId: row.to_entity_id,
63
- relType: row.rel_type,
64
- memoryId: row.memory_id,
65
- sourceKind: row.source_kind,
66
- sourceObjectType: row.source_object_type === null ? undefined : row.source_object_type,
67
- sourceObjectId: row.source_object_id === null ? undefined : row.source_object_id,
68
- createdAt: row.created_at,
69
- };
70
- }
71
- function rowToQueueItem(row) {
72
- // SAFETY: kind/status are DB CHECK-constrained (see db.ts CREATE TABLE
73
- // graph_extraction_queue) to exactly the SourceKind/GraphQueueStatus enum
74
- // values, so the row's column values match those types.
75
- return {
76
- id: row.id,
77
- tenantId: row.tenant_id,
78
- memoryId: row.memory_id,
79
- kind: row.kind,
80
- status: row.status,
81
- enqueuedAt: row.enqueued_at,
82
- processedAt: row.processed_at,
83
- };
84
- }
85
- const ENTITY_COLS = `id, tenant_id, entity_type, name, memory_id, source_kind, source_object_type, source_object_id, created_at`;
86
- const RELATION_COLS = `id, tenant_id, from_entity_id, to_entity_id, rel_type, memory_id, source_kind, source_object_type, source_object_id, created_at`;
87
- const QUEUE_COLS = `id, tenant_id, memory_id, kind, status, enqueued_at, processed_at`;
88
- function resolveConsolidatedSource(db, tenantId, memoryId, sourceObject, label) {
89
- let memKind = null;
90
- let effectiveMemoryId = memoryId;
91
- if (memoryId != null) {
92
- // SAFETY: row's shape matches the two columns (kind, tenant_id) named in
93
- // the SELECT above.
94
- const row = db.prepare(`SELECT kind, tenant_id FROM memories WHERE id = ?`).get(memoryId);
95
- if (!row) {
96
- // Stale / forgotten mirror. Tolerate it IFF a valid source object provides provenance:
97
- // graph-extract reads E2 rows then inserts, and a mirror forgotten/pruned in that window
98
- // must NOT roll back the whole tenant rebuild - the active E2 object survives mirror loss
99
- // (v38 contract; codex round-4 race). Anchor to the object; drop the dead memory pointer.
100
- if (sourceObject == null) {
101
- throw new Error(`${label}: source memory ${memoryId} not found`);
102
- }
103
- effectiveMemoryId = null;
104
- }
105
- else if (row.tenant_id !== tenantId) {
106
- throw new Error(`${label}: source memory ${memoryId} belongs to another tenant`);
107
- }
108
- else if (row.kind === 'raw') {
109
- throw new Error(`${label}: source memory ${memoryId} is raw; the graph indexes consolidated state only`);
110
- }
111
- else if (row.kind !== 'distilled' && row.kind !== 'superseded') {
112
- throw new Error(`${label}: source memory ${memoryId} has unsupported kind '${row.kind}'`);
113
- }
114
- else {
115
- memKind = row.kind;
116
- }
117
- }
118
- // Validate the object pointer WHENEVER it is provided - not only when memory is null
119
- // (codex review): a dual-set row whose object is wrong/closed/cross-tenant would become
120
- // the active provenance after ON DELETE SET NULL and could then block the memory delete.
121
- if (sourceObject != null) {
122
- const table = SOURCE_OBJECT_TABLE[sourceObject.type];
123
- if (!table) {
124
- throw new Error(`${label}: unsupported source_object_type '${sourceObject.type}'`);
125
- }
126
- // `table` is a fixed value from the SOURCE_OBJECT_TABLE map (never user-supplied), so
127
- // this string interpolation is safe; `id`/`tenant_id` stay parametrized.
128
- // SAFETY: row's shape matches the single `status` column named in the
129
- // SELECT above.
130
- const row = db.prepare(`SELECT status FROM ${table} WHERE id = ? AND tenant_id = ?`).get(sourceObject.id, tenantId);
131
- if (!row) {
132
- throw new Error(`${label}: source ${sourceObject.type} ${sourceObject.id} not found for tenant ${tenantId}`);
133
- }
134
- if (row.status !== 'active' && row.status !== 'superseded') {
135
- throw new Error(`${label}: source ${sourceObject.type} ${sourceObject.id} has status '${row.status}' (must be active|superseded)`);
136
- }
137
- }
138
- // source_kind is the memory's kind when a memory is present, else 'distilled' for an
139
- // object-only row (E2 objects are consolidated by construction). All-null is rejected.
140
- if (memKind != null)
141
- return { sourceKind: memKind, memoryId: effectiveMemoryId };
142
- if (sourceObject != null)
143
- return { sourceKind: 'distilled', memoryId: null };
144
- throw new Error(`${label}: graph row needs a memory or a source object`);
145
- }
146
- // ---------------------------------------------------------------------------
147
- // Public API
148
- // ---------------------------------------------------------------------------
149
- /**
150
- * Insert a graph entity extracted from a consolidated memory. Throws if the source
151
- * memory is missing / cross-tenant / raw (the DB trigger is the backstop).
152
- */
153
- export function insertEntity(hippoRoot, tenantId, opts, txDb) {
154
- assertTenantId('insertEntity', tenantId);
155
- if (!GRAPH_ENTITY_TYPES.has(opts.entityType)) {
156
- throw new Error(`insertEntity: entityType must be one of ${Array.from(GRAPH_ENTITY_TYPES).join('|')}; got ${opts.entityType}`);
157
- }
158
- const name = (opts.name ?? '').trim();
159
- if (name.length === 0)
160
- throw new Error('insertEntity: name is required');
161
- if (name.length > MAX_ENTITY_NAME_LEN) {
162
- throw new Error(`insertEntity: name exceeds the ${MAX_ENTITY_NAME_LEN}-char cap`);
163
- }
164
- const now = new Date().toISOString();
165
- const memoryId = opts.memoryId ?? null;
166
- const sourceObject = opts.sourceObject ?? null;
167
- const ownDb = txDb ? null : openHippoDb(hippoRoot);
168
- const db = txDb ?? ownDb;
169
- try {
170
- const { sourceKind, memoryId: effectiveMemoryId } = resolveConsolidatedSource(db, tenantId, memoryId, sourceObject, 'insertEntity');
171
- const result = db.prepare(`
172
- INSERT INTO entities(tenant_id, entity_type, name, memory_id, source_kind, source_object_type, source_object_id, created_at)
173
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
174
- `).run(tenantId, opts.entityType, name, effectiveMemoryId, sourceKind, sourceObject?.type ?? null, sourceObject?.id ?? null, now);
175
- const id = Number(result.lastInsertRowid ?? 0);
176
- // SAFETY: row's shape matches the columns named in ENTITY_COLS above.
177
- const row = db.prepare(`SELECT ${ENTITY_COLS} FROM entities WHERE id = ?`).get(id);
178
- if (!row)
179
- throw new Error('insertEntity: failed to reload inserted entity');
180
- return rowToEntity(row);
181
- }
182
- finally {
183
- if (ownDb)
184
- closeHippoDb(ownDb);
185
- }
186
- }
187
- /**
188
- * Insert a graph relation between two entities, sourced from a consolidated memory.
189
- * Both entities must exist in the same tenant; the source memory must be consolidated.
190
- */
191
- export function insertRelation(hippoRoot, tenantId, opts, txDb) {
192
- assertTenantId('insertRelation', tenantId);
193
- if (!GRAPH_RELATION_TYPES.has(opts.relType)) {
194
- throw new Error(`insertRelation: relType must be one of ${Array.from(GRAPH_RELATION_TYPES).join('|')}; got ${opts.relType}`);
195
- }
196
- const now = new Date().toISOString();
197
- const memoryId = opts.memoryId ?? null;
198
- const sourceObject = opts.sourceObject ?? null;
199
- const ownDb = txDb ? null : openHippoDb(hippoRoot);
200
- const db = txDb ?? ownDb;
201
- try {
202
- for (const [eid, role] of [[opts.fromEntityId, 'from'], [opts.toEntityId, 'to']]) {
203
- // SAFETY: ent's shape matches the single `tenant_id` column named in
204
- // the SELECT above.
205
- const ent = db.prepare(`SELECT tenant_id FROM entities WHERE id = ?`).get(eid);
206
- if (!ent)
207
- throw new Error(`insertRelation: ${role}_entity ${eid} not found`);
208
- if (ent.tenant_id !== tenantId) {
209
- throw new Error(`insertRelation: ${role}_entity ${eid} belongs to another tenant (no cross-tenant edges)`);
210
- }
211
- }
212
- const { sourceKind, memoryId: effectiveMemoryId } = resolveConsolidatedSource(db, tenantId, memoryId, sourceObject, 'insertRelation');
213
- const result = db.prepare(`
214
- INSERT INTO relations(tenant_id, from_entity_id, to_entity_id, rel_type, memory_id, source_kind, source_object_type, source_object_id, created_at)
215
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
216
- `).run(tenantId, opts.fromEntityId, opts.toEntityId, opts.relType, effectiveMemoryId, sourceKind, sourceObject?.type ?? null, sourceObject?.id ?? null, now);
217
- const id = Number(result.lastInsertRowid ?? 0);
218
- // SAFETY: row's shape matches the columns named in RELATION_COLS above.
219
- const row = db.prepare(`SELECT ${RELATION_COLS} FROM relations WHERE id = ?`).get(id);
220
- if (!row)
221
- throw new Error('insertRelation: failed to reload inserted relation');
222
- return rowToRelation(row);
223
- }
224
- finally {
225
- if (ownDb)
226
- closeHippoDb(ownDb);
227
- }
228
- }
229
- export function loadEntityById(hippoRoot, tenantId, id) {
230
- assertTenantId('loadEntityById', tenantId);
231
- const db = openHippoDb(hippoRoot);
232
- try {
233
- // SAFETY: row's shape matches the columns named in ENTITY_COLS above.
234
- const row = db.prepare(`SELECT ${ENTITY_COLS} FROM entities WHERE id = ? AND tenant_id = ?`)
235
- .get(id, tenantId);
236
- return row ? rowToEntity(row) : null;
237
- }
238
- finally {
239
- closeHippoDb(db);
240
- }
241
- }
242
- /** Entities with an exact `name` (read), bounded by `limit` in SQL with a
243
- * deterministic order. Lets the graph-view focus query find the `--entity NAME`
244
- * entity DIRECTLY (not from a globally-capped list) WITHOUT materializing every
245
- * same-name row when a name maps to many entities. */
246
- export function loadEntitiesByName(hippoRoot, tenantId, name, opts = {}, txDb) {
247
- assertTenantId('loadEntitiesByName', tenantId);
248
- const limit = opts.limit ?? 100;
249
- if (!Number.isInteger(limit) || limit < 0) {
250
- throw new Error(`loadEntitiesByName: limit must be a non-negative integer; got ${limit}`);
251
- }
252
- const ownDb = txDb ? null : openHippoDb(hippoRoot);
253
- const db = txDb ?? ownDb;
254
- try {
255
- // SAFETY: rows' shape matches the columns named in ENTITY_COLS above.
256
- const rows = db.prepare(`
257
- SELECT ${ENTITY_COLS} FROM entities WHERE tenant_id = ? AND name = ?
258
- ORDER BY id ASC LIMIT ?
259
- `).all(tenantId, name, limit);
260
- return rows.map(rowToEntity);
261
- }
262
- finally {
263
- if (ownDb)
264
- closeHippoDb(ownDb);
265
- }
266
- }
267
- export function loadEntities(hippoRoot, tenantId, opts = {}, txDb) {
268
- assertTenantId('loadEntities', tenantId);
269
- const limit = opts.limit ?? 100;
270
- if (opts.entityType && !GRAPH_ENTITY_TYPES.has(opts.entityType)) {
271
- throw new Error(`loadEntities: entityType must be one of ${Array.from(GRAPH_ENTITY_TYPES).join('|')}; got ${opts.entityType}`);
272
- }
273
- const ownDb = txDb ? null : openHippoDb(hippoRoot);
274
- const db = txDb ?? ownDb;
275
- try {
276
- const clauses = ['tenant_id = ?'];
277
- const params = [tenantId];
278
- if (opts.entityType) {
279
- clauses.push('entity_type = ?');
280
- params.push(opts.entityType);
281
- }
282
- params.push(limit);
283
- // SAFETY: rows' shape matches the columns named in ENTITY_COLS above.
284
- const rows = db.prepare(`
285
- SELECT ${ENTITY_COLS} FROM entities
286
- WHERE ${clauses.join(' AND ')}
287
- ORDER BY created_at DESC, id DESC
288
- LIMIT ?
289
- `).all(...params);
290
- return rows.map(rowToEntity);
291
- }
292
- finally {
293
- if (ownDb)
294
- closeHippoDb(ownDb);
295
- }
296
- }
297
- export function loadRelations(hippoRoot, tenantId, opts = {}, txDb) {
298
- assertTenantId('loadRelations', tenantId);
299
- const limit = opts.limit ?? 100;
300
- const ownDb = txDb ? null : openHippoDb(hippoRoot);
301
- const db = txDb ?? ownDb;
302
- try {
303
- const clauses = ['tenant_id = ?'];
304
- const params = [tenantId];
305
- if (opts.fromEntityId !== undefined) {
306
- clauses.push('from_entity_id = ?');
307
- params.push(opts.fromEntityId);
308
- }
309
- params.push(limit);
310
- // SAFETY: rows' shape matches the columns named in RELATION_COLS above.
311
- const rows = db.prepare(`
312
- SELECT ${RELATION_COLS} FROM relations
313
- WHERE ${clauses.join(' AND ')}
314
- ORDER BY created_at DESC, id DESC
315
- LIMIT ?
316
- `).all(...params);
317
- return rows.map(rowToRelation);
318
- }
319
- finally {
320
- if (ownDb)
321
- closeHippoDb(ownDb);
322
- }
323
- }
324
- // ---------------------------------------------------------------------------
325
- // E3.2 multi-hop recall read helpers (SELECT-only; the check-graph-writes lint
326
- // permits these here and in the read-only consumer src/graph-recall.ts).
327
- // ---------------------------------------------------------------------------
328
- /** Chunk size for IN-list queries: well under SQLite's 999-bound-variable default
329
- * (leaves headroom for the tenant_id param + the doubled list in neighbour lookups). */
330
- const IN_LIST_CHUNK = 400;
331
- /**
332
- * Map consolidated source memory ids -> their graph entities. The SEED step of E3.2
333
- * multi-hop recall (recall result memory ids -> entities to traverse from). Tenant-
334
- * scoped, read-only; chunks the IN-list under the SQLite variable cap.
335
- */
336
- export function loadEntitiesByMemoryId(hippoRoot, tenantId, memoryIds) {
337
- assertTenantId('loadEntitiesByMemoryId', tenantId);
338
- if (memoryIds.length === 0)
339
- return [];
340
- const db = openHippoDb(hippoRoot);
341
- try {
342
- const out = [];
343
- for (let i = 0; i < memoryIds.length; i += IN_LIST_CHUNK) {
344
- const slice = memoryIds.slice(i, i + IN_LIST_CHUNK);
345
- const ph = slice.map(() => '?').join(',');
346
- // T2: no ORDER BY meant chunk-local scan order decided ties; id ASC
347
- // makes it deterministic (entities.id is an autoincrement integer PK).
348
- // SAFETY: rows' shape matches the columns named in ENTITY_COLS above.
349
- const rows = db.prepare(`
350
- SELECT ${ENTITY_COLS} FROM entities
351
- WHERE tenant_id = ? AND memory_id IN (${ph})
352
- ORDER BY id ASC
353
- `).all(tenantId, ...slice);
354
- out.push(...rows.map(rowToEntity));
355
- }
356
- return out;
357
- }
358
- finally {
359
- closeHippoDb(db);
360
- }
361
- }
362
- /**
363
- * Load entities by their primary ids. Resolves the entity rows reached during the BFS
364
- * (whose `memory_id` maps back to a recall result). Tenant-scoped, read-only.
365
- */
366
- export function loadEntitiesByIds(hippoRoot, tenantId, ids, txDb) {
367
- assertTenantId('loadEntitiesByIds', tenantId);
368
- if (ids.length === 0)
369
- return [];
370
- const ownDb = txDb ? null : openHippoDb(hippoRoot);
371
- const db = txDb ?? ownDb;
372
- try {
373
- const out = [];
374
- for (let i = 0; i < ids.length; i += IN_LIST_CHUNK) {
375
- const slice = ids.slice(i, i + IN_LIST_CHUNK);
376
- const ph = slice.map(() => '?').join(',');
377
- // SAFETY: rows' shape matches the columns named in ENTITY_COLS above.
378
- const rows = db.prepare(`
379
- SELECT ${ENTITY_COLS} FROM entities
380
- WHERE tenant_id = ? AND id IN (${ph})
381
- `).all(tenantId, ...slice);
382
- out.push(...rows.map(rowToEntity));
383
- }
384
- return out;
385
- }
386
- finally {
387
- if (ownDb)
388
- closeHippoDb(ownDb);
389
- }
390
- }
391
- /**
392
- * All relations touching ANY of `entityIds` in EITHER direction (from OR to) — the
393
- * per-hop neighbour query for E3.2 multi-hop traversal. ONE query for the whole frontier
394
- * (not one per node): this is the bidirectional read `loadRelations` (from-only) lacks,
395
- * and avoids an N+1 across BFS frontier nodes. `limit` caps rows for the frontier and
396
- * must be a non-negative integer (the raw `LIMIT ?` rejects a fractional value).
397
- */
398
- export function loadNeighborRelations(hippoRoot, tenantId, entityIds, opts = {}, txDb) {
399
- assertTenantId('loadNeighborRelations', tenantId);
400
- if (entityIds.length === 0)
401
- return [];
402
- const limit = opts.limit ?? 1000;
403
- if (!Number.isInteger(limit) || limit < 0) {
404
- throw new Error(`loadNeighborRelations: limit must be a non-negative integer; got ${limit}`);
405
- }
406
- const ownDb = txDb ? null : openHippoDb(hippoRoot);
407
- const db = txDb ?? ownDb;
408
- try {
409
- // `limit` is applied PER CHUNK; a frontier spanning >IN_LIST_CHUNK ids could return
410
- // up to limit*chunks rows before the by-id dedup below. Harmless for E3.2 (the
411
- // frontier is bounded by maxNeighbors <= 200 << IN_LIST_CHUNK, so a single chunk,
412
- // and the BFS re-enforces the per-hop fanout cap), but note the semantics if a
413
- // tighter total cap is ever needed.
414
- const byId = new Map();
415
- for (let i = 0; i < entityIds.length; i += IN_LIST_CHUNK) {
416
- const slice = entityIds.slice(i, i + IN_LIST_CHUNK);
417
- const ph = slice.map(() => '?').join(',');
418
- // SAFETY: rows' shape matches the columns named in RELATION_COLS above.
419
- const rows = db.prepare(`
420
- SELECT ${RELATION_COLS} FROM relations
421
- WHERE tenant_id = ? AND (from_entity_id IN (${ph}) OR to_entity_id IN (${ph}))
422
- ORDER BY created_at DESC, id DESC
423
- LIMIT ?
424
- `).all(tenantId, ...slice, ...slice, limit);
425
- for (const r of rows)
426
- byId.set(r.id, rowToRelation(r));
427
- }
428
- return Array.from(byId.values());
429
- }
430
- finally {
431
- if (ownDb)
432
- closeHippoDb(ownDb);
433
- }
434
- }
435
- /**
436
- * Relations with BOTH endpoints in `entityIds` (edges AMONG the set, not merely
437
- * touching it). Read. Used by the graph-view focus subgraph so the displayed
438
- * edges are exactly the intra-union edges: the `LIMIT` only caps genuinely-many
439
- * intra-union edges — no out-of-union row can evict a valid in-set edge. The
440
- * caller bounds `entityIds` (<= the view limit), so a single query is safe.
441
- */
442
- export function loadRelationsAmong(hippoRoot, tenantId, entityIds, opts = {}, txDb) {
443
- assertTenantId('loadRelationsAmong', tenantId);
444
- if (entityIds.length === 0)
445
- return [];
446
- const limit = opts.limit ?? 1000;
447
- if (!Number.isInteger(limit) || limit < 0) {
448
- throw new Error(`loadRelationsAmong: limit must be a non-negative integer; got ${limit}`);
449
- }
450
- const ownDb = txDb ? null : openHippoDb(hippoRoot);
451
- const db = txDb ?? ownDb;
452
- try {
453
- const ph = entityIds.map(() => '?').join(',');
454
- // SAFETY: rows' shape matches the columns named in RELATION_COLS above.
455
- const rows = db.prepare(`
456
- SELECT ${RELATION_COLS} FROM relations
457
- WHERE tenant_id = ? AND from_entity_id IN (${ph}) AND to_entity_id IN (${ph})
458
- ORDER BY created_at DESC, id DESC
459
- LIMIT ?
460
- `).all(tenantId, ...entityIds, ...entityIds, limit);
461
- return rows.map(rowToRelation);
462
- }
463
- finally {
464
- if (ownDb)
465
- closeHippoDb(ownDb);
466
- }
467
- }
468
- /**
469
- * Run `fn` inside ONE read transaction (a single WAL snapshot) so every graph read
470
- * it performs — pass the supplied `txDb` to the `load*` functions — sees a consistent
471
- * view, even if a `graph extract` / sleep-drain rebuild commits concurrently between
472
- * reads (the rebuild clears + reinserts entities, so separate reads could otherwise
473
- * mix old entity ids with new relation ids). Reads only; the connection is opened
474
- * once and closed after.
475
- */
476
- export function withGraphReadSnapshot(hippoRoot, fn) {
477
- const db = openHippoDb(hippoRoot);
478
- try {
479
- db.exec('BEGIN');
480
- try {
481
- const out = fn(db);
482
- db.exec('COMMIT');
483
- return out;
484
- }
485
- catch (e) {
486
- try {
487
- db.exec('ROLLBACK');
488
- }
489
- catch { /* ignore */ }
490
- throw e;
491
- }
492
- }
493
- finally {
494
- closeHippoDb(db);
495
- }
496
- }
497
- // ---------------------------------------------------------------------------
498
- // Extraction queue (the interface the deferred sleep enqueue-hook + E3.1 will use)
499
- // ---------------------------------------------------------------------------
500
- /**
501
- * Enqueue a consolidated memory for later graph extraction. Rejects a raw / missing /
502
- * cross-tenant memory (the DB trigger is the backstop). The producer hook in
503
- * `hippo sleep` is deferred (E3.1); this is the API it will call.
504
- */
505
- export function enqueueExtraction(hippoRoot, tenantId, memoryId) {
506
- assertTenantId('enqueueExtraction', tenantId);
507
- const now = new Date().toISOString();
508
- const db = openHippoDb(hippoRoot);
509
- try {
510
- // enqueue is memory-keyed (no source object), so a missing memory still throws (correct -
511
- // you cannot enqueue a forgotten mirror); memoryId is non-null here by construction.
512
- const { sourceKind } = resolveConsolidatedSource(db, tenantId, memoryId, null, 'enqueueExtraction');
513
- const result = db.prepare(`
514
- INSERT INTO graph_extraction_queue(tenant_id, memory_id, kind, status, enqueued_at, processed_at)
515
- VALUES (?, ?, ?, 'pending', ?, NULL)
516
- `).run(tenantId, memoryId, sourceKind, now);
517
- const id = Number(result.lastInsertRowid ?? 0);
518
- // SAFETY: row's shape matches the columns named in QUEUE_COLS above.
519
- const row = db.prepare(`SELECT ${QUEUE_COLS} FROM graph_extraction_queue WHERE id = ?`).get(id);
520
- if (!row)
521
- throw new Error('enqueueExtraction: failed to reload queue item');
522
- return rowToQueueItem(row);
523
- }
524
- finally {
525
- closeHippoDb(db);
526
- }
527
- }
528
- export function loadExtractionQueue(hippoRoot, tenantId, opts = {}) {
529
- assertTenantId('loadExtractionQueue', tenantId);
530
- const limit = opts.limit ?? 100;
531
- if (opts.status && !VALID_QUEUE_STATES.has(opts.status)) {
532
- throw new Error(`loadExtractionQueue: status must be one of ${Array.from(VALID_QUEUE_STATES).join('|')}; got ${opts.status}`);
533
- }
534
- const db = openHippoDb(hippoRoot);
535
- try {
536
- const clauses = ['tenant_id = ?'];
537
- const params = [tenantId];
538
- if (opts.status) {
539
- clauses.push('status = ?');
540
- params.push(opts.status);
541
- }
542
- params.push(limit);
543
- // SAFETY: rows' shape matches the columns named in QUEUE_COLS above.
544
- const rows = db.prepare(`
545
- SELECT ${QUEUE_COLS} FROM graph_extraction_queue
546
- WHERE ${clauses.join(' AND ')}
547
- ORDER BY enqueued_at ASC, id ASC
548
- LIMIT ?
549
- `).all(...params);
550
- return rows.map(rowToQueueItem);
551
- }
552
- finally {
553
- closeHippoDb(db);
554
- }
555
- }
556
- /**
557
- * Mark a queue item terminal (processed | skipped). Only `status`/`processed_at`
558
- * change, so the consolidated-source guard trigger (which fires on
559
- * memory_id/kind/tenant_id changes) is not involved. CAS on the current status to a
560
- * non-terminal 'pending'.
561
- */
562
- export function markExtractionProcessed(hippoRoot, tenantId, id, status = 'processed') {
563
- assertTenantId('markExtractionProcessed', tenantId);
564
- const now = new Date().toISOString();
565
- const db = openHippoDb(hippoRoot);
566
- try {
567
- const updated = db.prepare(`
568
- UPDATE graph_extraction_queue
569
- SET status = ?, processed_at = ?
570
- WHERE id = ? AND tenant_id = ? AND status = 'pending'
571
- `).run(status, now, id, tenantId);
572
- if (updated.changes === 0) {
573
- // SAFETY: existing's shape matches the single `status` column named in
574
- // the SELECT above.
575
- const existing = db.prepare(`SELECT status FROM graph_extraction_queue WHERE id = ? AND tenant_id = ?`)
576
- .get(id, tenantId);
577
- if (!existing)
578
- throw new Error(`markExtractionProcessed: queue item ${id} not found for tenant ${tenantId}`);
579
- throw new Error(`markExtractionProcessed: queue item ${id} is not pending (status='${existing.status}')`);
580
- }
581
- // SAFETY: row's shape matches the columns named in QUEUE_COLS above.
582
- const row = db.prepare(`SELECT ${QUEUE_COLS} FROM graph_extraction_queue WHERE id = ? AND tenant_id = ?`)
583
- .get(id, tenantId);
584
- if (!row)
585
- throw new Error(`markExtractionProcessed: queue item ${id} not found after UPDATE`);
586
- return rowToQueueItem(row);
587
- }
588
- finally {
589
- closeHippoDb(db);
590
- }
591
- }
592
- /**
593
- * Delete ALL entities for a tenant (relations cascade via the from/to FKs). Returns
594
- * the number of entities deleted. The rebuild primitive for graph extraction: the
595
- * deterministic graph is a pure derived function of the consolidated objects, so an
596
- * extract clears then re-derives. Lives in graph.ts (the sole sanctioned graph
597
- * writer), so the E3.3 CI lint permits this `DELETE FROM entities`. Does NOT touch
598
- * graph_extraction_queue (the enqueue-hook's domain).
599
- */
600
- export function clearGraph(hippoRoot, tenantId, txDb) {
601
- assertTenantId('clearGraph', tenantId);
602
- const ownDb = txDb ? null : openHippoDb(hippoRoot);
603
- const db = txDb ?? ownDb;
604
- try {
605
- const res = db.prepare(`DELETE FROM entities WHERE tenant_id = ?`).run(tenantId);
606
- return Number(res.changes ?? 0);
607
- }
608
- finally {
609
- if (ownDb)
610
- closeHippoDb(ownDb);
611
- }
612
- }
613
- /**
614
- * Run a full graph rebuild for one tenant inside a single transaction. `clearGraph`
615
- * + every `insertEntity`/`insertRelation` call made inside `fn` (passing the supplied
616
- * `txDb`) share the one connection and its `BEGIN IMMEDIATE` write lock, so the
617
- * rebuild is ATOMIC: two concurrent rebuilds serialize on the write lock (the second
618
- * waits, then re-derives cleanly) instead of interleaving into duplicate rows, and a
619
- * throw mid-rebuild ROLLS BACK the clear (no bricked/empty graph). The sole sanctioned
620
- * place to wrap graph writes in a transaction.
621
- */
622
- export function runGraphRebuildTransaction(hippoRoot, tenantId, fn) {
623
- assertTenantId('runGraphRebuildTransaction', tenantId);
624
- const db = openHippoDb(hippoRoot);
625
- try {
626
- db.exec('BEGIN IMMEDIATE');
627
- let committed = false;
628
- try {
629
- const out = fn(db);
630
- db.exec('COMMIT');
631
- committed = true;
632
- return out;
633
- }
634
- finally {
635
- if (!committed) {
636
- try {
637
- db.exec('ROLLBACK');
638
- }
639
- catch { /* preserve the original throw */ }
640
- }
641
- }
642
- }
643
- finally {
644
- closeHippoDb(db);
645
- }
646
- }
647
- // ---------------------------------------------------------------------------
648
- // E3 sleep enqueue-hook — producer helper + drain support
649
- // ---------------------------------------------------------------------------
650
- /**
651
- * Fail-soft producer hook: mark a tenant dirty for graph re-extraction by
652
- * enqueuing its consolidated mirror memory. NEVER throws into the caller — a
653
- * graph-dirty signal failing must not abort a core E2 write. Graph staleness is
654
- * recoverable (next sleep / manual `graph extract`); a broken `hippo decide` is
655
- * not. Called POST-COMMIT from the E2 graph-source save/close mutations of
656
- * decision, policy, customer_note and project_brief. A null memoryId (a
657
- * forgotten mirror) is a no-op.
658
- */
659
- export function markGraphDirty(hippoRoot, tenantId, memoryId) {
660
- if (!memoryId)
661
- return;
662
- try {
663
- enqueueExtraction(hippoRoot, tenantId, memoryId);
664
- }
665
- catch (err) {
666
- // Logged (warn) so a SYSTEMATIC enqueue failure surfaces to operators, but
667
- // swallowed so the already-committed E2 write is never rolled back.
668
- // SAFETY: this is a best-effort log message only; property access on any
669
- // JS value is safe (undefined if absent), preserving the existing lenient
670
- // formatting even when something non-Error was thrown.
671
- console.warn(`markGraphDirty: enqueue failed for tenant=${tenantId} memory=${memoryId}: ${err.message}`);
672
- }
673
- }
674
- /**
675
- * Remove the graph rows sourced from one E2 object, by its (type, id). Used when a
676
- * MIRRORLESS object is closed: it has no mirror memory, so `markGraphDirty` cannot
677
- * enqueue a rebuild (the queue is memory-keyed). Closing must still drop the object's
678
- * now-stale entity + edges from the graph, so we remove them directly here. Fail-soft
679
- * like `markGraphDirty` (never throws into the E2 close caller; graph staleness is
680
- * recoverable). Deleting the entity cascade-deletes any relation where it is an endpoint
681
- * (relations FK entities ON DELETE CASCADE); the explicit relations DELETE also covers a
682
- * relation whose OWN provenance is this object (defensive — every such edge has the object
683
- * as an endpoint today, so the cascade already covers it). DELETE fires no BEFORE
684
- * INSERT/UPDATE guard trigger.
685
- */
686
- export function removeGraphEntitiesForObject(hippoRoot, tenantId, sourceObjectType, sourceObjectId) {
687
- try {
688
- assertTenantId('removeGraphEntitiesForObject', tenantId);
689
- const db = openHippoDb(hippoRoot);
690
- try {
691
- db.exec('BEGIN');
692
- db.prepare(`DELETE FROM relations WHERE tenant_id = ? AND source_object_type = ? AND source_object_id = ?`)
693
- .run(tenantId, sourceObjectType, sourceObjectId);
694
- db.prepare(`DELETE FROM entities WHERE tenant_id = ? AND source_object_type = ? AND source_object_id = ?`)
695
- .run(tenantId, sourceObjectType, sourceObjectId);
696
- db.exec('COMMIT');
697
- }
698
- catch (e) {
699
- try {
700
- db.exec('ROLLBACK');
701
- }
702
- catch { /* preserve original throw */ }
703
- throw e;
704
- }
705
- finally {
706
- closeHippoDb(db);
707
- }
708
- }
709
- catch (err) {
710
- // SAFETY: this is a best-effort log message only; property access on any
711
- // JS value is safe (undefined if absent), preserving the existing lenient
712
- // formatting even when something non-Error was thrown.
713
- console.warn(`removeGraphEntitiesForObject: failed for tenant=${tenantId} ${sourceObjectType}#${sourceObjectId}: ${err.message}`);
714
- }
715
- }
716
- /**
717
- * The dirty tenants awaiting graph re-extraction, each with the MAX pending
718
- * queue id at read time (a watermark). The sleep drain rebuilds each tenant's
719
- * graph, then marks only items at or below the watermark processed, so items
720
- * enqueued DURING the rebuild stay pending for the next sleep (no lost-update
721
- * race). Host-wide read (the queue is per-tenant but sleep is cross-tenant).
722
- */
723
- export function loadPendingExtractionTenants(hippoRoot) {
724
- const db = openHippoDb(hippoRoot);
725
- try {
726
- // SAFETY: rows' shape matches the two aliased columns (tenant_id, max_id)
727
- // named in the SELECT above.
728
- const rows = db.prepare(`
729
- SELECT tenant_id AS tenant_id, MAX(id) AS max_id
730
- FROM graph_extraction_queue
731
- WHERE status = 'pending'
732
- GROUP BY tenant_id
733
- `).all();
734
- return rows.map((r) => ({ tenantId: r.tenant_id, maxPendingId: Number(r.max_id) }));
735
- }
736
- finally {
737
- closeHippoDb(db);
738
- }
739
- }
740
- /**
741
- * Mark every pending queue item for a tenant with `id <= maxId` processed, in
742
- * one UPDATE. Status/processed_at only, so the consolidated-source guard trigger
743
- * is not involved (same as markExtractionProcessed). Returns the count marked.
744
- * The `<= maxId` watermark excludes items enqueued after the drain snapshot.
745
- */
746
- export function markPendingProcessedUpTo(hippoRoot, tenantId, maxId) {
747
- assertTenantId('markPendingProcessedUpTo', tenantId);
748
- const now = new Date().toISOString();
749
- const db = openHippoDb(hippoRoot);
750
- try {
751
- const res = db.prepare(`
752
- UPDATE graph_extraction_queue
753
- SET status = 'processed', processed_at = ?
754
- WHERE tenant_id = ? AND status = 'pending' AND id <= ?
755
- `).run(now, tenantId, maxId);
756
- return Number(res.changes ?? 0);
757
- }
758
- finally {
759
- closeHippoDb(db);
760
- }
761
- }
762
- //# sourceMappingURL=graph.js.map