hippo-memory 1.71.0 → 2.0.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 (625) hide show
  1. package/README.md +7 -5
  2. package/dist/agent-memories/apply.d.ts +0 -11
  3. package/dist/agent-memories/apply.js +11 -26
  4. package/dist/agent-memories/claude-code.js +1 -1
  5. package/dist/agent-memories/codex.js +1 -1
  6. package/dist/agent-memories/copilot.d.ts +1 -3
  7. package/dist/agent-memories/copilot.js +1 -17
  8. package/dist/agent-memories/project-folds.d.ts +10 -0
  9. package/dist/agent-memories/project-folds.js +34 -0
  10. package/dist/agent-memories/sync.js +8 -6
  11. package/dist/api/assemble.js +3 -2
  12. package/dist/api/audit.d.ts +30 -2
  13. package/dist/api/audit.js +48 -7
  14. package/dist/api/auth.d.ts +11 -9
  15. package/dist/api/auth.js +39 -40
  16. package/dist/api/auto-sleep.d.ts +5 -2
  17. package/dist/api/auto-sleep.js +7 -3
  18. package/dist/api/availability.js +2 -3
  19. package/dist/api/cards.d.ts +42 -0
  20. package/dist/api/cards.js +52 -0
  21. package/dist/api/conflicts.d.ts +28 -0
  22. package/dist/api/conflicts.js +61 -0
  23. package/dist/api/context-auto.js +4 -2
  24. package/dist/api/context-render.js +4 -3
  25. package/dist/api/context-select.js +15 -29
  26. package/dist/api/context.js +29 -18
  27. package/dist/api/continuity.d.ts +47 -0
  28. package/dist/api/continuity.js +66 -0
  29. package/dist/api/dormant.js +4 -2
  30. package/dist/api/drill-down.js +3 -2
  31. package/dist/api/embeddings.d.ts +17 -0
  32. package/dist/api/embeddings.js +28 -0
  33. package/dist/api/error-reply.d.ts +8 -0
  34. package/dist/api/error-reply.js +21 -0
  35. package/dist/api/forget.d.ts +7 -3
  36. package/dist/api/forget.js +24 -14
  37. package/dist/api/goals.d.ts +1 -1
  38. package/dist/api/goals.js +5 -9
  39. package/dist/api/graph.js +2 -1
  40. package/dist/api/index.d.ts +4 -2
  41. package/dist/api/index.js +4 -2
  42. package/dist/api/instruction-detect.js +5 -1
  43. package/dist/api/learn.d.ts +5 -1
  44. package/dist/api/learn.js +71 -44
  45. package/dist/api/ledger-db.d.ts +2 -6
  46. package/dist/api/ledger-db.js +4 -36
  47. package/dist/api/memories.d.ts +21 -1
  48. package/dist/api/memories.js +51 -1
  49. package/dist/api/objects.d.ts +1 -1
  50. package/dist/api/objects.js +2 -1
  51. package/dist/api/outcome.d.ts +5 -5
  52. package/dist/api/outcome.js +17 -16
  53. package/dist/api/pilot-arm.d.ts +1 -11
  54. package/dist/api/pilot-arm.js +5 -45
  55. package/dist/api/predictions.d.ts +3 -1
  56. package/dist/api/predictions.js +8 -1
  57. package/dist/api/projects.d.ts +21 -0
  58. package/dist/api/projects.js +24 -0
  59. package/dist/api/promote.d.ts +3 -3
  60. package/dist/api/promote.js +26 -28
  61. package/dist/api/prompt-hook.d.ts +17 -2
  62. package/dist/api/prompt-hook.js +45 -4
  63. package/dist/api/quarantine.js +2 -1
  64. package/dist/api/recall-cli.d.ts +3 -0
  65. package/dist/api/recall-cli.js +13 -4
  66. package/dist/api/recall-core.js +10 -5
  67. package/dist/api/recall-pipeline.js +23 -24
  68. package/dist/api/recall-request.js +1 -1
  69. package/dist/api/recall-types.d.ts +3 -1
  70. package/dist/api/recall.d.ts +0 -3
  71. package/dist/api/recall.js +51 -73
  72. package/dist/api/remember-local.d.ts +5 -2
  73. package/dist/api/remember-local.js +15 -7
  74. package/dist/api/remember.d.ts +7 -3
  75. package/dist/api/remember.js +19 -16
  76. package/dist/api/session-end.d.ts +46 -0
  77. package/dist/api/session-end.js +131 -0
  78. package/dist/api/sleep-run.d.ts +1 -1
  79. package/dist/api/sleep-run.js +16 -11
  80. package/dist/api/sleep.js +4 -3
  81. package/dist/api/status.d.ts +24 -0
  82. package/dist/api/status.js +40 -0
  83. package/dist/api/store-init.d.ts +4 -0
  84. package/dist/api/store-init.js +9 -0
  85. package/dist/api/tokens.js +2 -2
  86. package/dist/api/types.d.ts +3 -7
  87. package/dist/api/types.js +6 -1
  88. package/dist/capture/caller-session.d.ts +0 -3
  89. package/dist/capture/caller-session.js +1 -12
  90. package/dist/capture/capture-error.d.ts +2 -2
  91. package/dist/capture/capture-error.js +23 -18
  92. package/dist/capture/codex-patch.js +3 -1
  93. package/dist/capture/command.js +36 -95
  94. package/dist/capture/compact.js +10 -5
  95. package/dist/capture/compaction-items-caller.js +11 -20
  96. package/dist/capture/compaction-record.d.ts +7 -93
  97. package/dist/capture/compaction-record.js +29 -426
  98. package/dist/capture/compaction-spool.d.ts +7 -7
  99. package/dist/capture/compaction-spool.js +60 -51
  100. package/dist/capture/copilot-transcript.d.ts +2 -1
  101. package/dist/capture/copilot-transcript.js +2 -1
  102. package/dist/capture/extract.d.ts +5 -2
  103. package/dist/capture/extract.js +4 -3
  104. package/dist/capture/failure-caller.d.ts +1 -1
  105. package/dist/capture/failure-caller.js +21 -16
  106. package/dist/capture/failure-reading.d.ts +2 -1
  107. package/dist/capture/failure-reading.js +7 -9
  108. package/dist/capture/pre-compact-caller.js +5 -4
  109. package/dist/capture/session-digest.js +4 -3
  110. package/dist/capture/session-end-caller.js +3 -2
  111. package/dist/capture/session-worker.js +22 -10
  112. package/dist/capture/transcript.d.ts +2 -1
  113. package/dist/capture/transcript.js +6 -3
  114. package/dist/capture/working-state.d.ts +4 -2
  115. package/dist/capture/working-state.js +4 -2
  116. package/dist/cli/audit-prune.d.ts +0 -25
  117. package/dist/cli/audit-prune.js +1 -27
  118. package/dist/cli/audit.js +20 -20
  119. package/dist/cli/auth.d.ts +1 -1
  120. package/dist/cli/auth.js +16 -17
  121. package/dist/cli/briefs.d.ts +1 -4
  122. package/dist/cli/briefs.js +37 -292
  123. package/dist/cli/card.js +41 -33
  124. package/dist/cli/client.d.ts +6 -2
  125. package/dist/cli/client.js +37 -21
  126. package/dist/cli/compact-resume-payload.js +1 -1
  127. package/dist/cli/context.d.ts +1 -1
  128. package/dist/cli/context.js +13 -13
  129. package/dist/cli/continuity.d.ts +1 -1
  130. package/dist/cli/continuity.js +36 -39
  131. package/dist/cli/curate.d.ts +2 -2
  132. package/dist/cli/curate.js +32 -36
  133. package/dist/cli/dag.d.ts +1 -1
  134. package/dist/cli/dag.js +23 -8
  135. package/dist/cli/decisions.d.ts +0 -2
  136. package/dist/cli/decisions.js +7 -285
  137. package/dist/cli/eval.d.ts +1 -1
  138. package/dist/cli/eval.js +12 -13
  139. package/dist/cli/explain.d.ts +1 -1
  140. package/dist/cli/explain.js +21 -25
  141. package/dist/cli/flag-values.js +16 -6
  142. package/dist/cli/flags.d.ts +0 -289
  143. package/dist/cli/flags.js +3 -138
  144. package/dist/cli/graph.d.ts +3 -0
  145. package/dist/cli/graph.js +83 -0
  146. package/dist/cli/hook-runtime.d.ts +6 -6
  147. package/dist/cli/hook-runtime.js +9 -36
  148. package/dist/cli/incidents.d.ts +3 -0
  149. package/dist/cli/incidents.js +112 -0
  150. package/dist/cli/init.d.ts +1 -1
  151. package/dist/cli/init.js +28 -19
  152. package/dist/cli/install-steps.d.ts +2 -1
  153. package/dist/cli/install-steps.js +11 -3
  154. package/dist/cli/last-sleep.js +1 -1
  155. package/dist/cli/maintenance.d.ts +3 -3
  156. package/dist/cli/maintenance.js +29 -30
  157. package/dist/cli/notes.d.ts +2 -0
  158. package/dist/cli/notes.js +41 -0
  159. package/dist/cli/object-verbs.d.ts +2 -2
  160. package/dist/cli/object-verbs.js +4 -4
  161. package/dist/cli/open-browser.d.ts +14 -0
  162. package/dist/cli/open-browser.js +26 -0
  163. package/dist/cli/playbooks.d.ts +3 -4
  164. package/dist/cli/playbooks.js +126 -290
  165. package/dist/cli/predictions.d.ts +3 -0
  166. package/dist/cli/predictions.js +174 -0
  167. package/dist/cli/print.js +2 -1
  168. package/dist/cli/projects.js +30 -22
  169. package/dist/cli/quality-repair-once.d.ts +1 -1
  170. package/dist/cli/quality-repair-once.js +6 -5
  171. package/dist/cli/recall.js +13 -7
  172. package/dist/cli/refine-llm.js +18 -17
  173. package/dist/cli/remember.js +17 -17
  174. package/dist/cli/scheduler.js +2 -1
  175. package/dist/cli/serve.js +11 -6
  176. package/dist/cli/session-hooks.d.ts +1 -5
  177. package/dist/cli/session-hooks.js +89 -168
  178. package/dist/cli/setup.d.ts +1 -1
  179. package/dist/cli/setup.js +17 -10
  180. package/dist/cli/shared.d.ts +2 -6
  181. package/dist/cli/shared.js +9 -29
  182. package/dist/cli/sleep-render.js +6 -3
  183. package/dist/cli/sleep.js +6 -37
  184. package/dist/cli/status.d.ts +3 -3
  185. package/dist/cli/status.js +32 -35
  186. package/dist/cli/transfer.d.ts +3 -3
  187. package/dist/cli/transfer.js +64 -43
  188. package/dist/cli/usage.d.ts +1 -80
  189. package/dist/cli/usage.js +2 -696
  190. package/dist/cli/verb-row.d.ts +34 -0
  191. package/dist/cli/verb-row.js +6 -0
  192. package/dist/cli/verbs/health.d.ts +27 -0
  193. package/dist/cli/verbs/health.js +234 -0
  194. package/dist/cli/verbs/memory.d.ts +16 -0
  195. package/dist/cli/verbs/memory.js +236 -0
  196. package/dist/cli/verbs/objects.d.ts +20 -0
  197. package/dist/cli/verbs/objects.js +257 -0
  198. package/dist/cli/verbs/sessions.d.ts +31 -0
  199. package/dist/cli/verbs/sessions.js +314 -0
  200. package/dist/cli/verbs.d.ts +81 -0
  201. package/dist/cli/verbs.js +7 -0
  202. package/dist/cli/versioned-verbs.d.ts +51 -0
  203. package/dist/cli/versioned-verbs.js +79 -0
  204. package/dist/cli.d.ts +1 -272
  205. package/dist/cli.js +24 -315
  206. package/dist/connectors/dlq.d.ts +39 -3
  207. package/dist/connectors/dlq.js +39 -4
  208. package/dist/connectors/github/backfill.js +12 -3
  209. package/dist/connectors/github/deletion.js +2 -1
  210. package/dist/connectors/github/dlq.js +31 -73
  211. package/dist/connectors/github/ingest.d.ts +2 -6
  212. package/dist/connectors/github/ingest.js +5 -29
  213. package/dist/connectors/github/tenant-routing.js +2 -1
  214. package/dist/connectors/github/webhook.d.ts +2 -1
  215. package/dist/connectors/github/webhook.js +35 -2
  216. package/dist/connectors/ingest.d.ts +10 -0
  217. package/dist/connectors/ingest.js +29 -0
  218. package/dist/connectors/slack/deletion.js +2 -1
  219. package/dist/connectors/slack/dlq.js +49 -71
  220. package/dist/connectors/slack/ingest.d.ts +2 -6
  221. package/dist/connectors/slack/ingest.js +4 -28
  222. package/dist/connectors/slack/tenant-routing.js +2 -1
  223. package/dist/connectors/slack/webhook.d.ts +2 -1
  224. package/dist/connectors/slack/webhook.js +2 -1
  225. package/dist/consolidate/conflicts.js +2 -2
  226. package/dist/consolidate/dag.js +29 -18
  227. package/dist/consolidate/dedupe.d.ts +7 -0
  228. package/dist/consolidate/dedupe.js +6 -4
  229. package/dist/consolidate/llm-passes.js +45 -19
  230. package/dist/consolidate/memory-value.js +3 -2
  231. package/dist/consolidate/merge.js +8 -8
  232. package/dist/consolidate/physics-pass.d.ts +6 -1
  233. package/dist/consolidate/physics-pass.js +26 -6
  234. package/dist/consolidate/replay.js +11 -4
  235. package/dist/consolidate/sleep.js +9 -6
  236. package/dist/consolidate/traces.js +5 -5
  237. package/dist/core/ablation.d.ts +10 -0
  238. package/dist/core/ablation.js +12 -0
  239. package/dist/{sharing/scope.d.ts → core/active-scope.d.ts} +1 -1
  240. package/dist/{sharing/scope.js → core/active-scope.js} +1 -1
  241. package/dist/core/ambient.d.ts +4 -0
  242. package/dist/core/ambient.js +39 -18
  243. package/dist/core/api-errors.d.ts +16 -0
  244. package/dist/core/api-errors.js +20 -0
  245. package/dist/core/card.js +3 -1
  246. package/dist/core/compaction-timing.d.ts +7 -0
  247. package/dist/core/compaction-timing.js +9 -0
  248. package/dist/core/config.d.ts +1 -1
  249. package/dist/core/config.js +22 -18
  250. package/dist/core/cosine.d.ts +3 -0
  251. package/dist/core/cosine.js +19 -0
  252. package/dist/{store → core}/markdown.d.ts +1 -1
  253. package/dist/{store → core}/markdown.js +4 -4
  254. package/dist/core/memory-audit.d.ts +17 -0
  255. package/dist/core/memory-audit.js +54 -0
  256. package/dist/core/memory.d.ts +14 -8
  257. package/dist/core/memory.js +35 -23
  258. package/dist/{consolidate → core}/merged-row.d.ts +1 -1
  259. package/dist/{consolidate → core}/merged-row.js +1 -1
  260. package/dist/core/physics.d.ts +3 -1
  261. package/dist/core/physics.js +23 -18
  262. package/dist/core/prediction.d.ts +3 -0
  263. package/dist/core/prediction.js +6 -0
  264. package/dist/core/project-identity.d.ts +3 -0
  265. package/dist/core/project-identity.js +12 -2
  266. package/dist/{store → core}/recall-scope.d.ts +1 -10
  267. package/dist/{store → core}/recall-scope.js +2 -19
  268. package/dist/core/search-types.d.ts +1 -1
  269. package/dist/dashboard/dashboard-actions.d.ts +2 -2
  270. package/dist/dashboard/dashboard-actions.js +5 -5
  271. package/dist/dashboard/dashboard-queries.js +2 -7
  272. package/dist/dashboard/dashboard-snapshot.js +1 -3
  273. package/dist/dashboard/dashboard.js +16 -5
  274. package/dist/db/busy.d.ts +2 -7
  275. package/dist/db/busy.js +21 -26
  276. package/dist/db/connect.d.ts +2 -2
  277. package/dist/db/connect.js +7 -7
  278. package/dist/db/index.d.ts +3 -3
  279. package/dist/db/index.js +3 -3
  280. package/dist/db/migrate.js +14 -7
  281. package/dist/db/migrations/index.d.ts +1 -1
  282. package/dist/db/migrations/index.js +3 -1
  283. package/dist/db/migrations/v11.js +1 -0
  284. package/dist/db/migrations/v14.js +1 -0
  285. package/dist/db/migrations/v55.d.ts +3 -0
  286. package/dist/db/migrations/v55.js +17 -0
  287. package/dist/db/open.d.ts +0 -2
  288. package/dist/db/open.js +6 -10
  289. package/dist/db/physics-state.d.ts +0 -4
  290. package/dist/db/physics-state.js +7 -33
  291. package/dist/db/request-stores.d.ts +1 -0
  292. package/dist/db/request-stores.js +2 -1
  293. package/dist/db/tables.d.ts +2 -0
  294. package/dist/db/tables.js +6 -2
  295. package/dist/db/vector-store.js +19 -5
  296. package/dist/db/wal-checkpointer.js +2 -1
  297. package/dist/doctor.d.ts +3 -0
  298. package/dist/doctor.js +18 -15
  299. package/dist/embeddings/local.d.ts +62 -0
  300. package/dist/embeddings/local.js +146 -0
  301. package/dist/{store/embeddings → embeddings}/provider.d.ts +5 -2
  302. package/dist/{store/embeddings → embeddings}/provider.js +19 -25
  303. package/dist/embeddings/transformers.d.ts +26 -0
  304. package/dist/embeddings/transformers.js +89 -0
  305. package/dist/entry/session-text.d.ts +1 -1
  306. package/dist/entry/session-text.js +1 -1
  307. package/dist/entry/store-kit.d.ts +37 -0
  308. package/dist/entry/store-kit.js +25 -0
  309. package/dist/entry/testing.d.ts +6 -0
  310. package/dist/entry/testing.js +7 -0
  311. package/dist/eval/eval-suite.js +17 -11
  312. package/dist/eval/eval.js +1 -1
  313. package/dist/eval/judgment.js +12 -5
  314. package/dist/graph/extract.js +3 -3
  315. package/dist/graph/recall.js +1 -1
  316. package/dist/graph/view.js +13 -5
  317. package/dist/graph/write.d.ts +1 -1
  318. package/dist/graph/write.js +9 -9
  319. package/dist/hooks/codex-session.js +3 -2
  320. package/dist/hooks/codex-wrapper.js +2 -1
  321. package/dist/hooks/json-hooks.js +10 -4
  322. package/dist/hooks/opencode.js +8 -5
  323. package/dist/hooks/shared.d.ts +0 -6
  324. package/dist/hooks/shared.js +4 -15
  325. package/dist/importers/core.js +4 -4
  326. package/dist/importers/sources.js +5 -4
  327. package/dist/importers/vault.d.ts +1 -1
  328. package/dist/importers/vault.js +25 -23
  329. package/dist/index.d.ts +5 -4
  330. package/dist/index.js +4 -3
  331. package/dist/learn/autolearn.d.ts +15 -3
  332. package/dist/learn/autolearn.js +38 -16
  333. package/dist/learn/churn-git.js +13 -4
  334. package/dist/learn/extract.d.ts +3 -2
  335. package/dist/learn/extract.js +7 -5
  336. package/dist/learn/forward-claim-detector.js +4 -2
  337. package/dist/learn/invalidation.d.ts +2 -1
  338. package/dist/learn/invalidation.js +18 -9
  339. package/dist/mcp/admin-tools.d.ts +2 -2
  340. package/dist/mcp/admin-tools.js +27 -48
  341. package/dist/mcp/format.js +3 -2
  342. package/dist/mcp/framing.d.ts +1 -0
  343. package/dist/mcp/framing.js +1 -1
  344. package/dist/mcp/memory-tools.d.ts +1 -1
  345. package/dist/mcp/memory-tools.js +8 -9
  346. package/dist/mcp/protocol.d.ts +11 -7
  347. package/dist/mcp/protocol.js +25 -12
  348. package/dist/mcp/recall-tools.js +12 -9
  349. package/dist/mcp/request.js +22 -20
  350. package/dist/mcp/stdio.js +37 -16
  351. package/dist/mcp/tool-args.js +2 -1
  352. package/dist/mcp/tools.js +44 -21
  353. package/dist/objects/customer-notes.d.ts +2 -2
  354. package/dist/objects/decisions.d.ts +2 -2
  355. package/dist/objects/descriptor.d.ts +1 -1
  356. package/dist/objects/incidents.d.ts +2 -2
  357. package/dist/objects/lifecycle.d.ts +1 -1
  358. package/dist/objects/lifecycle.js +2 -1
  359. package/dist/objects/policies.d.ts +2 -2
  360. package/dist/objects/policies.js +2 -1
  361. package/dist/objects/processes.d.ts +2 -2
  362. package/dist/objects/project-briefs.d.ts +2 -2
  363. package/dist/objects/project-briefs.js +2 -3
  364. package/dist/objects/skills.d.ts +2 -2
  365. package/dist/postinstall.js +1 -1
  366. package/dist/rerankers/clef.js +3 -6
  367. package/dist/rerankers/cross-encoder.d.ts +31 -2
  368. package/dist/rerankers/cross-encoder.js +71 -98
  369. package/dist/rerankers/index.js +5 -4
  370. package/dist/rerankers/jev.js +2 -4
  371. package/dist/rerankers/outage-warning.d.ts +3 -1
  372. package/dist/rerankers/outage-warning.js +5 -3
  373. package/dist/search/bm25-search.js +1 -1
  374. package/dist/search/boosts.js +1 -1
  375. package/dist/search/embed-memories.d.ts +12 -0
  376. package/dist/search/embed-memories.js +389 -0
  377. package/dist/search/engine.d.ts +8 -0
  378. package/dist/search/engine.js +10 -0
  379. package/dist/search/goal-boost.d.ts +1 -1
  380. package/dist/search/goal-boost.js +6 -3
  381. package/dist/search/hybrid.d.ts +9 -2
  382. package/dist/search/hybrid.js +9 -4
  383. package/dist/search/physics-search.d.ts +6 -3
  384. package/dist/search/physics-search.js +22 -15
  385. package/dist/search/rerank.js +1 -1
  386. package/dist/search/vector.d.ts +8 -6
  387. package/dist/search/vector.js +14 -17
  388. package/dist/server/auth.d.ts +3 -1
  389. package/dist/server/auth.js +24 -15
  390. package/dist/server/boot.d.ts +2 -1
  391. package/dist/server/boot.js +34 -84
  392. package/dist/server/client-ip.d.ts +9 -6
  393. package/dist/server/client-ip.js +36 -17
  394. package/dist/server/deadline.d.ts +0 -2
  395. package/dist/server/deadline.js +1 -7
  396. package/dist/server/defaults.d.ts +1 -0
  397. package/dist/server/defaults.js +1 -0
  398. package/dist/server/mcp-http.js +16 -11
  399. package/dist/server/request.js +7 -2
  400. package/dist/server/route-checks.d.ts +7 -0
  401. package/dist/server/route-checks.js +42 -0
  402. package/dist/server/route-table.d.ts +9 -8
  403. package/dist/server/route-table.js +127 -133
  404. package/dist/server/routes/admin.d.ts +8 -8
  405. package/dist/server/routes/admin.js +13 -21
  406. package/dist/server/routes/customer-notes.d.ts +6 -6
  407. package/dist/server/routes/customer-notes.js +1 -2
  408. package/dist/server/routes/decisions.d.ts +6 -6
  409. package/dist/server/routes/decisions.js +2 -4
  410. package/dist/server/routes/incidents.d.ts +6 -6
  411. package/dist/server/routes/incidents.js +2 -5
  412. package/dist/server/routes/memories.d.ts +9 -9
  413. package/dist/server/routes/memories.js +19 -40
  414. package/dist/server/routes/object-routes.d.ts +6 -6
  415. package/dist/server/routes/object-routes.js +4 -7
  416. package/dist/server/routes/policies.d.ts +7 -7
  417. package/dist/server/routes/policies.js +2 -4
  418. package/dist/server/routes/predictions.d.ts +6 -6
  419. package/dist/server/routes/predictions.js +9 -13
  420. package/dist/server/routes/processes.d.ts +6 -6
  421. package/dist/server/routes/processes.js +1 -2
  422. package/dist/server/routes/project-briefs.d.ts +7 -7
  423. package/dist/server/routes/project-briefs.js +2 -4
  424. package/dist/server/routes/recall.d.ts +5 -5
  425. package/dist/server/routes/recall.js +6 -10
  426. package/dist/server/routes/skills.d.ts +7 -7
  427. package/dist/server/routes/skills.js +2 -4
  428. package/dist/server/server-detect.d.ts +7 -1
  429. package/dist/server/server-detect.js +36 -11
  430. package/dist/server/sleep-child.js +26 -7
  431. package/dist/server/sleep-offload.d.ts +11 -5
  432. package/dist/server/sleep-offload.js +17 -11
  433. package/dist/server/tls.d.ts +7 -2
  434. package/dist/server/tls.js +17 -5
  435. package/dist/server/types.d.ts +29 -12
  436. package/dist/server/validation.d.ts +1 -2
  437. package/dist/server/validation.js +6 -11
  438. package/dist/server.d.ts +4 -40
  439. package/dist/server.js +3 -29
  440. package/dist/sharing/global-store.d.ts +4 -5
  441. package/dist/sharing/global-store.js +8 -13
  442. package/dist/sharing/global-sync.js +38 -45
  443. package/dist/sharing/project-merge.d.ts +7 -14
  444. package/dist/sharing/project-merge.js +57 -121
  445. package/dist/sharing/search-both.js +10 -3
  446. package/dist/sharing/share.d.ts +2 -0
  447. package/dist/sharing/share.js +39 -38
  448. package/dist/store/ambient.js +7 -7
  449. package/dist/store/audit-event.d.ts +1 -1
  450. package/dist/store/audit.d.ts +0 -16
  451. package/dist/store/audit.js +4 -55
  452. package/dist/store/auth.d.ts +4 -2
  453. package/dist/store/auth.js +7 -3
  454. package/dist/store/candidates.d.ts +3 -2
  455. package/dist/store/candidates.js +59 -30
  456. package/dist/store/capture-write.d.ts +17 -0
  457. package/dist/store/capture-write.js +35 -0
  458. package/dist/store/cards.js +6 -5
  459. package/dist/store/compaction-caller.d.ts +18 -0
  460. package/dist/store/compaction-caller.js +29 -0
  461. package/dist/store/compactions-record.d.ts +115 -0
  462. package/dist/store/compactions-record.js +418 -0
  463. package/dist/store/compactions.js +6 -4
  464. package/dist/store/conflicts.d.ts +7 -1
  465. package/dist/store/conflicts.js +13 -9
  466. package/dist/store/connectors/dlq.d.ts +10 -0
  467. package/dist/store/connectors/dlq.js +33 -0
  468. package/dist/store/connectors/event-log.d.ts +13 -0
  469. package/dist/store/connectors/event-log.js +24 -0
  470. package/dist/store/connectors/github.d.ts +7 -9
  471. package/dist/store/connectors/github.js +35 -60
  472. package/dist/store/connectors/slack.d.ts +2 -11
  473. package/dist/store/connectors/slack.js +24 -57
  474. package/dist/store/dashboard-reads.js +8 -6
  475. package/dist/store/delete-and-batch.d.ts +6 -0
  476. package/dist/store/delete-and-batch.js +40 -6
  477. package/dist/store/delivery-recorder.d.ts +12 -5
  478. package/dist/store/delivery-recorder.js +13 -11
  479. package/dist/store/descendant-page.js +8 -4
  480. package/dist/store/dormant.d.ts +1 -1
  481. package/dist/store/dormant.js +10 -4
  482. package/dist/store/embeddings/index.d.ts +2 -12
  483. package/dist/store/embeddings/index.js +5 -374
  484. package/dist/store/entry-reads.d.ts +35 -4
  485. package/dist/store/entry-reads.js +86 -19
  486. package/dist/store/entry-row.js +9 -2
  487. package/dist/store/entry-writes.d.ts +15 -12
  488. package/dist/store/entry-writes.js +54 -22
  489. package/dist/store/failure-log-at.d.ts +8 -0
  490. package/dist/store/failure-log-at.js +16 -0
  491. package/dist/store/failure-log.d.ts +2 -2
  492. package/dist/store/failure-log.js +5 -3
  493. package/dist/{trust → store}/gated-write.d.ts +3 -1
  494. package/dist/{trust → store}/gated-write.js +7 -5
  495. package/dist/store/goals.js +22 -19
  496. package/dist/store/graph-reads.js +9 -6
  497. package/dist/store/graph-view-rows.js +2 -1
  498. package/dist/store/graph-writes.d.ts +6 -6
  499. package/dist/store/graph-writes.js +48 -71
  500. package/dist/store/half-life.js +2 -2
  501. package/dist/store/handoffs.d.ts +10 -4
  502. package/dist/store/handoffs.js +10 -9
  503. package/dist/store/index-and-stats.js +2 -2
  504. package/dist/store/index.d.ts +2 -2
  505. package/dist/store/index.js +1 -1
  506. package/dist/store/key-writes.js +1 -1
  507. package/dist/store/ledger-turn.d.ts +9 -0
  508. package/dist/store/ledger-turn.js +38 -0
  509. package/dist/store/mirrors.js +19 -10
  510. package/dist/store/open.d.ts +2 -5
  511. package/dist/store/open.js +42 -54
  512. package/dist/store/pilot-arm.d.ts +12 -0
  513. package/dist/store/pilot-arm.js +42 -0
  514. package/dist/store/port.d.ts +68 -6
  515. package/dist/store/port.js +8 -0
  516. package/dist/store/predictions.d.ts +1 -2
  517. package/dist/store/predictions.js +3 -6
  518. package/dist/store/project-tags.d.ts +62 -0
  519. package/dist/store/project-tags.js +67 -0
  520. package/dist/store/quality-repair.js +1 -1
  521. package/dist/store/quarantine.js +2 -1
  522. package/dist/store/recall-trace.d.ts +2 -0
  523. package/dist/store/recall-trace.js +20 -3
  524. package/dist/store/rejected-values.js +16 -10
  525. package/dist/store/rejection-probe.d.ts +4 -0
  526. package/dist/store/rejection-probe.js +19 -0
  527. package/dist/store/rejection.d.ts +0 -17
  528. package/dist/store/rejection.js +1 -21
  529. package/dist/store/rows.js +2 -2
  530. package/dist/store/rule-sql.d.ts +11 -0
  531. package/dist/store/rule-sql.js +31 -6
  532. package/dist/store/search-rows.d.ts +5 -5
  533. package/dist/store/search-rows.js +18 -16
  534. package/dist/store/sessions.js +4 -2
  535. package/dist/store/set-aside.d.ts +14 -0
  536. package/dist/store/set-aside.js +23 -0
  537. package/dist/store/sqlite/busy.d.ts +3 -0
  538. package/dist/store/sqlite/busy.js +8 -0
  539. package/dist/store/sqlite/connector-events-group.js +4 -7
  540. package/dist/store/sqlite/connector-writes-group.js +6 -4
  541. package/dist/store/sqlite/entry-writes-group.d.ts +3 -3
  542. package/dist/store/sqlite/entry-writes-group.js +3 -3
  543. package/dist/store/sqlite/error-codec.js +4 -3
  544. package/dist/store/sqlite/executor.js +10 -4
  545. package/dist/store/sqlite/graph-reads-group.js +1 -1
  546. package/dist/store/sqlite/held-connection.d.ts +11 -0
  547. package/dist/store/sqlite/held-connection.js +41 -0
  548. package/dist/store/sqlite/last-recall-group.d.ts +13 -0
  549. package/dist/store/sqlite/last-recall-group.js +57 -0
  550. package/dist/store/sqlite/local.d.ts +0 -17
  551. package/dist/store/sqlite/local.js +0 -31
  552. package/dist/store/sqlite/maintenance-groups.d.ts +6 -0
  553. package/dist/store/sqlite/maintenance-groups.js +60 -0
  554. package/dist/store/sqlite/object-rows.d.ts +1 -1
  555. package/dist/store/sqlite/objects-group.d.ts +1 -1
  556. package/dist/store/sqlite/objects-group.js +15 -7
  557. package/dist/store/sqlite/store.d.ts +1 -8
  558. package/dist/store/sqlite/store.js +13 -22
  559. package/dist/store/summaries.d.ts +10 -3
  560. package/dist/store/summaries.js +54 -11
  561. package/dist/store/token-ledger-rows.js +3 -2
  562. package/dist/store/token-ledger.d.ts +0 -7
  563. package/dist/store/token-ledger.js +0 -35
  564. package/dist/store/vector-index.js +8 -4
  565. package/dist/support-bundle.js +2 -3
  566. package/dist/trust/reject-flow.js +2 -2
  567. package/dist/util/agent-homes.d.ts +15 -0
  568. package/dist/util/agent-homes.js +34 -0
  569. package/dist/util/anthropic-messages.d.ts +6 -1
  570. package/dist/util/anthropic-messages.js +26 -7
  571. package/dist/util/atomic-write.d.ts +5 -2
  572. package/dist/util/atomic-write.js +12 -8
  573. package/dist/util/chunked.d.ts +3 -0
  574. package/dist/util/chunked.js +10 -0
  575. package/dist/util/ellipsize.d.ts +3 -0
  576. package/dist/util/ellipsize.js +5 -0
  577. package/dist/util/env.d.ts +12 -2
  578. package/dist/util/env.js +12 -2
  579. package/dist/util/format.d.ts +5 -0
  580. package/dist/util/format.js +10 -0
  581. package/dist/util/hook-payload.d.ts +8 -0
  582. package/dist/util/hook-payload.js +37 -0
  583. package/dist/util/http-retry.d.ts +6 -0
  584. package/dist/util/http-retry.js +43 -5
  585. package/dist/util/http-util.d.ts +0 -8
  586. package/dist/util/http-util.js +10 -21
  587. package/dist/util/limits.d.ts +7 -0
  588. package/dist/util/limits.js +14 -0
  589. package/dist/util/log.d.ts +4 -0
  590. package/dist/util/log.js +9 -0
  591. package/dist/util/request-scope.d.ts +9 -3
  592. package/dist/util/request-scope.js +18 -9
  593. package/dist/util/secret-detect.js +6 -1
  594. package/dist/util/spawn-argv.d.ts +9 -0
  595. package/dist/util/spawn-argv.js +57 -0
  596. package/dist/util/sql.d.ts +3 -0
  597. package/dist/util/sql.js +6 -0
  598. package/dist/util/sqlite-blocked.d.ts +2 -0
  599. package/dist/util/sqlite-blocked.js +5 -0
  600. package/dist/util/stream-tee.d.ts +3 -0
  601. package/dist/util/stream-tee.js +35 -0
  602. package/dist/util/time.d.ts +4 -0
  603. package/dist/util/time.js +4 -0
  604. package/dist/util/vector-codec.d.ts +4 -0
  605. package/dist/util/vector-codec.js +15 -0
  606. package/dist/util/version.d.ts +1 -1
  607. package/dist/util/version.js +1 -1
  608. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  609. package/extensions/openclaw-plugin/package.json +1 -1
  610. package/openclaw.plugin.json +1 -1
  611. package/package.json +4 -2
  612. package/dist/api/on-store.d.ts +0 -16
  613. package/dist/api/on-store.js +0 -38
  614. package/dist/store/embeddings/local.d.ts +0 -15
  615. package/dist/store/embeddings/local.js +0 -175
  616. /package/dist/{cli → api}/correction-latency.d.ts +0 -0
  617. /package/dist/{cli → api}/correction-latency.js +0 -0
  618. /package/dist/{cli → api}/provenance-coverage.d.ts +0 -0
  619. /package/dist/{cli → api}/provenance-coverage.js +0 -0
  620. /package/dist/{store → core}/object-types.d.ts +0 -0
  621. /package/dist/{store → core}/object-types.js +0 -0
  622. /package/dist/{capture → util}/compaction-items.d.ts +0 -0
  623. /package/dist/{capture → util}/compaction-items.js +0 -0
  624. /package/dist/{store → util}/yaml.d.ts +0 -0
  625. /package/dist/{store → util}/yaml.js +0 -0
@@ -1,88 +1,46 @@
1
- import { bumpGitHubDlqRetryCount, githubDlqEntry, listGitHubDlq, } from '../../store/connectors/github.js';
2
- import { replayFailed } from '../dlq.js';
1
+ import { githubDlqEntry, markGitHubDlqRetried, listGitHubDlq, } from '../../store/connectors/github.js';
2
+ import { replayParked } from '../dlq.js';
3
3
  import { verifyGitHubSignature } from './signature.js';
4
4
  import { isGitHubWebhookEnvelope } from './types.js';
5
5
  /** GitHub's dead-letter table; the event, delivery, installation and repo columns let an operator triage a row without re-reading the payload. */
6
6
  export const githubDlq = {
7
7
  letter: (row) => ({ connector: 'github', ...row }),
8
8
  list: listGitHubDlq,
9
+ entry: githubDlqEntry,
10
+ bump: markGitHubDlqRetried,
9
11
  };
10
12
  /** Replay a DLQ row through the normal ingest path; a failed signature, parse or envelope check bumps retry_count.
11
13
  * Without an `ingestHook` (dry-run) it bumps retry_count and returns `replayed` with memoryId=null; replays use today's routing, not the original's. */
12
14
  export async function replayDlqEntry(ctx, id, opts = {}) {
13
- const row = githubDlqEntry(ctx.hippoRoot, id);
14
- if (!row)
15
- return replayFailed('not_found', 0, `dlq id ${id} not found`);
16
- // Signature verification (current secret, not the one in effect when DLQed).
17
- if (!opts.force && opts.webhookSecret) {
18
- const sigFailure = checkReplaySignature(ctx.hippoRoot, id, row, opts.webhookSecret, opts.previousSecret);
19
- if (sigFailure)
20
- return sigFailure;
21
- }
22
- const envelopeFailure = checkReplayEnvelope(ctx.hippoRoot, id, row);
23
- if (envelopeFailure)
24
- return envelopeFailure;
25
- // Without an ingest hook this is a dry-run validation. Bump and report.
26
- if (!opts.ingestHook) {
27
- bumpGitHubDlqRetryCount(ctx.hippoRoot, id);
28
- return {
29
- ok: true,
30
- status: 'replayed',
31
- memoryId: null,
32
- retryCount: row.retryCount + 1,
33
- reason: 'dry-run: no ingest hook supplied',
34
- };
35
- }
36
- // Real replay path: the route's IngestHook owns routing, idempotency and the memory write; this module only validates and bumps the retry counter.
37
- // No idempotencyKey arg: the hook re-derives it from the parsed event (artifact_ref + updated_at).
38
- const eventName = row.eventName ?? '';
39
- const deliveryId = row.deliveryId ?? '';
40
- const { memoryId } = await opts.ingestHook(ctx, {
41
- rawPayload: row.rawPayload,
42
- eventName,
43
- deliveryId,
44
- });
45
- bumpGitHubDlqRetryCount(ctx.hippoRoot, id);
46
- return {
47
- ok: true,
48
- status: 'replayed',
49
- memoryId,
50
- retryCount: row.retryCount + 1,
51
- };
15
+ const { webhookSecret, previousSecret, ingestHook } = opts;
16
+ return replayParked({
17
+ dlq: githubDlq,
18
+ // The secret in effect now, not the one in effect when the row was parked.
19
+ refuseSignature: (row) => (webhookSecret ? refuseSignature(row, webhookSecret, previousSecret) : null),
20
+ isEnvelope: isGitHubWebhookEnvelope,
21
+ notEnvelope: 'not a GitHub webhook envelope',
22
+ reingest: async (row) => {
23
+ if (!ingestHook)
24
+ return { ok: true, status: 'replayed', memoryId: null, reason: 'dry-run: no ingest hook supplied' };
25
+ // The hook owns routing, idempotency and the memory write, and re-derives the key from the parsed event.
26
+ const { memoryId } = await ingestHook(ctx, {
27
+ rawPayload: row.rawPayload,
28
+ eventName: row.eventName ?? '',
29
+ deliveryId: row.deliveryId ?? '',
30
+ });
31
+ return { ok: true, status: 'replayed', memoryId };
32
+ },
33
+ }, ctx.hippoRoot, id, opts.force === true);
52
34
  }
53
- /** The failure result when the row cannot pass the signature gate, else null. */
54
- function checkReplaySignature(hippoRoot, id, row, webhookSecret, previousSecret) {
35
+ function refuseSignature(row, webhookSecret, previousSecret) {
55
36
  if (!row.signature) {
56
- return replayFailed('sig_missing', row.retryCount, 'row has no signature (legacy, or redacted before storing); pass --force to replay');
57
- }
58
- const sigOk = verifyGitHubSignature({
59
- rawBody: row.rawPayload,
60
- signature: row.signature,
61
- webhookSecret,
62
- previousSecret,
63
- });
64
- if (!sigOk) {
65
- bumpGitHubDlqRetryCount(hippoRoot, id);
66
- return replayFailed('sig_fail', row.retryCount + 1, 'signature did not verify against current GITHUB_WEBHOOK_SECRET; pass --force to replay anyway');
37
+ return { status: 'sig_missing', reason: 'row has no signature (legacy, or redacted before storing); pass --force to replay' };
67
38
  }
68
- return null;
69
- }
70
- /** Parse + envelope guard; the failure result after bumping the count, else null. */
71
- function checkReplayEnvelope(hippoRoot, id, row) {
72
- let parsed;
73
- try {
74
- parsed = JSON.parse(row.rawPayload);
75
- }
76
- catch (e) {
77
- bumpGitHubDlqRetryCount(hippoRoot, id);
78
- // SAFETY: best-effort error message only; property access on any JS value is safe, even for a non-Error throw.
79
- const message = e.message;
80
- return replayFailed('parse_error', row.retryCount + 1, `still unparseable: ${message}`);
81
- }
82
- if (!isGitHubWebhookEnvelope(parsed)) {
83
- bumpGitHubDlqRetryCount(hippoRoot, id);
84
- return replayFailed('unhandled', row.retryCount + 1, 'not a GitHub webhook envelope');
85
- }
86
- return null;
39
+ if (verifyGitHubSignature({ rawBody: row.rawPayload, signature: row.signature, webhookSecret, previousSecret }))
40
+ return null;
41
+ return {
42
+ status: 'sig_fail',
43
+ reason: 'signature did not verify against current GITHUB_WEBHOOK_SECRET; pass --force to replay anyway',
44
+ };
87
45
  }
88
46
  //# sourceMappingURL=dlq.js.map
@@ -1,10 +1,6 @@
1
- import { type Context } from '../../api/index.js';
1
+ import type { Context } from '../../api/index.js';
2
+ import { type IngestResult } from '../ingest.js';
2
3
  import type { GitHubIssueEvent, GitHubIssueCommentEvent, GitHubPullRequestEvent, GitHubPullRequestReviewCommentEvent } from './types.js';
3
- export type IngestStatus = 'ingested' | 'duplicate' | 'skipped' | 'skipped_duplicate';
4
- export interface IngestResult {
5
- status: IngestStatus;
6
- memoryId: string | null;
7
- }
8
4
  /** Discriminated union of the four event shapes V1 ingests; eventName MUST equal the X-GitHub-Event header,
9
5
  * since computeIdempotencyKey folds it into the dedupe key. */
10
6
  export type IngestEvent = {
@@ -1,9 +1,9 @@
1
1
  // GitHub event ingest, once per idempotency key. The key comes from the event's own content, never from the unsigned
2
2
  // X-GitHub-Delivery header, so a replay cannot get past it by rotating the delivery id. The pre-check is only the fast path:
3
3
  // the store logs the key in the memory's own transaction, which is what holds when two workers race.
4
- import { remember } from '../../api/index.js';
5
- import { requireGroup, storeFor } from '../../store/index.js';
6
- import { RejectedValueError } from '../../store/rejection.js';
4
+ import { requireGroup } from '../../store/index.js';
5
+ import { storeFor } from '../../store/sqlite/store.js';
6
+ import { rememberWithEventLog } from '../ingest.js';
7
7
  import { computeIdempotencyKey } from './signature.js';
8
8
  import { issueEventToRememberOpts, issueCommentEventToRememberOpts, pullRequestEventToRememberOpts, prReviewCommentEventToRememberOpts, } from './transform.js';
9
9
  function transformEvent(event) {
@@ -54,31 +54,7 @@ export async function ingestEvent(ctx, input) {
54
54
  const seen = await events.eventRecord(event);
55
55
  if (seen.seen)
56
56
  return { status: 'duplicate', memoryId: seen.memoryId };
57
- const opts = transformEvent(input.event);
58
- if (!opts) {
59
- // Empty body: no memory to write, but mark seen so a retry returns 'duplicate' instead of re-running the transform.
60
- await events.markEventSeen(event);
61
- return { status: 'skipped', memoryId: null };
62
- }
63
- try {
64
- return await rememberWithEventLog(ctx, event, opts);
65
- }
66
- catch (e) {
67
- if (e instanceof RejectedValueError) {
68
- // A tombstone hit is a PERMANENT skip, never DLQ-retried: mark the key seen like the empty-body
69
- // branch above so a GitHub retry of the same delivery acks as done, not error.
70
- await events.markEventSeen(event);
71
- return { status: 'skipped', memoryId: null };
72
- }
73
- throw e;
74
- }
75
- }
76
- async function rememberWithEventLog(ctx, event, opts) {
77
- // No `|| 'connector:github'` fallback: the caller always builds ctx with the connector subject (same as slack/ingest.ts).
78
- const result = await remember(ctx, { ...opts, untrusted: true, event });
79
- // Another worker logged this key between the pre-check and the write: its memory stands and ours was not stored.
80
- if (result.duplicate)
81
- return { status: 'skipped_duplicate', memoryId: result.duplicate.memoryId };
82
- return { status: 'ingested', memoryId: result.id };
57
+ // An empty body is logged too, so a retry returns 'duplicate' instead of re-running the transform.
58
+ return rememberWithEventLog(ctx, event, transformEvent(input.event));
83
59
  }
84
60
  //# sourceMappingURL=ingest.js.map
@@ -1,5 +1,6 @@
1
1
  import { envGitHubAllowUnknownInstallationFallback, envTenant } from '../../util/env.js';
2
- import { requireGroup, storeFor } from '../../store/index.js';
2
+ import { requireGroup } from '../../store/index.js';
3
+ import { storeFor } from '../../store/sqlite/store.js';
3
4
  /** Resolve a GitHub envelope's tenant_id by installation id, then repository.full_name; the HIPPO_TENANT fallback applies only if both tables are empty.
4
5
  * An unknown installation or repo on a multi-tenant deployment returns null (fail closed); GITHUB_ALLOW_UNKNOWN_INSTALLATION_FALLBACK=1 escapes. */
5
6
  export async function resolveTenantForGitHub(hippoRoot, args, store) {
@@ -1,6 +1,7 @@
1
1
  import type { HippoStore } from '../../store/index.js';
2
2
  import { type WebhookRequest } from '../../util/http-util.js';
3
3
  /** GitHub webhook receiver: HMAC SHA-256 over the raw body, event type from the X-GitHub-Event header, tenant by installation.id then repository.full_name.
4
- * ACKs 200 on signed envelopes (DLQ too); 401 only on a bad signature; 404 when GITHUB_WEBHOOK_SECRET is unset. No Bearer: server.ts checks isPublicRoute. */
4
+ * ACKs 200 on signed envelopes (DLQ too); 401 only on a bad signature; 409 on a delivery id seen in the replay window;
5
+ * 404 when GITHUB_WEBHOOK_SECRET is unset. No Bearer: its route row declares webhook-signature. */
5
6
  export declare function handleGitHubEventsWebhook(request: WebhookRequest, store?: HippoStore): Promise<void>;
6
7
  //# sourceMappingURL=webhook.d.ts.map
@@ -1,4 +1,5 @@
1
1
  import { envGitHubWebhookSecret, envGitHubWebhookSecretPrevious } from '../../util/env.js';
2
+ import { DAY_MS } from '../../util/time.js';
2
3
  import { verifyGitHubSignature } from './signature.js';
3
4
  import { isGitHubWebhookEnvelope, isGitHubIssueEvent, isGitHubIssueCommentEvent, isGitHubPullRequestEvent, isGitHubPullRequestReviewCommentEvent, } from './types.js';
4
5
  import { ingestEvent as ingestGitHubEvent } from './ingest.js';
@@ -10,7 +11,8 @@ import { computeDeletionKey as computeGitHubDeletionKey } from './signature.js';
10
11
  import { resolveTenantId } from '../../store/tenant.js';
11
12
  import { HttpError, JSON_HEADERS, isHeaderString, closeIfBodyUnread, readWebhookBody, sendJson, } from '../../util/http-util.js';
12
13
  /** GitHub webhook receiver: HMAC SHA-256 over the raw body, event type from the X-GitHub-Event header, tenant by installation.id then repository.full_name.
13
- * ACKs 200 on signed envelopes (DLQ too); 401 only on a bad signature; 404 when GITHUB_WEBHOOK_SECRET is unset. No Bearer: server.ts checks isPublicRoute. */
14
+ * ACKs 200 on signed envelopes (DLQ too); 401 only on a bad signature; 409 on a delivery id seen in the replay window;
15
+ * 404 when GITHUB_WEBHOOK_SECRET is unset. No Bearer: its route row declares webhook-signature. */
14
16
  export async function handleGitHubEventsWebhook(request, store) {
15
17
  const { req, res, opts } = request;
16
18
  // Secret and signature header before the body, so a caller with neither cannot make the server buffer one.
@@ -43,7 +45,38 @@ export async function handleGitHubEventsWebhook(request, store) {
43
45
  }
44
46
  // Signature OK from here on. Everything else is ACK-200; bad envelopes go
45
47
  // to the DLQ and a human can replay later.
46
- await routeSignedDelivery({ hippoRoot: opts.hippoRoot, store, res, rawBody, eventName, deliveryId, signature: sigStr });
48
+ const replayKey = deliveryId === null ? null : `${opts.hippoRoot}\n${deliveryId}`;
49
+ if (replayKey !== null && !claimDelivery(replayKey, Date.now()))
50
+ throw new HttpError(409, 'duplicate X-GitHub-Delivery');
51
+ try {
52
+ await routeSignedDelivery({ hippoRoot: opts.hippoRoot, store, res, rawBody, eventName, deliveryId, signature: sigStr });
53
+ }
54
+ catch (err) {
55
+ // A delivery that failed left nothing stored, so GitHub's redelivery of the same id must get through.
56
+ if (replayKey !== null)
57
+ seenDeliveries.delete(replayKey);
58
+ throw err;
59
+ }
60
+ }
61
+ // GitHub signs no timestamp, so a captured delivery verifies forever; this window is what refuses its replay.
62
+ const DELIVERY_REPLAY_TTL_MS = DAY_MS;
63
+ const DELIVERY_REPLAY_MAX_IDS = 10_000;
64
+ // A fast path only: the durable dedupe is the connector event log's content-derived idempotency key (ingest.ts, and the deletion key below),
65
+ // so a replay after a restart or an eviction is a stored 'duplicate' with no new rows.
66
+ const seenDeliveries = new Map();
67
+ /** Claims a delivery id for the window; false when it was claimed within the window already. The oldest claim goes first at the cap. */
68
+ function claimDelivery(key, now) {
69
+ const seenAt = seenDeliveries.get(key);
70
+ if (seenAt !== undefined && now - seenAt < DELIVERY_REPLAY_TTL_MS)
71
+ return false;
72
+ seenDeliveries.delete(key);
73
+ if (seenDeliveries.size >= DELIVERY_REPLAY_MAX_IDS) {
74
+ const oldest = seenDeliveries.keys().next();
75
+ if (!oldest.done)
76
+ seenDeliveries.delete(oldest.value);
77
+ }
78
+ seenDeliveries.set(key, now);
79
+ return true;
47
80
  }
48
81
  const ALLOWED_EVENTS = new Set([
49
82
  'issues',
@@ -0,0 +1,10 @@
1
+ import { type Context, type RememberOpts } from '../api/index.js';
2
+ import type { ConnectorEvent } from '../store/port.js';
3
+ export type IngestStatus = 'ingested' | 'duplicate' | 'skipped' | 'skipped_duplicate';
4
+ export interface IngestResult {
5
+ status: IngestStatus;
6
+ memoryId: string | null;
7
+ }
8
+ /** Stores `opts` once per event key; null `opts` (an empty body) and a tombstoned value are logged with no memory, so a redelivery acks instead of retrying. */
9
+ export declare function rememberWithEventLog(ctx: Context, event: ConnectorEvent, opts: RememberOpts | null): Promise<IngestResult>;
10
+ //# sourceMappingURL=ingest.d.ts.map
@@ -0,0 +1,29 @@
1
+ // The write half every connector's ingest shares, after its own pre-check of the event log.
2
+ import { remember } from '../api/index.js';
3
+ import { requireGroup } from '../store/index.js';
4
+ import { storeFor } from '../store/sqlite/store.js';
5
+ import { RejectedValueError } from '../core/api-errors.js';
6
+ /** Stores `opts` once per event key; null `opts` (an empty body) and a tombstoned value are logged with no memory, so a redelivery acks instead of retrying. */
7
+ export async function rememberWithEventLog(ctx, event, opts) {
8
+ if (!opts)
9
+ return markSkipped(ctx, event);
10
+ try {
11
+ // No actor fallback: every caller builds ctx with its connector subject.
12
+ const result = await remember(ctx, { ...opts, untrusted: true, event });
13
+ // Another worker logged this key between the pre-check and the write: its memory stands and ours was not stored.
14
+ if (result.duplicate)
15
+ return { status: 'skipped_duplicate', memoryId: result.duplicate.memoryId };
16
+ return { status: 'ingested', memoryId: result.id };
17
+ }
18
+ catch (e) {
19
+ // A tombstone refusal is permanent, so a DLQ retry would hit it forever.
20
+ if (e instanceof RejectedValueError)
21
+ return markSkipped(ctx, event);
22
+ throw e;
23
+ }
24
+ }
25
+ async function markSkipped(ctx, event) {
26
+ await requireGroup(storeFor(ctx), 'connectorEvents').markEventSeen(event);
27
+ return { status: 'skipped', memoryId: null };
28
+ }
29
+ //# sourceMappingURL=ingest.js.map
@@ -1,5 +1,6 @@
1
1
  import { archiveRaw } from '../../api/index.js';
2
- import { requireGroup, storeFor } from '../../store/index.js';
2
+ import { requireGroup } from '../../store/index.js';
3
+ import { storeFor } from '../../store/sqlite/store.js';
3
4
  /** Handles Slack `message_deleted`. The store logs the event in the archive's own transaction, so a crash cannot leave a retry
4
5
  * answering `not_found` where `duplicate` is due. */
5
6
  export async function handleMessageDeleted(ctx, input) {
@@ -1,96 +1,75 @@
1
1
  import { adminActor } from '../../api/index.js';
2
- import { bumpSlackDlqRetryCount, listSlackDlq, markSlackDlqRetried, slackDlqEntry, } from '../../store/connectors/slack.js';
3
- import { replayFailed } from '../dlq.js';
2
+ import { listSlackDlq, markSlackDlqRetried, slackDlqEntry, } from '../../store/connectors/slack.js';
3
+ import { replayParked } from '../dlq.js';
4
4
  import { ingestMessage } from './ingest.js';
5
5
  import { resolveTenantForSlackTeam } from './tenant-routing.js';
6
6
  import { verifySlackSignature } from './signature.js';
7
7
  import { isSlackEventEnvelope, isSlackMessageEvent } from './types.js';
8
8
  import { handleMessageDeleted } from './deletion.js';
9
- import { errorMessage } from '../../util/log.js';
9
+ import { YEAR_S } from '../../util/time.js';
10
10
  /** Slack's dead-letter table; `teamId` and `slackTimestamp` are the columns only it has. */
11
11
  export const slackDlq = {
12
12
  letter: (row) => ({ connector: 'slack', ...row }),
13
13
  list: listSlackDlq,
14
+ entry: slackDlqEntry,
15
+ bump: markSlackDlqRetried,
14
16
  };
15
17
  /** Replay a DLQ row via the normal ingest path (`hippo slack dlq replay <id> [--force]`), re-verifying the signature with the CURRENT secret unless forced.
16
18
  * Rows with a NULL signature need --force; replays use today's routing, because the DLQ exists to be drained after the operator fixed routing. */
17
19
  export async function replayDlqEntry(ctx, id, opts = {}) {
18
- const row = slackDlqEntry(ctx.hippoRoot, id);
19
- if (!row)
20
- return replayFailed('not_found', 0, `dlq id ${id} not found`);
21
- // Signature verification (current secret, not previous).
22
- if (!opts.force) {
23
- const sigFailure = checkReplaySignature(row, opts);
24
- if (sigFailure)
25
- return sigFailure;
26
- }
27
- // Parse + dispatch.
28
- let parsed;
29
- try {
30
- parsed = JSON.parse(row.rawPayload);
31
- }
32
- catch (e) {
33
- return failAndBump(ctx.hippoRoot, row, 'parse_error', `still unparseable: ${errorMessage(e)}`);
34
- }
35
- if (!isSlackEventEnvelope(parsed)) {
36
- return failAndBump(ctx.hippoRoot, row, 'unhandled', 'not an event_callback envelope');
37
- }
38
- // Resolve tenant against current state. If still unroutable, bail.
39
- const tenant = await resolveTenantForSlackTeam(ctx.hippoRoot, parsed.team_id);
40
- if (!tenant) {
41
- return failAndBump(ctx.hippoRoot, row, 'unroutable', `team_id ${parsed.team_id} still unroutable`);
42
- }
43
- const replayCtx = {
44
- hippoRoot: ctx.hippoRoot,
45
- tenantId: tenant,
46
- actor: adminActor('connector:slack:replay'),
47
- };
48
- return dispatchReplay(replayCtx, row, parsed);
20
+ return replayParked({
21
+ dlq: slackDlq,
22
+ refuseSignature: (row) => refuseSignature(row, opts),
23
+ isEnvelope: isSlackEventEnvelope,
24
+ notEnvelope: 'not an event_callback envelope',
25
+ reingest: (_row, envelope) => reingest(ctx.hippoRoot, envelope),
26
+ }, ctx.hippoRoot, id, opts.force === true);
49
27
  }
50
- /** The failure result when the row cannot pass the signature gate, else null; never bumps the count. */
51
- function checkReplaySignature(row, opts) {
28
+ /** A missing signature or timestamp refuses even without a secret; a mismatch needs the current secret to show. */
29
+ function refuseSignature(row, opts) {
52
30
  if (!row.signature || !row.slackTimestamp) {
53
- return replayFailed('sig_missing', row.retryCount, 'row has no signature/timestamp (legacy, or redacted before storing); pass --force to replay');
31
+ return {
32
+ status: 'sig_missing',
33
+ reason: 'row has no signature/timestamp (legacy, or redacted before storing); pass --force to replay',
34
+ };
54
35
  }
55
- if (opts.signingSecret) {
56
- const ok = verifySlackSignature({
57
- rawBody: row.rawPayload,
58
- signature: row.signature,
59
- timestamp: row.slackTimestamp,
60
- signingSecret: opts.signingSecret,
61
- now: opts.now,
62
- // Replays happen long after the fact — give them a wider skew unless overridden.
63
- skewSeconds: opts.skewSeconds ?? 60 * 60 * 24 * 365,
64
- });
65
- if (!ok) {
66
- return replayFailed('sig_fail', row.retryCount, 'signature did not verify against current SLACK_SIGNING_SECRET; pass --force to replay anyway');
67
- }
68
- }
69
- return null;
70
- }
71
- function failAndBump(hippoRoot, row, status, reason) {
72
- bumpSlackDlqRetryCount(hippoRoot, row.id);
73
- return replayFailed(status, row.retryCount + 1, reason);
36
+ if (!opts.signingSecret)
37
+ return null;
38
+ const ok = verifySlackSignature({
39
+ rawBody: row.rawPayload,
40
+ signature: row.signature,
41
+ timestamp: row.slackTimestamp,
42
+ signingSecret: opts.signingSecret,
43
+ now: opts.now,
44
+ // Replays happen long after the fact, so give them a wider skew unless overridden.
45
+ skewSeconds: opts.skewSeconds ?? YEAR_S,
46
+ });
47
+ if (ok)
48
+ return null;
49
+ return {
50
+ status: 'sig_fail',
51
+ reason: 'signature did not verify against current SLACK_SIGNING_SECRET; pass --force to replay anyway',
52
+ };
74
53
  }
75
- async function dispatchReplay(replayCtx, row, parsed) {
76
- const { hippoRoot } = replayCtx;
77
- const id = row.id;
78
- const inner = parsed.event;
79
- if (!isSlackMessageEvent(inner)) {
80
- return failAndBump(hippoRoot, row, 'unhandled', `unhandled inner event type`);
81
- }
54
+ async function reingest(hippoRoot, envelope) {
55
+ const tenantId = await resolveTenantForSlackTeam(hippoRoot, envelope.team_id);
56
+ if (!tenantId)
57
+ return { ok: false, status: 'unroutable', reason: `team_id ${envelope.team_id} still unroutable` };
58
+ const inner = envelope.event;
59
+ if (!isSlackMessageEvent(inner))
60
+ return { ok: false, status: 'unhandled', reason: 'unhandled inner event type' };
61
+ const replayCtx = { hippoRoot, tenantId, actor: adminActor('connector:slack:replay') };
82
62
  if (inner.subtype === 'message_deleted' && inner.deleted_ts) {
83
63
  const r = await handleMessageDeleted(replayCtx, {
84
- teamId: parsed.team_id,
64
+ teamId: envelope.team_id,
85
65
  channelId: inner.channel,
86
66
  deletedTs: inner.deleted_ts,
87
- eventId: parsed.event_id,
67
+ eventId: envelope.event_id,
88
68
  });
89
- markSlackDlqRetried(hippoRoot, id);
90
- return { ok: true, status: r.status, memoryId: r.memoryId, retryCount: row.retryCount + 1 };
69
+ return { ok: true, status: r.status, memoryId: r.memoryId };
91
70
  }
92
71
  const result = await ingestMessage(replayCtx, {
93
- teamId: parsed.team_id,
72
+ teamId: envelope.team_id,
94
73
  channel: {
95
74
  id: inner.channel,
96
75
  is_private: inner.channel_type !== 'channel',
@@ -98,9 +77,8 @@ async function dispatchReplay(replayCtx, row, parsed) {
98
77
  is_mpim: inner.channel_type === 'mpim',
99
78
  },
100
79
  message: inner,
101
- eventId: parsed.event_id,
80
+ eventId: envelope.event_id,
102
81
  });
103
- markSlackDlqRetried(hippoRoot, id);
104
- return { ok: true, status: result.status, memoryId: result.memoryId, retryCount: row.retryCount + 1 };
82
+ return { ok: true, status: result.status, memoryId: result.memoryId };
105
83
  }
106
84
  //# sourceMappingURL=dlq.js.map
@@ -1,4 +1,5 @@
1
- import { type Context } from '../../api/index.js';
1
+ import type { Context } from '../../api/index.js';
2
+ import { type IngestResult } from '../ingest.js';
2
3
  import type { ChannelMeta } from './scope.js';
3
4
  import type { SlackMessageEvent } from './types.js';
4
5
  export interface IngestInput {
@@ -8,11 +9,6 @@ export interface IngestInput {
8
9
  /** Slack event_id for the envelope (or for backfill, a synthesized stable id). */
9
10
  eventId: string;
10
11
  }
11
- export type IngestStatus = 'ingested' | 'duplicate' | 'skipped' | 'skipped_duplicate';
12
- export interface IngestResult {
13
- status: IngestStatus;
14
- memoryId: string | null;
15
- }
16
12
  /** Ingests a Slack message as a kind='raw' memory once per event id (Slack redelivers within a minute); the pre-check is only the fast path,
17
13
  * the store logs the event in the memory's own transaction, which holds when two workers race. An empty body is logged with no memory. */
18
14
  export declare function ingestMessage(ctx: Context, input: IngestInput): Promise<IngestResult>;
@@ -1,6 +1,6 @@
1
- import { remember } from '../../api/index.js';
2
- import { requireGroup, storeFor } from '../../store/index.js';
3
- import { RejectedValueError } from '../../store/rejection.js';
1
+ import { requireGroup } from '../../store/index.js';
2
+ import { storeFor } from '../../store/sqlite/store.js';
3
+ import { rememberWithEventLog } from '../ingest.js';
4
4
  import { messageToRememberOpts } from './transform.js';
5
5
  /** Ingests a Slack message as a kind='raw' memory once per event id (Slack redelivers within a minute); the pre-check is only the fast path,
6
6
  * the store logs the event in the memory's own transaction, which holds when two workers race. An empty body is logged with no memory. */
@@ -15,30 +15,6 @@ export async function ingestMessage(ctx, input) {
15
15
  // they first returned; a non-NULL memory_id means a memory was ingested, so 'duplicate'.
16
16
  return { status: seen.memoryId === null ? 'skipped' : 'duplicate', memoryId: seen.memoryId };
17
17
  }
18
- const opts = messageToRememberOpts(input);
19
- if (!opts) {
20
- await events.markEventSeen(event);
21
- return { status: 'skipped', memoryId: null };
22
- }
23
- try {
24
- return await rememberWithEventLog(ctx, event, opts);
25
- }
26
- catch (e) {
27
- if (!(e instanceof RejectedValueError))
28
- throw e;
29
- // A tombstone hit is a PERMANENT skip: a DLQ retry would hit the same refusal forever, so mark the
30
- // event seen like the empty-body branch above and let a Slack retry ack as done, not error.
31
- await events.markEventSeen(event);
32
- return { status: 'skipped', memoryId: null };
33
- }
34
- }
35
- async function rememberWithEventLog(ctx, event, opts) {
36
- // No `|| 'connector:slack'` fallback: the caller always builds ctx with the connector subject, and with
37
- // an object-shaped Context.actor an OR-fallback would never fire anyway.
38
- const result = await remember(ctx, { ...opts, untrusted: true, event });
39
- // Another worker logged this event between the pre-check and the write: its memory stands and ours was not stored.
40
- if (result.duplicate)
41
- return { status: 'skipped_duplicate', memoryId: result.duplicate.memoryId };
42
- return { status: 'ingested', memoryId: result.id };
18
+ return rememberWithEventLog(ctx, event, messageToRememberOpts(input));
43
19
  }
44
20
  //# sourceMappingURL=ingest.js.map
@@ -1,5 +1,6 @@
1
1
  import { envSlackAllowUnknownTeamFallback, envTenant } from '../../util/env.js';
2
- import { requireGroup, storeFor } from '../../store/index.js';
2
+ import { requireGroup } from '../../store/index.js';
3
+ import { storeFor } from '../../store/sqlite/store.js';
3
4
  /** Look up the tenant_id for a Slack team_id; the HIPPO_TENANT fallback applies only when slack_workspaces is empty (single-workspace install).
4
5
  * An unknown team on a multi-workspace install returns null (fail closed); SLACK_ALLOW_UNKNOWN_TEAM_FALLBACK=1 is the emergency escape. */
5
6
  export async function resolveTenantForSlackTeam(hippoRoot, teamId, store) {
@@ -1,6 +1,7 @@
1
1
  import type { HippoStore } from '../../store/index.js';
2
2
  import { type WebhookRequest } from '../../util/http-util.js';
3
- /** Slack Events API webhook: HMAC over the raw body with SLACK_SIGNING_SECRET, no Bearer (hence PUBLIC_ROUTES); malformed payloads go to slack_dlq, ACK 200.
3
+ /** Slack Events API webhook: HMAC over the raw body with SLACK_SIGNING_SECRET, no Bearer (its route row declares webhook-signature);
4
+ * malformed payloads go to slack_dlq, ACK 200.
4
5
  * 404 (not 503) when the secret is unset, so a probe cannot tell a gated-off route from a missing one. */
5
6
  export declare function handleSlackEventsWebhook(request: WebhookRequest, store?: HippoStore): Promise<void>;
6
7
  //# sourceMappingURL=webhook.d.ts.map
@@ -9,7 +9,8 @@ import { resolveTenantForSlackTeam } from './tenant-routing.js';
9
9
  import { resolveTenantId } from '../../store/tenant.js';
10
10
  import { HttpError, JSON_HEADERS, isHeaderString, closeIfBodyUnread, readWebhookBody, sendJson } from '../../util/http-util.js';
11
11
  import { isJsonObject } from '../../util/json.js';
12
- /** Slack Events API webhook: HMAC over the raw body with SLACK_SIGNING_SECRET, no Bearer (hence PUBLIC_ROUTES); malformed payloads go to slack_dlq, ACK 200.
12
+ /** Slack Events API webhook: HMAC over the raw body with SLACK_SIGNING_SECRET, no Bearer (its route row declares webhook-signature);
13
+ * malformed payloads go to slack_dlq, ACK 200.
13
14
  * 404 (not 503) when the secret is unset, so a probe cannot tell a gated-off route from a missing one. */
14
15
  export async function handleSlackEventsWebhook(request, store) {
15
16
  const { req, res, opts } = request;
@@ -1,7 +1,7 @@
1
1
  import { Layer, calculateStrength } from '../core/memory.js';
2
2
  import { jaccardMinShared, overlapPartners } from './overlap-index.js';
3
3
  import { isQuarantineScope } from '../trust/quarantine.js';
4
- import { isPersonalScope } from '../store/recall-scope.js';
4
+ import { isPersonalScope } from '../core/recall-scope.js';
5
5
  import { DECAY_THRESHOLD } from './decay.js';
6
6
  // Gate contradictions on content overlap, not shared tags (`feedback`/`policy` are too coarse). The Jaccard threshold on stopword-filtered tokens
7
7
  // only applies after a polarity signal, so it filters drive-by topic similarity, not semantic drift.
@@ -65,7 +65,7 @@ function recalledTogether(a, b) {
65
65
  // A personal row pairs only inside its own scope; any other pair shows its id to someone else.
66
66
  if ((isPersonalScope(a.scope) || isPersonalScope(b.scope)) && a.scope !== b.scope)
67
67
  return false;
68
- if (a.tenantId !== b.tenantId)
68
+ if (a.tenant_id !== b.tenant_id)
69
69
  return false;
70
70
  const [x, y] = [a.origin_project ?? null, b.origin_project ?? null];
71
71
  return x === y || (x === '' && y !== null) || (y === '' && x !== null);