hippo-memory 1.70.0 → 1.71.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (629) hide show
  1. package/README.md +1 -1
  2. package/dist/agent-memories/claude-code.d.ts +4 -2
  3. package/dist/agent-memories/claude-code.js +14 -5
  4. package/dist/agent-memories/files.js +23 -12
  5. package/dist/agent-memories/markdown.d.ts +1 -3
  6. package/dist/agent-memories/markdown.js +1 -3
  7. package/dist/agent-memories/report.js +2 -1
  8. package/dist/agent-memories/sync.d.ts +4 -2
  9. package/dist/agent-memories/sync.js +10 -5
  10. package/dist/api/assemble.d.ts +7 -44
  11. package/dist/api/assemble.js +2 -22
  12. package/dist/api/audit.d.ts +5 -1
  13. package/dist/api/audit.js +9 -1
  14. package/dist/api/auth.d.ts +13 -22
  15. package/dist/api/auth.js +34 -24
  16. package/dist/api/auto-sleep.js +2 -2
  17. package/dist/api/availability.d.ts +2 -15
  18. package/dist/api/availability.js +2 -15
  19. package/dist/api/context-select.js +3 -4
  20. package/dist/api/context-types.d.ts +10 -35
  21. package/dist/api/context.d.ts +5 -22
  22. package/dist/api/context.js +21 -38
  23. package/dist/api/dormant.d.ts +5 -21
  24. package/dist/api/dormant.js +7 -26
  25. package/dist/api/drill-down.d.ts +7 -46
  26. package/dist/api/drill-down.js +5 -26
  27. package/dist/api/forget.d.ts +5 -24
  28. package/dist/api/forget.js +5 -28
  29. package/dist/api/graph.d.ts +8 -0
  30. package/dist/api/graph.js +7 -0
  31. package/dist/api/index.d.ts +2 -0
  32. package/dist/api/index.js +2 -0
  33. package/dist/api/instruction-detect.js +16 -5
  34. package/dist/api/ledger-db.d.ts +2 -1
  35. package/dist/api/ledger-db.js +5 -3
  36. package/dist/api/memories.d.ts +5 -0
  37. package/dist/api/memories.js +7 -0
  38. package/dist/api/objects.d.ts +9 -0
  39. package/dist/api/objects.js +11 -0
  40. package/dist/api/on-store.js +5 -3
  41. package/dist/api/predictions.d.ts +9 -0
  42. package/dist/api/predictions.js +18 -0
  43. package/dist/api/promote.d.ts +13 -17
  44. package/dist/api/promote.js +11 -19
  45. package/dist/api/prompt-hook.d.ts +4 -4
  46. package/dist/api/prompt-hook.js +10 -9
  47. package/dist/api/recall-cli.d.ts +55 -0
  48. package/dist/api/recall-cli.js +94 -0
  49. package/dist/api/recall-core.js +14 -6
  50. package/dist/api/recall-finish.d.ts +53 -0
  51. package/dist/api/recall-finish.js +30 -0
  52. package/dist/api/recall-history.d.ts +17 -84
  53. package/dist/api/recall-history.js +15 -88
  54. package/dist/api/recall-pipeline.d.ts +2 -3
  55. package/dist/api/recall-pipeline.js +16 -9
  56. package/dist/api/recall-types.d.ts +64 -304
  57. package/dist/api/recall.d.ts +5 -33
  58. package/dist/api/recall.js +59 -60
  59. package/dist/api/refine.d.ts +7 -0
  60. package/dist/api/refine.js +10 -0
  61. package/dist/api/remember-local.d.ts +57 -0
  62. package/dist/api/remember-local.js +90 -0
  63. package/dist/api/remember.d.ts +18 -1
  64. package/dist/api/remember.js +13 -1
  65. package/dist/api/sleep-run.d.ts +1 -3
  66. package/dist/api/sleep-run.js +17 -21
  67. package/dist/api/sleep.d.ts +9 -28
  68. package/dist/api/tokens.d.ts +3 -10
  69. package/dist/api/tokens.js +3 -10
  70. package/dist/api/types.d.ts +6 -29
  71. package/dist/api/types.js +4 -22
  72. package/dist/capture/command.d.ts +4 -12
  73. package/dist/capture/command.js +6 -22
  74. package/dist/capture/compact.d.ts +4 -15
  75. package/dist/capture/compact.js +16 -25
  76. package/dist/capture/compaction-record.js +101 -69
  77. package/dist/capture/compaction-spool.d.ts +1 -1
  78. package/dist/capture/compaction-spool.js +1 -1
  79. package/dist/capture/session-digest.d.ts +1 -1
  80. package/dist/capture/session-digest.js +13 -7
  81. package/dist/capture/transcript.d.ts +2 -10
  82. package/dist/capture/transcript.js +4 -18
  83. package/dist/cli/api-context.d.ts +3 -0
  84. package/dist/cli/api-context.js +6 -0
  85. package/dist/cli/audit-prune.d.ts +6 -39
  86. package/dist/cli/audit-prune.js +6 -39
  87. package/dist/cli/audit.d.ts +1 -1
  88. package/dist/cli/audit.js +33 -34
  89. package/dist/cli/auth.d.ts +2 -2
  90. package/dist/cli/auth.js +57 -39
  91. package/dist/cli/briefs.d.ts +4 -4
  92. package/dist/cli/briefs.js +18 -22
  93. package/dist/cli/card.d.ts +2 -2
  94. package/dist/cli/card.js +31 -32
  95. package/dist/cli/client.d.ts +7 -27
  96. package/dist/cli/client.js +24 -43
  97. package/dist/cli/compact-resume-payload.js +3 -2
  98. package/dist/cli/context.d.ts +1 -2
  99. package/dist/cli/context.js +12 -8
  100. package/dist/cli/continuity.d.ts +6 -6
  101. package/dist/cli/continuity.js +62 -64
  102. package/dist/cli/correction-latency.d.ts +2 -14
  103. package/dist/cli/correction-latency.js +2 -14
  104. package/dist/cli/curate.d.ts +13 -17
  105. package/dist/cli/curate.js +68 -92
  106. package/dist/cli/dag.d.ts +4 -4
  107. package/dist/cli/dag.js +33 -27
  108. package/dist/cli/decisions.d.ts +4 -4
  109. package/dist/cli/decisions.js +33 -47
  110. package/dist/cli/eval.js +15 -13
  111. package/dist/cli/exit.d.ts +6 -0
  112. package/dist/cli/exit.js +11 -0
  113. package/dist/cli/explain.d.ts +1 -2
  114. package/dist/cli/explain.js +6 -4
  115. package/dist/cli/flag-values.d.ts +6 -1
  116. package/dist/cli/flag-values.js +27 -10
  117. package/dist/cli/flags.d.ts +1 -0
  118. package/dist/cli/flags.js +1 -1
  119. package/dist/cli/github.d.ts +14 -0
  120. package/dist/{connectors/github/cli-impl.js → cli/github.js} +43 -71
  121. package/dist/cli/goals.d.ts +2 -2
  122. package/dist/cli/goals.js +46 -50
  123. package/dist/cli/hook-runtime.d.ts +9 -27
  124. package/dist/cli/hook-runtime.js +15 -31
  125. package/dist/cli/init.d.ts +2 -2
  126. package/dist/cli/init.js +6 -12
  127. package/dist/cli/install-steps.js +3 -12
  128. package/dist/cli/last-sleep.d.ts +2 -1
  129. package/dist/cli/last-sleep.js +3 -0
  130. package/dist/cli/maintenance.d.ts +4 -4
  131. package/dist/cli/maintenance.js +14 -19
  132. package/dist/cli/object-verbs.js +4 -3
  133. package/dist/cli/owner-validation.d.ts +5 -28
  134. package/dist/cli/owner-validation.js +5 -28
  135. package/dist/cli/playbooks.d.ts +4 -4
  136. package/dist/cli/playbooks.js +23 -28
  137. package/dist/cli/print.d.ts +2 -5
  138. package/dist/cli/print.js +1 -4
  139. package/dist/cli/projects.d.ts +2 -2
  140. package/dist/cli/projects.js +1 -3
  141. package/dist/cli/provenance-coverage.d.ts +2 -6
  142. package/dist/cli/provenance-coverage.js +2 -6
  143. package/dist/cli/quality-repair-once.js +2 -2
  144. package/dist/cli/recall.d.ts +2 -4
  145. package/dist/cli/recall.js +55 -131
  146. package/dist/cli/refine-llm.d.ts +5 -31
  147. package/dist/cli/refine-llm.js +9 -36
  148. package/dist/cli/remember.d.ts +3 -3
  149. package/dist/cli/remember.js +122 -180
  150. package/dist/cli/scheduler.d.ts +2 -17
  151. package/dist/cli/scheduler.js +12 -18
  152. package/dist/cli/serve.js +21 -12
  153. package/dist/cli/session-hooks.d.ts +10 -18
  154. package/dist/cli/session-hooks.js +112 -113
  155. package/dist/cli/setup.d.ts +4 -4
  156. package/dist/cli/setup.js +19 -21
  157. package/dist/cli/shared.d.ts +9 -23
  158. package/dist/cli/shared.js +9 -32
  159. package/dist/cli/slack.d.ts +2 -2
  160. package/dist/cli/slack.js +19 -23
  161. package/dist/cli/sleep.d.ts +3 -2
  162. package/dist/cli/sleep.js +15 -16
  163. package/dist/cli/status.d.ts +9 -12
  164. package/dist/cli/status.js +55 -98
  165. package/dist/cli/stdin.d.ts +4 -6
  166. package/dist/cli/stdin.js +2 -3
  167. package/dist/cli/transfer.d.ts +9 -9
  168. package/dist/cli/transfer.js +66 -89
  169. package/dist/cli/usage.js +11 -5
  170. package/dist/cli.d.ts +66 -448
  171. package/dist/cli.js +87 -263
  172. package/dist/connectors/github/backfill.d.ts +5 -25
  173. package/dist/connectors/github/backfill.js +14 -49
  174. package/dist/connectors/github/deletion.d.ts +4 -18
  175. package/dist/connectors/github/deletion.js +2 -15
  176. package/dist/connectors/github/dlq.d.ts +8 -33
  177. package/dist/connectors/github/dlq.js +12 -29
  178. package/dist/connectors/github/ingest.d.ts +2 -6
  179. package/dist/connectors/github/ingest.js +4 -10
  180. package/dist/connectors/github/octokit-client.d.ts +4 -16
  181. package/dist/connectors/github/octokit-client.js +27 -24
  182. package/dist/connectors/github/ratelimit.d.ts +3 -14
  183. package/dist/connectors/github/ratelimit.js +3 -14
  184. package/dist/connectors/github/scope.d.ts +3 -5
  185. package/dist/connectors/github/scope.js +3 -5
  186. package/dist/connectors/github/signature.d.ts +4 -26
  187. package/dist/connectors/github/signature.js +4 -26
  188. package/dist/connectors/github/tenant-routing.d.ts +2 -24
  189. package/dist/connectors/github/tenant-routing.js +4 -26
  190. package/dist/connectors/github/transform.js +2 -16
  191. package/dist/connectors/github/types.d.ts +3 -15
  192. package/dist/connectors/github/types.js +2 -9
  193. package/dist/connectors/github/webhook.d.ts +2 -16
  194. package/dist/connectors/github/webhook.js +6 -22
  195. package/dist/connectors/slack/backfill.d.ts +4 -17
  196. package/dist/connectors/slack/backfill.js +4 -13
  197. package/dist/connectors/slack/dlq.d.ts +2 -19
  198. package/dist/connectors/slack/dlq.js +2 -19
  199. package/dist/connectors/slack/ingest.d.ts +2 -3
  200. package/dist/connectors/slack/ingest.js +2 -3
  201. package/dist/connectors/slack/scope.d.ts +2 -8
  202. package/dist/connectors/slack/scope.js +2 -8
  203. package/dist/connectors/slack/signature.d.ts +1 -6
  204. package/dist/connectors/slack/tenant-routing.d.ts +2 -19
  205. package/dist/connectors/slack/tenant-routing.js +2 -21
  206. package/dist/connectors/slack/transform.d.ts +2 -18
  207. package/dist/connectors/slack/transform.js +2 -18
  208. package/dist/connectors/slack/types.d.ts +3 -9
  209. package/dist/connectors/slack/types.js +2 -4
  210. package/dist/connectors/slack/web-client.js +33 -27
  211. package/dist/connectors/slack/webhook.d.ts +2 -19
  212. package/dist/connectors/slack/webhook.js +5 -26
  213. package/dist/connectors/slack/workspaces.d.ts +4 -24
  214. package/dist/connectors/slack/workspaces.js +4 -24
  215. package/dist/consolidate/conflicts.js +6 -14
  216. package/dist/consolidate/dag-summary.d.ts +8 -0
  217. package/dist/consolidate/dag-summary.js +41 -0
  218. package/dist/consolidate/dag.d.ts +5 -28
  219. package/dist/consolidate/dag.js +14 -75
  220. package/dist/consolidate/decay.js +7 -19
  221. package/dist/consolidate/dedupe.d.ts +6 -52
  222. package/dist/consolidate/dedupe.js +13 -71
  223. package/dist/consolidate/flush-units.d.ts +3 -4
  224. package/dist/consolidate/flush-units.js +3 -3
  225. package/dist/consolidate/half-life-migration.d.ts +3 -26
  226. package/dist/consolidate/half-life-migration.js +11 -28
  227. package/dist/consolidate/llm-passes.js +4 -21
  228. package/dist/consolidate/memory-value-weights.d.ts +2 -13
  229. package/dist/consolidate/memory-value-weights.js +2 -13
  230. package/dist/consolidate/memory-value.d.ts +11 -84
  231. package/dist/consolidate/memory-value.js +16 -104
  232. package/dist/consolidate/merge.js +10 -31
  233. package/dist/consolidate/merged-row.js +2 -1
  234. package/dist/consolidate/physics-pass.js +1 -3
  235. package/dist/consolidate/replay.d.ts +6 -38
  236. package/dist/consolidate/replay.js +14 -52
  237. package/dist/consolidate/run.js +1 -1
  238. package/dist/consolidate/sleep.d.ts +1 -8
  239. package/dist/consolidate/sleep.js +5 -17
  240. package/dist/consolidate/trace.d.ts +3 -18
  241. package/dist/consolidate/trace.js +3 -18
  242. package/dist/consolidate/traces.js +6 -22
  243. package/dist/core/ablation.d.ts +4 -91
  244. package/dist/core/ablation.js +4 -91
  245. package/dist/core/ambient.d.ts +1 -8
  246. package/dist/core/ambient.js +1 -8
  247. package/dist/core/capture-contract.d.ts +4 -2
  248. package/dist/core/capture-contract.js +4 -2
  249. package/dist/core/card.d.ts +4 -1
  250. package/dist/core/card.js +8 -0
  251. package/dist/core/compare.d.ts +11 -67
  252. package/dist/core/compare.js +9 -63
  253. package/dist/core/config.d.ts +10 -24
  254. package/dist/core/config.js +13 -14
  255. package/dist/core/handoff.d.ts +1 -7
  256. package/dist/core/handoff.js +1 -7
  257. package/dist/core/memory-quality.js +1 -1
  258. package/dist/core/memory.d.ts +41 -164
  259. package/dist/core/memory.js +51 -221
  260. package/dist/core/package-root.d.ts +3 -0
  261. package/dist/core/package-root.js +5 -0
  262. package/dist/core/physics-config.d.ts +1 -4
  263. package/dist/core/physics-config.js +3 -8
  264. package/dist/core/physics.d.ts +15 -61
  265. package/dist/core/physics.js +59 -122
  266. package/dist/core/project-identity.d.ts +17 -58
  267. package/dist/core/project-identity.js +17 -38
  268. package/dist/core/project-remote.js +13 -2
  269. package/dist/core/raw-append-only.d.ts +5 -0
  270. package/dist/core/raw-append-only.js +7 -0
  271. package/dist/core/salience.d.ts +1 -7
  272. package/dist/core/salience.js +1 -7
  273. package/dist/dashboard/dashboard-actions.js +2 -2
  274. package/dist/dashboard/dashboard-snapshot.d.ts +2 -1
  275. package/dist/dashboard/dashboard-snapshot.js +11 -2
  276. package/dist/dashboard/dashboard-types.d.ts +2 -1
  277. package/dist/dashboard/dashboard.d.ts +1 -0
  278. package/dist/dashboard/dashboard.js +50 -4
  279. package/dist/db/busy.d.ts +1 -1
  280. package/dist/db/busy.js +17 -8
  281. package/dist/db/connect.d.ts +1 -0
  282. package/dist/db/connect.js +3 -3
  283. package/dist/db/migrate.js +3 -3
  284. package/dist/db/migrations/types.d.ts +2 -5
  285. package/dist/db/migrations/v14.js +2 -3
  286. package/dist/db/migrations/v15.js +2 -8
  287. package/dist/db/migrations/v16.js +2 -3
  288. package/dist/db/migrations/v17.js +2 -3
  289. package/dist/db/migrations/v19.js +2 -5
  290. package/dist/db/migrations/v20.js +2 -7
  291. package/dist/db/migrations/v22.js +4 -17
  292. package/dist/db/migrations/v23.js +3 -14
  293. package/dist/db/migrations/v24.js +2 -4
  294. package/dist/db/migrations/v25.js +3 -8
  295. package/dist/db/migrations/v26.js +2 -13
  296. package/dist/db/migrations/v27.js +3 -11
  297. package/dist/db/migrations/v28.js +2 -14
  298. package/dist/db/migrations/v29.js +4 -18
  299. package/dist/db/migrations/v30.js +4 -16
  300. package/dist/db/migrations/v31.js +2 -15
  301. package/dist/db/migrations/v32.js +4 -22
  302. package/dist/db/migrations/v33.js +2 -15
  303. package/dist/db/migrations/v34.js +2 -11
  304. package/dist/db/migrations/v35.js +2 -11
  305. package/dist/db/migrations/v36.js +2 -11
  306. package/dist/db/migrations/v37.js +8 -33
  307. package/dist/db/migrations/v38.js +5 -38
  308. package/dist/db/migrations/v39.js +9 -20
  309. package/dist/db/migrations/v40.js +2 -9
  310. package/dist/db/migrations/v41.js +2 -24
  311. package/dist/db/migrations/v43.js +1 -1
  312. package/dist/db/migrations/v44.js +2 -8
  313. package/dist/db/migrations/v45.js +2 -7
  314. package/dist/db/migrations/v47.js +2 -3
  315. package/dist/db/migrations/v51.js +1 -1
  316. package/dist/db/open.d.ts +2 -0
  317. package/dist/db/open.js +17 -1
  318. package/dist/db/physics-state.d.ts +6 -22
  319. package/dist/db/physics-state.js +25 -36
  320. package/dist/db/raw-archive-mirror-cleanup.d.ts +2 -17
  321. package/dist/db/raw-archive-mirror-cleanup.js +2 -17
  322. package/dist/db/vector-store.d.ts +2 -0
  323. package/dist/db/vector-store.js +8 -1
  324. package/dist/doctor.js +74 -19
  325. package/dist/entry/session-text.js +2 -1
  326. package/dist/eval/eval-stats.d.ts +15 -53
  327. package/dist/eval/eval-stats.js +12 -42
  328. package/dist/eval/eval-suite.d.ts +2 -13
  329. package/dist/eval/eval-suite.js +74 -34
  330. package/dist/eval/eval.d.ts +6 -24
  331. package/dist/eval/eval.js +7 -34
  332. package/dist/eval/judgment.d.ts +0 -3
  333. package/dist/eval/judgment.js +19 -11
  334. package/dist/extensions/openclaw-plugin/index.js +1 -1
  335. package/dist/graph/extract.d.ts +5 -27
  336. package/dist/graph/extract.js +7 -33
  337. package/dist/graph/recall.d.ts +7 -20
  338. package/dist/graph/recall.js +14 -76
  339. package/dist/graph/stream.d.ts +7 -39
  340. package/dist/graph/stream.js +11 -34
  341. package/dist/graph/view.d.ts +9 -35
  342. package/dist/graph/view.js +11 -39
  343. package/dist/hooks/codex-wrapper.js +2 -2
  344. package/dist/hooks/copilot.js +2 -1
  345. package/dist/hooks/hook-blocks.d.ts +6 -2
  346. package/dist/hooks/hook-blocks.js +37 -124
  347. package/dist/hooks/json-hooks.d.ts +4 -36
  348. package/dist/hooks/json-hooks.js +18 -57
  349. package/dist/hooks/opencode.d.ts +0 -38
  350. package/dist/hooks/opencode.js +9 -76
  351. package/dist/hooks/shared.d.ts +8 -17
  352. package/dist/hooks/shared.js +29 -20
  353. package/dist/importers/core.d.ts +12 -37
  354. package/dist/importers/core.js +9 -27
  355. package/dist/importers/markdown-parse.d.ts +8 -22
  356. package/dist/importers/markdown-parse.js +8 -25
  357. package/dist/importers/markdown.js +3 -12
  358. package/dist/importers/sources.js +7 -35
  359. package/dist/importers/vault.d.ts +2 -8
  360. package/dist/importers/vault.js +25 -81
  361. package/dist/index.d.ts +6 -2
  362. package/dist/index.js +6 -2
  363. package/dist/learn/autolearn.d.ts +14 -41
  364. package/dist/learn/autolearn.js +14 -41
  365. package/dist/learn/extract.js +2 -4
  366. package/dist/learn/forward-claim-detector.d.ts +6 -30
  367. package/dist/learn/forward-claim-detector.js +14 -66
  368. package/dist/learn/invalidation.d.ts +6 -18
  369. package/dist/learn/invalidation.js +9 -26
  370. package/dist/mcp/admin-tools.js +3 -5
  371. package/dist/mcp/memory-tools.js +4 -9
  372. package/dist/mcp/protocol.d.ts +8 -26
  373. package/dist/mcp/protocol.js +3 -6
  374. package/dist/mcp/recall-tools.js +3 -3
  375. package/dist/mcp/request.d.ts +3 -11
  376. package/dist/mcp/request.js +10 -26
  377. package/dist/mcp/server.d.ts +3 -9
  378. package/dist/mcp/server.js +5 -16
  379. package/dist/mcp/session-state.d.ts +1 -1
  380. package/dist/mcp/session-state.js +5 -11
  381. package/dist/mcp/stdio.d.ts +2 -6
  382. package/dist/mcp/stdio.js +48 -12
  383. package/dist/mcp/tools.js +5 -3
  384. package/dist/objects/customer-notes.d.ts +7 -42
  385. package/dist/objects/customer-notes.js +7 -48
  386. package/dist/objects/decisions.d.ts +12 -50
  387. package/dist/objects/decisions.js +15 -53
  388. package/dist/objects/incidents.d.ts +7 -38
  389. package/dist/objects/incidents.js +7 -41
  390. package/dist/objects/policies.d.ts +11 -89
  391. package/dist/objects/policies.js +11 -98
  392. package/dist/objects/processes.d.ts +7 -52
  393. package/dist/objects/processes.js +7 -61
  394. package/dist/objects/project-briefs.d.ts +11 -55
  395. package/dist/objects/project-briefs.js +14 -75
  396. package/dist/objects/skills.d.ts +7 -42
  397. package/dist/objects/skills.js +8 -54
  398. package/dist/postinstall.js +6 -19
  399. package/dist/predictions/planning-fallacy.d.ts +11 -34
  400. package/dist/rerankers/clef.js +3 -31
  401. package/dist/rerankers/cross-encoder.js +4 -6
  402. package/dist/rerankers/jev.js +9 -6
  403. package/dist/rerankers/llm.d.ts +2 -11
  404. package/dist/rerankers/llm.js +14 -14
  405. package/dist/rerankers/outage-warning.d.ts +2 -1
  406. package/dist/rerankers/outage-warning.js +2 -1
  407. package/dist/rerankers/remote.d.ts +1 -0
  408. package/dist/rerankers/remote.js +2 -0
  409. package/dist/rerankers/types.d.ts +2 -14
  410. package/dist/search/boosts.d.ts +0 -2
  411. package/dist/search/boosts.js +2 -2
  412. package/dist/search/goal-boost.d.ts +23 -0
  413. package/dist/search/goal-boost.js +90 -0
  414. package/dist/search/hybrid.d.ts +2 -0
  415. package/dist/search/multihop.js +2 -3
  416. package/dist/search/path-context.d.ts +5 -18
  417. package/dist/search/path-context.js +5 -18
  418. package/dist/search/physics-search.js +11 -8
  419. package/dist/search/rrf.d.ts +7 -35
  420. package/dist/search/rrf.js +5 -30
  421. package/dist/search/vector.d.ts +7 -0
  422. package/dist/search/vector.js +35 -5
  423. package/dist/server/auth.d.ts +9 -28
  424. package/dist/server/auth.js +32 -25
  425. package/dist/server/boot.d.ts +2 -21
  426. package/dist/server/boot.js +63 -96
  427. package/dist/server/client-ip.d.ts +3 -19
  428. package/dist/server/client-ip.js +5 -28
  429. package/dist/server/defaults.d.ts +3 -0
  430. package/dist/server/defaults.js +4 -0
  431. package/dist/server/key-check-bounds.d.ts +2 -1
  432. package/dist/server/lifecycle.d.ts +5 -4
  433. package/dist/server/lifecycle.js +19 -4
  434. package/dist/server/mcp-http.js +10 -44
  435. package/dist/server/rate-limit.d.ts +5 -18
  436. package/dist/server/rate-limit.js +4 -13
  437. package/dist/server/request.d.ts +4 -8
  438. package/dist/server/request.js +9 -17
  439. package/dist/server/route-table.js +42 -49
  440. package/dist/server/routes/admin.js +22 -28
  441. package/dist/server/routes/customer-notes.js +7 -12
  442. package/dist/server/routes/decisions.js +10 -17
  443. package/dist/server/routes/incidents.js +12 -20
  444. package/dist/server/routes/memories.js +12 -32
  445. package/dist/server/routes/object-routes.d.ts +0 -5
  446. package/dist/server/routes/object-routes.js +7 -15
  447. package/dist/server/routes/policies.js +10 -18
  448. package/dist/server/routes/predictions.js +13 -25
  449. package/dist/server/routes/processes.js +16 -26
  450. package/dist/server/routes/project-briefs.js +9 -16
  451. package/dist/server/routes/recall.js +10 -35
  452. package/dist/server/routes/skills.js +8 -18
  453. package/dist/server/server-detect.d.ts +9 -53
  454. package/dist/server/server-detect.js +24 -90
  455. package/dist/server/sleep-offload.js +4 -1
  456. package/dist/server/types.d.ts +12 -10
  457. package/dist/server/validation.d.ts +3 -1
  458. package/dist/server/validation.js +10 -23
  459. package/dist/server.d.ts +2 -2
  460. package/dist/server.js +3 -2
  461. package/dist/sharing/global-store.d.ts +19 -0
  462. package/dist/sharing/global-store.js +75 -0
  463. package/dist/sharing/global-sync.d.ts +6 -0
  464. package/dist/sharing/global-sync.js +80 -0
  465. package/dist/sharing/project-merge.d.ts +4 -5
  466. package/dist/sharing/project-merge.js +9 -7
  467. package/dist/sharing/scope.d.ts +4 -11
  468. package/dist/sharing/scope.js +4 -11
  469. package/dist/sharing/search-both.d.ts +60 -0
  470. package/dist/sharing/search-both.js +138 -0
  471. package/dist/sharing/share.d.ts +38 -0
  472. package/dist/sharing/share.js +226 -0
  473. package/dist/store/ambient.js +4 -9
  474. package/dist/store/audit-event.d.ts +4 -12
  475. package/dist/store/audit-event.js +4 -12
  476. package/dist/store/audit.d.ts +2 -5
  477. package/dist/store/audit.js +4 -12
  478. package/dist/store/auth.d.ts +6 -6
  479. package/dist/store/auth.js +10 -9
  480. package/dist/store/candidates.d.ts +20 -3
  481. package/dist/store/candidates.js +77 -48
  482. package/dist/store/card-detail.d.ts +2 -1
  483. package/dist/store/card-detail.js +2 -1
  484. package/dist/store/cards.d.ts +14 -9
  485. package/dist/store/cards.js +72 -126
  486. package/dist/store/conflicts.d.ts +4 -21
  487. package/dist/store/conflicts.js +71 -150
  488. package/dist/store/connectors/github.d.ts +10 -10
  489. package/dist/store/connectors/github.js +10 -10
  490. package/dist/store/dashboard-reads.js +4 -8
  491. package/dist/store/delete-and-batch.d.ts +11 -31
  492. package/dist/store/delete-and-batch.js +48 -64
  493. package/dist/store/delivery-recorder.d.ts +8 -4
  494. package/dist/store/delivery-recorder.js +25 -15
  495. package/dist/store/diagnostics.js +6 -13
  496. package/dist/store/dormant.d.ts +7 -29
  497. package/dist/store/dormant.js +15 -56
  498. package/dist/store/embeddings/index.d.ts +11 -80
  499. package/dist/store/embeddings/index.js +71 -207
  500. package/dist/store/embeddings/local.js +15 -32
  501. package/dist/store/embeddings/provider.d.ts +16 -53
  502. package/dist/store/embeddings/provider.js +41 -69
  503. package/dist/store/entry-reads.d.ts +21 -57
  504. package/dist/store/entry-reads.js +65 -126
  505. package/dist/store/entry-row.d.ts +6 -35
  506. package/dist/store/entry-row.js +9 -37
  507. package/dist/store/entry-writes.d.ts +10 -16
  508. package/dist/store/entry-writes.js +17 -35
  509. package/dist/store/goals.d.ts +3 -40
  510. package/dist/store/goals.js +21 -160
  511. package/dist/store/graph-queue.d.ts +6 -22
  512. package/dist/store/graph-queue.js +14 -45
  513. package/dist/store/graph-reads.d.ts +11 -35
  514. package/dist/store/graph-reads.js +20 -58
  515. package/dist/store/graph-rows.d.ts +3 -6
  516. package/dist/store/graph-rows.js +6 -9
  517. package/dist/store/graph-view-rows.d.ts +2 -1
  518. package/dist/store/graph-view-rows.js +2 -1
  519. package/dist/store/graph-writes.d.ts +6 -31
  520. package/dist/store/graph-writes.js +13 -37
  521. package/dist/store/half-life.d.ts +2 -1
  522. package/dist/store/half-life.js +14 -16
  523. package/dist/store/handoffs.d.ts +5 -11
  524. package/dist/store/handoffs.js +16 -34
  525. package/dist/store/index-and-stats.d.ts +6 -19
  526. package/dist/store/index-and-stats.js +34 -82
  527. package/dist/store/markdown.d.ts +2 -6
  528. package/dist/store/markdown.js +21 -20
  529. package/dist/store/mirrors.d.ts +2 -6
  530. package/dist/store/mirrors.js +14 -23
  531. package/dist/store/open.js +6 -13
  532. package/dist/store/planning-fallacy-evidence.d.ts +2 -30
  533. package/dist/store/planning-fallacy-evidence.js +8 -37
  534. package/dist/store/port.d.ts +82 -79
  535. package/dist/store/predictions.d.ts +11 -51
  536. package/dist/store/predictions.js +38 -119
  537. package/dist/{cli → store}/quality-repair.js +15 -31
  538. package/dist/store/raw-archive.d.ts +4 -16
  539. package/dist/store/raw-archive.js +14 -29
  540. package/dist/store/recall-scope.d.ts +19 -79
  541. package/dist/store/recall-scope.js +21 -82
  542. package/dist/store/recall-trace.d.ts +10 -77
  543. package/dist/store/recall-trace.js +19 -95
  544. package/dist/store/rejected-values.js +7 -19
  545. package/dist/store/rejection.d.ts +12 -58
  546. package/dist/store/rejection.js +13 -65
  547. package/dist/store/report-reads.d.ts +6 -0
  548. package/dist/store/report-reads.js +29 -0
  549. package/dist/store/rows.d.ts +9 -19
  550. package/dist/store/rows.js +36 -34
  551. package/dist/store/rule-sql.d.ts +5 -0
  552. package/dist/store/rule-sql.js +37 -0
  553. package/dist/store/search-rows.d.ts +7 -38
  554. package/dist/store/search-rows.js +14 -50
  555. package/dist/store/sessions.d.ts +10 -47
  556. package/dist/store/sessions.js +17 -73
  557. package/dist/store/sqlite/connector-events-group.js +2 -2
  558. package/dist/store/sqlite/entry-writes-group.js +2 -2
  559. package/dist/store/sqlite/error-codec.js +4 -2
  560. package/dist/store/sqlite/executor.d.ts +2 -1
  561. package/dist/store/sqlite/executor.js +2 -1
  562. package/dist/store/sqlite/local.d.ts +3 -3
  563. package/dist/store/sqlite/local.js +1 -0
  564. package/dist/store/sqlite/object-rows.js +6 -3
  565. package/dist/store/sqlite/objects-group.js +4 -2
  566. package/dist/store/sqlite/quarantine-group.js +2 -2
  567. package/dist/store/sqlite/store.d.ts +1 -4
  568. package/dist/store/sqlite/store.js +2 -3
  569. package/dist/store/sqlite/vector-reads-group.js +2 -2
  570. package/dist/store/sqlite/worker-jobs.js +1 -1
  571. package/dist/store/sqlite/worker-ops.d.ts +13 -2
  572. package/dist/store/sqlite/worker-ops.js +13 -2
  573. package/dist/store/sqlite/worker-store.js +5 -2
  574. package/dist/store/summaries.d.ts +10 -62
  575. package/dist/store/summaries.js +34 -146
  576. package/dist/store/summary-dirty.js +1 -1
  577. package/dist/store/tenant-lookup.d.ts +6 -1
  578. package/dist/store/tenant-lookup.js +7 -0
  579. package/dist/store/tenant.d.ts +2 -16
  580. package/dist/store/tenant.js +4 -19
  581. package/dist/store/token-ledger.d.ts +13 -43
  582. package/dist/store/token-ledger.js +19 -50
  583. package/dist/store/usage-reports.js +5 -13
  584. package/dist/store/vector-index.d.ts +46 -0
  585. package/dist/store/vector-index.js +170 -0
  586. package/dist/store/working-memory.d.ts +6 -25
  587. package/dist/store/working-memory.js +18 -52
  588. package/dist/store/yaml.d.ts +1 -5
  589. package/dist/store/yaml.js +2 -6
  590. package/dist/support-bundle.js +7 -5
  591. package/dist/trust/reject-flow.js +1 -3
  592. package/dist/util/anthropic-messages.js +14 -2
  593. package/dist/util/atomic-write.d.ts +2 -1
  594. package/dist/util/atomic-write.js +35 -4
  595. package/dist/util/capped-json.d.ts +6 -0
  596. package/dist/util/capped-json.js +46 -0
  597. package/dist/util/crash-handlers.d.ts +8 -1
  598. package/dist/util/crash-handlers.js +52 -10
  599. package/dist/util/env.d.ts +13 -6
  600. package/dist/util/env.js +14 -7
  601. package/dist/util/home-path.d.ts +2 -1
  602. package/dist/util/home-path.js +4 -2
  603. package/dist/util/http-retry.d.ts +3 -1
  604. package/dist/util/http-retry.js +26 -5
  605. package/dist/util/log.d.ts +3 -2
  606. package/dist/util/log.js +25 -9
  607. package/dist/util/request-scope.d.ts +2 -1
  608. package/dist/util/request-scope.js +2 -1
  609. package/dist/util/secret-detect.d.ts +5 -30
  610. package/dist/util/secret-detect.js +13 -39
  611. package/dist/util/stored-json.d.ts +1 -1
  612. package/dist/util/stored-json.js +1 -1
  613. package/dist/util/token-text.d.ts +1 -4
  614. package/dist/util/token-text.js +1 -4
  615. package/dist/util/transcript-tail.d.ts +2 -0
  616. package/dist/util/transcript-tail.js +24 -23
  617. package/dist/util/version.d.ts +5 -20
  618. package/dist/util/version.js +5 -20
  619. package/extensions/openclaw-plugin/index.ts +1 -1
  620. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  621. package/extensions/openclaw-plugin/package.json +1 -1
  622. package/openclaw.plugin.json +1 -1
  623. package/package.json +1 -1
  624. package/dist/connectors/github/cli-impl.d.ts +0 -25
  625. package/dist/sharing/shared.d.ts +0 -187
  626. package/dist/sharing/shared.js +0 -563
  627. package/dist/store/vector-writes.d.ts +0 -13
  628. package/dist/store/vector-writes.js +0 -89
  629. /package/dist/{cli → store}/quality-repair.d.ts +0 -0
@@ -1,21 +1,14 @@
1
1
  import type { TokenSummary, TokenSurface } from '../store/token-ledger.js';
2
2
  import type { FailureSummary } from '../store/failure-log.js';
3
3
  import type { Context } from './types.js';
4
- /**
5
- * Record memory text handed to an agent in the token ledger.
6
- * Best-effort: never throws, because a ledger failure must not fail the
7
- * recall or context call that produced the text.
8
- */
4
+ /** Records memory text handed to an agent in the token ledger. Best-effort: never throws, since a ledger failure must not fail the recall or context call. */
9
5
  export declare function recordTokens(ctx: Context, surface: TokenSurface, use: {
10
6
  items: number;
11
7
  tokens: number;
12
8
  sessionId?: string | null;
13
9
  }): Promise<void>;
14
- /**
15
- * Token ledger totals for the tenant over the last `days` days (default 30):
16
- * tokens sent, skipped as unchanged and re-read by later model calls, per
17
- * surface, with session counts and mean tokens per session.
18
- */
10
+ /** Token ledger totals for the tenant over the last `days` days (default 30): tokens sent, skipped as unchanged and re-read,
11
+ * per surface, with session counts and mean tokens per session. */
19
12
  export declare function tokenSummary(ctx: Context, opts?: {
20
13
  days?: number;
21
14
  }): TokenSummary;
@@ -4,11 +4,7 @@ import { storeFor } from '../store/index.js';
4
4
  import { failureLogSummary, tokenUseSummary } from '../store/usage-reports.js';
5
5
  import { errorMessage, log } from '../util/log.js';
6
6
  import { DAY_MS } from '../util/time.js';
7
- /**
8
- * Record memory text handed to an agent in the token ledger.
9
- * Best-effort: never throws, because a ledger failure must not fail the
10
- * recall or context call that produced the text.
11
- */
7
+ /** Records memory text handed to an agent in the token ledger. Best-effort: never throws, since a ledger failure must not fail the recall or context call. */
12
8
  export async function recordTokens(ctx, surface, use) {
13
9
  try {
14
10
  await storeFor(ctx).recordTokens({
@@ -25,11 +21,8 @@ export async function recordTokens(ctx, surface, use) {
25
21
  log.warnThenDebug('api-token-ledger', `token ledger write failed; the reply is unaffected: ${errorMessage(err)}`);
26
22
  }
27
23
  }
28
- /**
29
- * Token ledger totals for the tenant over the last `days` days (default 30):
30
- * tokens sent, skipped as unchanged and re-read by later model calls, per
31
- * surface, with session counts and mean tokens per session.
32
- */
24
+ /** Token ledger totals for the tenant over the last `days` days (default 30): tokens sent, skipped as unchanged and re-read,
25
+ * per surface, with session counts and mean tokens per session. */
33
26
  export function tokenSummary(ctx, opts = {}) {
34
27
  return tokenUseSummary(ctx.hippoRoot, ctx.tenantId, reportWindowStart(opts.days));
35
28
  }
@@ -1,12 +1,7 @@
1
1
  import { BadRequestError } from '../core/api-errors.js';
2
2
  import type { HippoStore } from '../store/index.js';
3
- /**
4
- * Actor identity + authorization role for a Context.
5
- *
6
- * Carries the audit-log subject plus a role for /v1/sleep admin gating. Audit
7
- * helpers take the bare `string`, so callers pass `ctx.actor.subject`. Role checks happen at the request
8
- * boundary (e.g. /v1/sleep), except in authCreate and authRevoke (ForbiddenError).
9
- */
3
+ /** Actor identity + role for a Context: the audit-log subject (pass `ctx.actor.subject` to audit helpers) and the role for admin gating.
4
+ * Role checks happen at the request boundary (e.g. /v1/sleep), except in authCreate and authRevoke (ForbiddenError). */
10
5
  export interface Actor {
11
6
  /** 'cli' | 'localhost:cli' | 'api_key:<key_id>' | 'mcp' | 'connector:slack' | 'connector:github' */
12
7
  subject: string;
@@ -34,31 +29,13 @@ export type StoreReply<C extends Context, R> = C extends {
34
29
  readonly hippoRoot: string;
35
30
  readonly store?: undefined;
36
31
  } ? R : R | Promise<R>;
37
- /**
38
- * Helper for building process-local Actor values (admin and host admin),
39
- * used by CLI and CLI-run connector Context constructors so the role
40
- * boilerplate isn't repeated at every site. Bearer-authed callers (HTTP
41
- * /v1/*) construct Actor directly from the api_keys row's role column via
42
- * buildContextWithAuth in src/server.ts.
43
- */
32
+ /** Builds process-local Actor values (admin and host admin) for CLI and CLI-run connector Contexts; Bearer-authed callers build Actor from the api_keys row
33
+ * instead. */
44
34
  export declare function adminActor(subject: string): Actor;
45
35
  /** The per-person key: an unowned key gets its own bucket by key id rather than sharing one. */
46
36
  export declare function ownerOrSubject(actor: Actor): string;
47
- /**
48
- * Thrown by `api.recall` when a caller's options violate a recall contract
49
- * that has been opted into via env. Carries a stable `code` field for HTTP /
50
- * MCP / CLI render paths to discriminate without parsing the message.
51
- *
52
- * Codes:
53
- * - 'fresh_tail_requires_session_id' — `freshTailCount > 0` AND no
54
- * `freshTailSessionId` AND `HIPPO_REQUIRE_SESSION_SCOPED_FRESH_TAIL=1`.
55
- * Default behaviour (env unset) returns tenant-wide rows; the env gate
56
- * is opt-in so multi-session tenants can fail loud instead of silently
57
- * surfacing cross-session rows tagged `isFreshTail=true`.
58
- * - 'invalid_scorer_window' — `opts.scorerWindow` is set to a non-positive,
59
- * non-integer, or non-finite value. 0 would route through FTS/LIKE
60
- * `LIMIT 0` and then an uncapped full-store fallback, so it is validated upfront.
61
- */
37
+ /** Thrown by `api.recall` on a contract violation; the stable `code` lets callers discriminate without parsing the message.
38
+ * 'fresh_tail_requires_session_id' (needs HIPPO_REQUIRE_SESSION_SCOPED_FRESH_TAIL=1) or 'invalid_scorer_window' (0 would hit an uncapped fallback). */
62
39
  export declare class RecallContractError extends BadRequestError {
63
40
  readonly code: 'fresh_tail_requires_session_id' | 'invalid_scorer_window';
64
41
  constructor(code: 'fresh_tail_requires_session_id' | 'invalid_scorer_window', message: string);
package/dist/api/types.js CHANGED
@@ -1,12 +1,7 @@
1
1
  // Request context (caller identity and tenant) shared by every API module, plus the recall contract error.
2
2
  import { BadRequestError } from '../core/api-errors.js';
3
- /**
4
- * Helper for building process-local Actor values (admin and host admin),
5
- * used by CLI and CLI-run connector Context constructors so the role
6
- * boilerplate isn't repeated at every site. Bearer-authed callers (HTTP
7
- * /v1/*) construct Actor directly from the api_keys row's role column via
8
- * buildContextWithAuth in src/server.ts.
9
- */
3
+ /** Builds process-local Actor values (admin and host admin) for CLI and CLI-run connector Contexts; Bearer-authed callers build Actor from the api_keys row
4
+ * instead. */
10
5
  export function adminActor(subject) {
11
6
  return { subject, role: 'admin', hostAdmin: true };
12
7
  }
@@ -14,21 +9,8 @@ export function adminActor(subject) {
14
9
  export function ownerOrSubject(actor) {
15
10
  return actor.owner ?? actor.subject;
16
11
  }
17
- /**
18
- * Thrown by `api.recall` when a caller's options violate a recall contract
19
- * that has been opted into via env. Carries a stable `code` field for HTTP /
20
- * MCP / CLI render paths to discriminate without parsing the message.
21
- *
22
- * Codes:
23
- * - 'fresh_tail_requires_session_id' — `freshTailCount > 0` AND no
24
- * `freshTailSessionId` AND `HIPPO_REQUIRE_SESSION_SCOPED_FRESH_TAIL=1`.
25
- * Default behaviour (env unset) returns tenant-wide rows; the env gate
26
- * is opt-in so multi-session tenants can fail loud instead of silently
27
- * surfacing cross-session rows tagged `isFreshTail=true`.
28
- * - 'invalid_scorer_window' — `opts.scorerWindow` is set to a non-positive,
29
- * non-integer, or non-finite value. 0 would route through FTS/LIKE
30
- * `LIMIT 0` and then an uncapped full-store fallback, so it is validated upfront.
31
- */
12
+ /** Thrown by `api.recall` on a contract violation; the stable `code` lets callers discriminate without parsing the message.
13
+ * 'fresh_tail_requires_session_id' (needs HIPPO_REQUIRE_SESSION_SCOPED_FRESH_TAIL=1) or 'invalid_scorer_window' (0 would hit an uncapped fallback). */
32
14
  export class RecallContractError extends BadRequestError {
33
15
  code;
34
16
  constructor(code, message) {
@@ -12,21 +12,13 @@ export interface CaptureOptions {
12
12
  stdinText?: string;
13
13
  stdinTimedOut?: boolean;
14
14
  sessionTurns?: readonly SessionTurn[];
15
- /**
16
- * Tee stdout/stderr to this log file while capture runs. Mirrors the
17
- * pattern used by `hippo sleep --log-file` so the SessionEnd hook output
18
- * (invisible during TUI teardown) can be surfaced via `hippo last-sleep`
19
- * on the next session start. Appends rather than truncates — `hippo sleep`
20
- * writes the same file first in the SessionEnd sequence.
21
- */
15
+ /** Tee stdout/stderr to this log file while capture runs, so SessionEnd output (lost in TUI teardown) shows via `hippo last-sleep`.
16
+ * Appends, because `hippo sleep` writes the same file first. */
22
17
  logFile?: string;
23
18
  dryRun: boolean;
24
19
  global: boolean;
25
- /**
26
- * Tenant scope for the dedup read in `cmdCaptureCore`. When provided
27
- * AND `global` is false, the dedup check only considers this tenant's
28
- * existing memories. Undefined means host-wide dedup. Ignored when `global: true` (global captures are host-wide).
29
- */
20
+ /** Tenant scope for the dedup read in `cmdCaptureCore`: when set and `global` is false, only this tenant's memories count.
21
+ * Undefined means host-wide dedup; ignored when `global: true`. */
30
22
  tenantId?: string;
31
23
  /** The session's project: rows are stamped with its id, and dedup reads its rows under either name. */
32
24
  originProject?: ProjectRef;
@@ -8,7 +8,7 @@ import { writeEntryMirrors } from '../store/entry-writes.js';
8
8
  import { EVERY_SCOPE, loadTextsHoldingWords } from '../store/candidates.js';
9
9
  import { updateStatsOn } from '../store/index-and-stats.js';
10
10
  import { gatedWrite } from '../trust/gated-write.js';
11
- import { getGlobalRoot, initGlobal } from '../sharing/shared.js';
11
+ import { getGlobalRoot, initGlobal } from '../sharing/global-store.js';
12
12
  import { embedMemory } from '../store/embeddings/index.js';
13
13
  import { maskEmails, redactSecretsStrict } from '../util/secret-detect.js';
14
14
  import { RejectedValueError, checkRejectionGuard } from '../store/rejection.js';
@@ -20,11 +20,7 @@ import { errorMessage, log } from '../util/log.js';
20
20
  import { extractFromTexts } from './extract.js';
21
21
  import { collectSessionTurns, sessionTail, resolveLastSessionTranscript } from './transcript.js';
22
22
  export function cmdCapture(hippoRoot, options) {
23
- // Tee stdout/stderr to a log file when --log-file is set. Used by the
24
- // SessionEnd hook so output (otherwise swallowed by TUI teardown) surfaces
25
- // on the next session start via `hippo last-sleep`. Runs second in the
26
- // SessionEnd sequence after `hippo sleep`, so we APPEND rather than
27
- // truncate — sleep already wrote its own header + body to this file.
23
+ // Tee to a log file for the SessionEnd hook; APPEND, because `hippo sleep` runs first in that sequence and already wrote its header and body.
28
24
  const restoreStdio = options.logFile ? beginLogTee(options.logFile) : null;
29
25
  try {
30
26
  cmdCaptureCore(hippoRoot, options);
@@ -41,12 +37,7 @@ export function cmdCapture(hippoRoot, options) {
41
37
  restoreStdio();
42
38
  }
43
39
  }
44
- /**
45
- * Append-mode tee: writes a banner line then mirrors every stdout/stderr
46
- * chunk to `logFile` until the returned restore function is called.
47
- * Failures to write the log are non-fatal; the real streams still get
48
- * the data.
49
- */
40
+ /** Append-mode tee: mirror every stdout/stderr chunk to `logFile` until the returned restore function is called; a log-write failure is non-fatal. */
50
41
  function beginLogTee(logFile) {
51
42
  if (!writeLogBanner(logFile))
52
43
  return () => { };
@@ -56,16 +47,10 @@ function beginLogTee(logFile) {
56
47
  const wrapWrite = (origWrite) => {
57
48
  const wrapped = (...args) => {
58
49
  tee(args[0]);
59
- // SAFETY: forwarding the exact arguments Node's real overloaded
60
- // `write` received is safe regardless of which overload the call
61
- // site used — Node dispatches on the actual argument shapes at
62
- // runtime, and `StreamWriteArgs` is the union of both overloads'
63
- // parameter lists.
50
+ // SAFETY: forwarding the exact arguments the real overloaded `write` received is safe; `StreamWriteArgs` is the union of both overloads' parameter lists.
64
51
  return origWrite(...args);
65
52
  };
66
- // SAFETY: `wrapped` matches both real `write` overload shapes it's
67
- // assigned to; TS can't verify a single implementation covers an
68
- // overloaded type, but this one forwards to the real stream method.
53
+ // SAFETY: `wrapped` matches both real `write` overload shapes; TS cannot verify one implementation covers an overloaded type.
69
54
  return wrapped;
70
55
  };
71
56
  process.stdout.write = wrapWrite(origStdoutWrite);
@@ -131,8 +116,7 @@ function cmdCaptureCore(hippoRoot, options) {
131
116
  };
132
117
  printCaptureTally(options, captureExtractedItems(targetRoot, writeOpts, extracted, keys));
133
118
  }
134
- // Dedup only against rows this capture's reader sees: another tenant's rows, or another
135
- // project's, are hidden from it, so they must not stop its own copy.
119
+ // Dedup only against rows this capture's reader sees: another tenant's or project's rows are hidden, so they must not stop its own copy.
136
120
  // Only a row holding an item's longest word can hold that item, so the store returns those rows and no others.
137
121
  function storedKeysInView(targetRoot, options, extracted) {
138
122
  const stored = loadTextsHoldingWords(targetRoot, options.global ? undefined : options.tenantId, extracted.map((item) => longestWord(item.content)), undefined, EVERY_SCOPE);
@@ -1,12 +1,6 @@
1
1
  import { type HookRuntime } from '../core/capture-contract.js';
2
- /**
3
- * Log-forgery guard: messages here interpolate payload-controlled values
4
- * (transcript paths, session ids). Strip C0 control chars — newlines above
5
- * all — so a crafted value can't inject fake `[hippo] ...` log lines.
6
- * Exported for every `[hippo]`-prefixed log writer that interpolates
7
- * payload-controlled values (cli.ts appendSessionEndCloseLog) — one shared
8
- * guard, not per-file copies.
9
- */
2
+ /** Log-forgery guard: strip C0 control chars (newlines above all) from payload-controlled values so a crafted value cannot inject fake `[hippo]` log lines.
3
+ * Exported as the one shared guard for every `[hippo]`-prefixed log writer that interpolates payload values. */
10
4
  export declare function sanitizeLogMessage(message: string): string;
11
5
  export interface PreCompactOptions {
12
6
  stdinText?: string;
@@ -16,13 +10,8 @@ export interface PreCompactOptions {
16
10
  /** Called once when the hook accepts a compaction, with the text it printed or null when it printed none. */
17
11
  onBoundary?: (printed: string | null) => void;
18
12
  }
19
- /**
20
- * PreCompact hook entry point. Exit code 2 on PreCompact BLOCKS compaction,
21
- * so this verb must exit 0 on every path — malformed stdin, missing
22
- * transcript, and store errors all degrade to a logged no-op rather than a
23
- * thrown error. Callers (src/cli.ts) must not wrap this in anything that
24
- * could turn a caught-and-logged failure back into a non-zero exit.
25
- */
13
+ /** PreCompact hook entry point. Exit code 2 BLOCKS compaction, so every path (bad stdin, missing transcript, store error) must exit 0 as a logged no-op.
14
+ * Callers must not wrap this in anything that turns a caught-and-logged failure into a non-zero exit. */
26
15
  export declare function cmdPreCompact(hippoRoot: string, options: PreCompactOptions): Promise<void>;
27
16
  export interface PostCompactOptions {
28
17
  stdinText?: string;
@@ -10,19 +10,10 @@ import { errorMessage, log as logger } from '../util/log.js';
10
10
  import { resolveLastSessionTranscript } from './transcript.js';
11
11
  import { isVscodeTranscript } from './copilot-transcript.js';
12
12
  import { mergeWorkingState, transcriptWorkingState } from './working-state.js';
13
- // ---------------------------------------------------------------------------
14
- // `hippo pre-compact` — PreCompact hook producer
15
- // ---------------------------------------------------------------------------
16
13
  // Diagnostic-only log; a long-lived install must not grow it unbounded.
17
14
  const PRE_COMPACT_LOG_MAX_BYTES = 256 * 1024;
18
- /**
19
- * Log-forgery guard: messages here interpolate payload-controlled values
20
- * (transcript paths, session ids). Strip C0 control chars — newlines above
21
- * all — so a crafted value can't inject fake `[hippo] ...` log lines.
22
- * Exported for every `[hippo]`-prefixed log writer that interpolates
23
- * payload-controlled values (cli.ts appendSessionEndCloseLog) — one shared
24
- * guard, not per-file copies.
25
- */
15
+ /** Log-forgery guard: strip C0 control chars (newlines above all) from payload-controlled values so a crafted value cannot inject fake `[hippo]` log lines.
16
+ * Exported as the one shared guard for every `[hippo]`-prefixed log writer that interpolates payload values. */
26
17
  export function sanitizeLogMessage(message) {
27
18
  // eslint-disable-next-line no-control-regex
28
19
  return message.replace(/[\x00-\x1f]/g, '');
@@ -30,11 +21,18 @@ export function sanitizeLogMessage(message) {
30
21
  function appendPreCompactLog(logFile, message) {
31
22
  try {
32
23
  fs.mkdirSync(path.dirname(logFile), { recursive: true });
33
- const stat = fs.existsSync(logFile) ? fs.statSync(logFile) : null;
34
- if (stat && stat.size > PRE_COMPACT_LOG_MAX_BYTES) {
35
- fs.writeFileSync(logFile, '', 'utf8'); // start fresh — dumb cap, no rotation
24
+ // One handle, so the cap acts on the file it measured; two hooks writing in the same instant can overwrite one diagnostic line, which this log accepts.
25
+ const fd = fs.openSync(logFile, fs.constants.O_RDWR | fs.constants.O_CREAT);
26
+ try {
27
+ const size = fs.fstatSync(fd).size;
28
+ const startFresh = size > PRE_COMPACT_LOG_MAX_BYTES; // a dumb cap, no rotation
29
+ if (startFresh)
30
+ fs.ftruncateSync(fd, 0);
31
+ fs.writeSync(fd, `[hippo] ${new Date().toISOString()} ${sanitizeLogMessage(message)}\n`, startFresh ? 0 : size, 'utf8');
32
+ }
33
+ finally {
34
+ fs.closeSync(fd);
36
35
  }
37
- fs.appendFileSync(logFile, `[hippo] ${new Date().toISOString()} ${sanitizeLogMessage(message)}\n`, 'utf8');
38
36
  }
39
37
  catch (err) {
40
38
  // Diagnostic-only; a log write failure must never affect the exit-0 contract.
@@ -74,9 +72,7 @@ function snapshotJustSaved(hippoRoot, sessionId) {
74
72
  /** Runs the PreCompact producer: records the compaction, asks the summariser for memories, saves a working-state snapshot. Never extracts memories itself; SessionEnd capture owns that. */
75
73
  function runPreCompact(hippoRoot, options, logFile) {
76
74
  const { stdinText, stdinTimedOut = false, runtime = 'claude-code' } = options;
77
- // The PreCompact hook fires in every Claude Code project, including
78
- // ones that never ran `hippo init`, so gate before any store-opening call
79
- // (saveActiveTaskSnapshot etc. call initStore, which would create one).
75
+ // PreCompact fires in every Claude Code project, including ones that never ran `hippo init`; gate before any call that would create a store.
80
76
  if (!isInitialized(hippoRoot)) {
81
77
  appendPreCompactLog(logFile, 'skip: store not initialized');
82
78
  return;
@@ -180,13 +176,8 @@ function saveDerivedSnapshot(hippoRoot, logFile, sessionId, recordId, derived) {
180
176
  }
181
177
  }
182
178
  }
183
- /**
184
- * PreCompact hook entry point. Exit code 2 on PreCompact BLOCKS compaction,
185
- * so this verb must exit 0 on every path — malformed stdin, missing
186
- * transcript, and store errors all degrade to a logged no-op rather than a
187
- * thrown error. Callers (src/cli.ts) must not wrap this in anything that
188
- * could turn a caught-and-logged failure back into a non-zero exit.
189
- */
179
+ /** PreCompact hook entry point. Exit code 2 BLOCKS compaction, so every path (bad stdin, missing transcript, store error) must exit 0 as a logged no-op.
180
+ * Callers must not wrap this in anything that turns a caught-and-logged failure into a non-zero exit. */
190
181
  export async function cmdPreCompact(hippoRoot, options) {
191
182
  const logFile = options.logFile ?? defaultPreCompactLogPath();
192
183
  try {
@@ -284,6 +284,55 @@ export function saveItems(db, hippoRoot, ctx, log) {
284
284
  finishItemWrites(hippoRoot, writes, log);
285
285
  return writes.written.length;
286
286
  }
287
+ /** One failure, told once to the hook's output and once to the structured log. */
288
+ function reportFailure(log, step, reason) {
289
+ log(`${step} failed: ${reason}`);
290
+ logger.error(`post-compact: ${step} failed: ${reason}`);
291
+ }
292
+ function recordStep(step) {
293
+ try {
294
+ const record = recordSummary(step.db, step.hippoRoot, step.tenantId, { meta: step.payload, text: step.text, at: step.at });
295
+ step.result.snapshotSaved = record.snapshotSaved;
296
+ return record;
297
+ }
298
+ catch (err) {
299
+ if (isSqliteBusy(err))
300
+ throw err;
301
+ reportFailure(step.log, 'record step', errorMessage(err));
302
+ return null;
303
+ }
304
+ }
305
+ /** Busy with a saved record defers to sleep; any other failure goes to the caller. */
306
+ function itemsStep(step, record) {
307
+ const { payload, hippoRoot, log } = step;
308
+ try {
309
+ step.result.written = saveItems(step.db, hippoRoot, {
310
+ tenantId: step.tenantId,
311
+ recordId: record?.id ?? null,
312
+ sessionId: payload.sessionId,
313
+ originProject: record?.originProject ?? compactionOrigin(hippoRoot, payload.cwd),
314
+ cwd: payload.cwd,
315
+ items: step.text.items,
316
+ }, log);
317
+ }
318
+ catch (err) {
319
+ if (!isSqliteBusy(err) || record === null)
320
+ throw err;
321
+ // The record already holds the items; sleep finishes them.
322
+ step.result.deferred = true;
323
+ log(`store busy, items left for the next sleep: ${errorMessage(err)}`);
324
+ }
325
+ }
326
+ function spoolSummary(hippoRoot, payload, text, at, reason, result, log) {
327
+ try {
328
+ spool(hippoRoot, resolveTenantId({}), payload, text, at);
329
+ result.deferred = true;
330
+ log(`store busy, summary spooled: ${reason}`);
331
+ }
332
+ catch (spoolErr) {
333
+ reportFailure(log, 'spool', errorMessage(spoolErr));
334
+ }
335
+ }
287
336
  /** The PostCompact work: record the summary, then write its items. Each step is independent; a busy store spools or defers. Never throws. */
288
337
  export function saveCompaction(hippoRoot, payload, log) {
289
338
  const result = { written: null, deferred: false, snapshotSaved: false };
@@ -298,52 +347,14 @@ export function saveCompaction(hippoRoot, payload, log) {
298
347
  let db;
299
348
  try {
300
349
  db = openHippoDb(hippoRoot, { busyWaitMs: COMPACTION_DB_WAIT_MS });
301
- const tenantId = resolveTenantId({});
302
- let record = null;
303
- try {
304
- record = recordSummary(db, hippoRoot, tenantId, { meta: payload, text, at });
305
- result.snapshotSaved = record.snapshotSaved;
306
- }
307
- catch (err) {
308
- if (isSqliteBusy(err))
309
- throw err;
310
- log(`record step failed: ${errorMessage(err)}`);
311
- logger.error(`post-compact: record step failed: ${errorMessage(err)}`);
312
- }
313
- try {
314
- result.written = saveItems(db, hippoRoot, {
315
- tenantId,
316
- recordId: record?.id ?? null,
317
- sessionId: payload.sessionId,
318
- originProject: record?.originProject ?? compactionOrigin(hippoRoot, payload.cwd),
319
- cwd: payload.cwd,
320
- items: text.items,
321
- }, log);
322
- }
323
- catch (err) {
324
- if (!isSqliteBusy(err) || record === null)
325
- throw err;
326
- // The record already holds the items; sleep finishes them.
327
- result.deferred = true;
328
- log(`store busy, items left for the next sleep: ${errorMessage(err)}`);
329
- }
350
+ const step = { db, hippoRoot, tenantId: resolveTenantId({}), payload, text, at, result, log };
351
+ itemsStep(step, recordStep(step));
330
352
  }
331
353
  catch (err) {
332
- if (isSqliteBusy(err) || db === undefined) {
333
- try {
334
- spool(hippoRoot, resolveTenantId({}), payload, text, at);
335
- result.deferred = true;
336
- log(`store busy, summary spooled: ${errorMessage(err)}`);
337
- }
338
- catch (spoolErr) {
339
- log(`spool failed: ${errorMessage(spoolErr)}`);
340
- logger.error(`post-compact: spool failed: ${errorMessage(spoolErr)}`);
341
- }
342
- }
343
- else {
344
- log(`items step failed: ${errorMessage(err)}`);
345
- logger.error(`post-compact: items step failed: ${errorMessage(err)}`);
346
- }
354
+ if (isSqliteBusy(err) || db === undefined)
355
+ spoolSummary(hippoRoot, payload, text, at, errorMessage(err), result, log);
356
+ else
357
+ reportFailure(log, 'items step', errorMessage(err));
347
358
  }
348
359
  finally {
349
360
  if (db)
@@ -400,61 +411,74 @@ function closeWithoutSummary(db, tenantId, id, log) {
400
411
  function nextStartedAt(db, record) {
401
412
  return nextCompactionStart(db, record.tenantId, record.sessionId, record.startedAt);
402
413
  }
414
+ /** The one place a record becomes the argument saveItems takes. */
415
+ function itemContext(tenantId, record, items = record.items) {
416
+ return { tenantId, recordId: record.id, sessionId: record.sessionId, originProject: record.originProject, cwd: record.cwd, items };
417
+ }
403
418
  /** Records a spooled summary, then writes its items. */
404
419
  function spoolImporter(db, hippoRoot, log) {
405
420
  return (spooled, recorded) => {
406
421
  const record = recordSummary(db, hippoRoot, spooled.tenantId, { meta: spooled.payload, text: spooled.text, at: spooled.at });
407
422
  // The record holds the items now, so the file is done even if the write below fails.
408
423
  recorded();
409
- saveItems(db, hippoRoot, { tenantId: spooled.tenantId, recordId: record.id, sessionId: record.sessionId, originProject: record.originProject, cwd: record.cwd, items: record.items }, log);
424
+ saveItems(db, hippoRoot, itemContext(spooled.tenantId, record), log);
410
425
  };
411
426
  }
412
- /** Finishes what a killed hook or a busy store left: `summarised` records, spool files, and `started` records the transcript can fill. Returns how many compactions it saved. */
413
- export function replayCompactions(db, hippoRoot, log, deadline = Number.POSITIVE_INFINITY) {
414
- const tenantId = resolveTenantId({});
415
- const now = Date.now();
427
+ function replayStalled(db, hippoRoot, tenantId, now, log, deadline) {
416
428
  let finished = 0;
417
429
  const stalled = stalledSummarisedRows(db, tenantId, new Date(now - REPLAY_AFTER_MS).toISOString()).map(toRecord);
418
430
  for (const record of stalled) {
419
431
  if (Date.now() > deadline)
420
432
  break;
421
433
  try {
422
- saveItems(db, hippoRoot, { tenantId, recordId: record.id, sessionId: record.sessionId, originProject: record.originProject, cwd: record.cwd, items: record.items }, log);
434
+ saveItems(db, hippoRoot, itemContext(tenantId, record), log);
423
435
  finished++;
424
436
  }
425
437
  catch (err) {
426
438
  log(`replay of ${record.id} failed: ${errorMessage(err)}`);
427
439
  }
428
440
  }
441
+ return finished;
442
+ }
443
+ function replaySpool(db, hippoRoot, tenantId, log, deadline) {
429
444
  try {
430
- finished += importSpool(hippoRoot, tenantId, log, deadline, spoolImporter(db, hippoRoot, log));
445
+ return importSpool(hippoRoot, tenantId, log, deadline, spoolImporter(db, hippoRoot, log));
431
446
  }
432
447
  catch (err) {
433
448
  log(`spool import failed: ${errorMessage(err)}`);
449
+ return 0;
434
450
  }
451
+ }
452
+ /** Fills one open record from its transcript; true when it saved items. */
453
+ function fillFromTranscript(db, hippoRoot, tenantId, record, log) {
454
+ if (record.transcriptPath === null || !fs.existsSync(record.transcriptPath))
455
+ return false;
456
+ const next = nextStartedAt(db, record);
457
+ const found = transcriptSummary(record.transcriptPath, Date.parse(record.startedAt), next === null ? Number.POSITIVE_INFINITY : Date.parse(next));
458
+ if (found === null) {
459
+ // The record is past REPLAY_AFTER_MS, so a window that is fully scanned or out of reach stays empty.
460
+ closeWithoutSummary(db, tenantId, record.id, log);
461
+ return false;
462
+ }
463
+ const { found: listed, ...text } = readCompactionText(found);
464
+ if (!listed)
465
+ log(`no memories section in the transcript summary for ${record.id}`);
466
+ if (!markSummarised(db, tenantId, record.id, { text, summarisedAt: new Date().toISOString() })) {
467
+ log(`${record.id} was filled by another process`);
468
+ return false;
469
+ }
470
+ saveItems(db, hippoRoot, itemContext(tenantId, record, text.items), log);
471
+ return true;
472
+ }
473
+ function replayOpen(db, hippoRoot, tenantId, now, log, deadline) {
474
+ let finished = 0;
435
475
  const open = openTranscriptRows(db, tenantId, new Date(now - REPLAY_AFTER_MS).toISOString(), new Date(now - TRANSCRIPT_FILL_WINDOW_MS).toISOString()).map(toRecord);
436
476
  for (const record of open) {
437
477
  if (Date.now() > deadline)
438
478
  break;
439
479
  try {
440
- if (record.transcriptPath === null || !fs.existsSync(record.transcriptPath))
441
- continue;
442
- const next = nextStartedAt(db, record);
443
- const found = transcriptSummary(record.transcriptPath, Date.parse(record.startedAt), next === null ? Number.POSITIVE_INFINITY : Date.parse(next));
444
- if (found === null) {
445
- // The record is past REPLAY_AFTER_MS, so a window that is fully scanned or out of reach stays empty.
446
- closeWithoutSummary(db, tenantId, record.id, log);
447
- continue;
448
- }
449
- const { found: listed, ...text } = readCompactionText(found);
450
- if (!listed)
451
- log(`no memories section in the transcript summary for ${record.id}`);
452
- if (!markSummarised(db, tenantId, record.id, { text, summarisedAt: new Date().toISOString() })) {
453
- log(`${record.id} was filled by another process`);
454
- continue;
455
- }
456
- saveItems(db, hippoRoot, { tenantId, recordId: record.id, sessionId: record.sessionId, originProject: record.originProject, cwd: record.cwd, items: text.items }, log);
457
- finished++;
480
+ if (fillFromTranscript(db, hippoRoot, tenantId, record, log))
481
+ finished++;
458
482
  }
459
483
  catch (err) {
460
484
  log(`transcript fill of ${record.id} failed: ${errorMessage(err)}`);
@@ -462,6 +486,14 @@ export function replayCompactions(db, hippoRoot, log, deadline = Number.POSITIVE
462
486
  }
463
487
  return finished;
464
488
  }
489
+ /** Finishes what a killed hook or a busy store left: `summarised` records, spool files, and `started` records the transcript can fill. Returns how many compactions it saved. */
490
+ export function replayCompactions(db, hippoRoot, log, deadline = Number.POSITIVE_INFINITY) {
491
+ const tenantId = resolveTenantId({});
492
+ const now = Date.now();
493
+ return replayStalled(db, hippoRoot, tenantId, now, log, deadline)
494
+ + replaySpool(db, hippoRoot, tenantId, log, deadline)
495
+ + replayOpen(db, hippoRoot, tenantId, now, log, deadline);
496
+ }
465
497
  /** For `hippo sleep` and post-compact: opens the store itself and never throws. */
466
498
  export function replayCompactionsAt(hippoRoot, log, opts = {}) {
467
499
  let db;
@@ -21,7 +21,7 @@ export interface SpoolFs {
21
21
  }): void;
22
22
  }
23
23
  /** Test-only seam, so a test can make one fs call fail; null restores the real fs. */
24
- export declare function __setSpoolFs(next: SpoolFs | null): void;
24
+ export declare function _setSpoolFsForTests(next: SpoolFs | null): void;
25
25
  export interface SpooledCompaction {
26
26
  tenantId: string;
27
27
  payload: PostCompactPayload;
@@ -29,7 +29,7 @@ const NEW_STEM = /^(\d{13})-[0-9a-f]{8}$/;
29
29
  const LEGACY_STEM_TIME = /-(\d+)$/;
30
30
  let fsx = fs;
31
31
  /** Test-only seam, so a test can make one fs call fail; null restores the real fs. */
32
- export function __setSpoolFs(next) {
32
+ export function _setSpoolFsForTests(next) {
33
33
  fsx = next ?? fs;
34
34
  }
35
35
  const stamp = (ms) => String(Math.trunc(ms)).padStart(STAMP_DIGITS, '0');
@@ -30,7 +30,7 @@ export declare function readSessionTranscript(transcriptPath: string, log: (mess
30
30
  /** The transcript, read once and scanned, or null with the reason logged. */
31
31
  export declare function readSessionScan(transcriptPath: string, log: (message: string) => void): SessionScan | null;
32
32
  /** Test-only seam, the scheduler's pattern: lets a test prove a network path never reaches the probe. Null restores it. */
33
- export declare function __setDigestExistsProbe(probe: ((p: string) => boolean) | null): void;
33
+ export declare function _setDigestExistsProbeForTests(probe: ((p: string) => boolean) | null): void;
34
34
  /** The store root is realpath'd; transcript paths are not, and a deleted file has no realpath of its own. Null for a network path. */
35
35
  export declare function realFsPath(p: string): string | null;
36
36
  /** Repo-relative with forward slashes, '' for the root itself, null outside the repo or when the path cannot be resolved. */
@@ -18,7 +18,7 @@ import { loadLiveContentsBySourceAndTag } from '../store/entry-reads.js';
18
18
  import { SNAPSHOT_AMBIENT_MAX_AGE_MS } from '../store/sessions.js';
19
19
  import { loadLatestHandoff } from '../store/handoffs.js';
20
20
  import { isSyntheticMessage } from '../store/token-ledger.js';
21
- import { readTranscriptTail } from '../util/transcript-tail.js';
21
+ import { readOpenTranscriptTail } from '../util/transcript-tail.js';
22
22
  /** Five-word runs are stock phrases; six in a row is a copied clause. */
23
23
  export const ECHO_WINDOW = 6;
24
24
  /** Five sentences of about 150 chars leave room for the Changed line inside the total cap. */
@@ -228,11 +228,17 @@ export function scanSessionTranscript(jsonl) {
228
228
  };
229
229
  }
230
230
  export function readSessionTranscript(transcriptPath, log) {
231
- const size = fs.statSync(transcriptPath).size;
232
- if (size <= READ_CAP_BYTES)
233
- return fs.readFileSync(transcriptPath, 'utf8');
234
- log(`digest: transcript is ${size} bytes, reading its last ${READ_CAP_BYTES}`);
235
- return readTranscriptTail(transcriptPath, READ_CAP_BYTES);
231
+ const fd = fs.openSync(transcriptPath, 'r');
232
+ try {
233
+ const size = fs.fstatSync(fd).size;
234
+ if (size <= READ_CAP_BYTES)
235
+ return fs.readFileSync(fd, 'utf8');
236
+ log(`digest: transcript is ${size} bytes, reading its last ${READ_CAP_BYTES}`);
237
+ return readOpenTranscriptTail(fd, size, READ_CAP_BYTES);
238
+ }
239
+ finally {
240
+ fs.closeSync(fd);
241
+ }
236
242
  }
237
243
  /** The transcript, read once and scanned, or null with the reason logged. */
238
244
  export function readSessionScan(transcriptPath, log) {
@@ -246,7 +252,7 @@ export function readSessionScan(transcriptPath, log) {
246
252
  }
247
253
  let existsProbe = fs.existsSync;
248
254
  /** Test-only seam, the scheduler's pattern: lets a test prove a network path never reaches the probe. Null restores it. */
249
- export function __setDigestExistsProbe(probe) {
255
+ export function _setDigestExistsProbeForTests(probe) {
250
256
  existsProbe = probe ?? fs.existsSync;
251
257
  }
252
258
  /** A \\host or //host path would make existsSync open an SMB connection to a host named in transcript text. */