hippo-memory 1.44.0 → 1.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (528) hide show
  1. package/README.md +12 -10
  2. package/bin/hippo.js +3 -1
  3. package/dist/api.d.ts +21 -21
  4. package/dist/api.js +69 -42
  5. package/dist/audit.d.ts +1 -1
  6. package/dist/audit.js +9 -0
  7. package/dist/autolearn.d.ts +1 -1
  8. package/dist/autolearn.js +2 -1
  9. package/dist/cli.d.ts +3 -0
  10. package/dist/cli.js +151 -72
  11. package/dist/client.d.ts +4 -21
  12. package/dist/client.js +3 -112
  13. package/dist/config.js +2 -1
  14. package/dist/consolidate.d.ts +3 -0
  15. package/dist/consolidate.js +44 -42
  16. package/dist/dag.d.ts +1 -0
  17. package/dist/dag.js +10 -5
  18. package/dist/dashboard.js +7 -3
  19. package/dist/db.js +12 -23
  20. package/dist/dedupe.d.ts +1 -0
  21. package/dist/dedupe.js +4 -7
  22. package/dist/embedding-provider.js +2 -1
  23. package/dist/embeddings.js +81 -8
  24. package/dist/extract.d.ts +2 -0
  25. package/dist/extract.js +9 -4
  26. package/dist/mcp/server.js +21 -36
  27. package/dist/memory.d.ts +3 -0
  28. package/dist/memory.js +7 -1
  29. package/dist/refine-llm.js +3 -2
  30. package/dist/rerankers/jev.js +3 -2
  31. package/dist/rerankers/llm.js +3 -2
  32. package/dist/search.js +3 -3
  33. package/dist/server.d.ts +5 -0
  34. package/dist/server.js +39 -29
  35. package/dist/shared.js +1 -1
  36. package/dist/store.d.ts +18 -11
  37. package/dist/store.js +144 -63
  38. package/dist/version.d.ts +4 -6
  39. package/dist/version.js +4 -7
  40. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  41. package/extensions/openclaw-plugin/package.json +1 -1
  42. package/openclaw.plugin.json +1 -1
  43. package/package.json +6 -3
  44. package/dist/ablation.d.ts.map +0 -1
  45. package/dist/ablation.js.map +0 -1
  46. package/dist/ambient.d.ts.map +0 -1
  47. package/dist/ambient.js.map +0 -1
  48. package/dist/api.d.ts.map +0 -1
  49. package/dist/api.js.map +0 -1
  50. package/dist/audit-prune.d.ts.map +0 -1
  51. package/dist/audit-prune.js.map +0 -1
  52. package/dist/audit.d.ts.map +0 -1
  53. package/dist/audit.js.map +0 -1
  54. package/dist/auth.d.ts.map +0 -1
  55. package/dist/auth.js.map +0 -1
  56. package/dist/autolearn.d.ts.map +0 -1
  57. package/dist/autolearn.js.map +0 -1
  58. package/dist/availability.d.ts.map +0 -1
  59. package/dist/availability.js.map +0 -1
  60. package/dist/benchmarks/e1.3/incident-recall-eval.js +0 -78
  61. package/dist/benchmarks/e1.3/incident-recall-eval.js.map +0 -1
  62. package/dist/benchmarks/e1.3/slack-1000-event-smoke.js +0 -103
  63. package/dist/benchmarks/e1.3/slack-1000-event-smoke.js.map +0 -1
  64. package/dist/capture.d.ts.map +0 -1
  65. package/dist/capture.js.map +0 -1
  66. package/dist/card-detail.d.ts.map +0 -1
  67. package/dist/card-detail.js.map +0 -1
  68. package/dist/card.d.ts.map +0 -1
  69. package/dist/card.js.map +0 -1
  70. package/dist/cli.d.ts.map +0 -1
  71. package/dist/cli.js.map +0 -1
  72. package/dist/client.d.ts.map +0 -1
  73. package/dist/client.js.map +0 -1
  74. package/dist/compare.d.ts.map +0 -1
  75. package/dist/compare.js.map +0 -1
  76. package/dist/config.d.ts.map +0 -1
  77. package/dist/config.js.map +0 -1
  78. package/dist/connectors/github/backfill.d.ts.map +0 -1
  79. package/dist/connectors/github/backfill.js.map +0 -1
  80. package/dist/connectors/github/cli-impl.d.ts.map +0 -1
  81. package/dist/connectors/github/cli-impl.js.map +0 -1
  82. package/dist/connectors/github/deletion.d.ts.map +0 -1
  83. package/dist/connectors/github/deletion.js.map +0 -1
  84. package/dist/connectors/github/dlq.d.ts.map +0 -1
  85. package/dist/connectors/github/dlq.js.map +0 -1
  86. package/dist/connectors/github/idempotency.d.ts.map +0 -1
  87. package/dist/connectors/github/idempotency.js.map +0 -1
  88. package/dist/connectors/github/ingest.d.ts.map +0 -1
  89. package/dist/connectors/github/ingest.js.map +0 -1
  90. package/dist/connectors/github/octokit-client.d.ts.map +0 -1
  91. package/dist/connectors/github/octokit-client.js.map +0 -1
  92. package/dist/connectors/github/ratelimit.d.ts.map +0 -1
  93. package/dist/connectors/github/ratelimit.js.map +0 -1
  94. package/dist/connectors/github/scope.d.ts.map +0 -1
  95. package/dist/connectors/github/scope.js.map +0 -1
  96. package/dist/connectors/github/signature.d.ts.map +0 -1
  97. package/dist/connectors/github/signature.js.map +0 -1
  98. package/dist/connectors/github/tenant-routing.d.ts.map +0 -1
  99. package/dist/connectors/github/tenant-routing.js.map +0 -1
  100. package/dist/connectors/github/transform.d.ts.map +0 -1
  101. package/dist/connectors/github/transform.js.map +0 -1
  102. package/dist/connectors/github/types.d.ts.map +0 -1
  103. package/dist/connectors/github/types.js.map +0 -1
  104. package/dist/connectors/slack/backfill.d.ts.map +0 -1
  105. package/dist/connectors/slack/backfill.js.map +0 -1
  106. package/dist/connectors/slack/deletion.d.ts.map +0 -1
  107. package/dist/connectors/slack/deletion.js.map +0 -1
  108. package/dist/connectors/slack/dlq.d.ts.map +0 -1
  109. package/dist/connectors/slack/dlq.js.map +0 -1
  110. package/dist/connectors/slack/idempotency.d.ts.map +0 -1
  111. package/dist/connectors/slack/idempotency.js.map +0 -1
  112. package/dist/connectors/slack/ingest.d.ts.map +0 -1
  113. package/dist/connectors/slack/ingest.js.map +0 -1
  114. package/dist/connectors/slack/ratelimit.d.ts.map +0 -1
  115. package/dist/connectors/slack/ratelimit.js.map +0 -1
  116. package/dist/connectors/slack/scope.d.ts.map +0 -1
  117. package/dist/connectors/slack/scope.js.map +0 -1
  118. package/dist/connectors/slack/signature.d.ts.map +0 -1
  119. package/dist/connectors/slack/signature.js.map +0 -1
  120. package/dist/connectors/slack/tenant-routing.d.ts.map +0 -1
  121. package/dist/connectors/slack/tenant-routing.js.map +0 -1
  122. package/dist/connectors/slack/transform.d.ts.map +0 -1
  123. package/dist/connectors/slack/transform.js.map +0 -1
  124. package/dist/connectors/slack/types.d.ts.map +0 -1
  125. package/dist/connectors/slack/types.js.map +0 -1
  126. package/dist/connectors/slack/web-client.d.ts.map +0 -1
  127. package/dist/connectors/slack/web-client.js.map +0 -1
  128. package/dist/connectors/slack/workspaces.d.ts.map +0 -1
  129. package/dist/connectors/slack/workspaces.js.map +0 -1
  130. package/dist/consolidate.d.ts.map +0 -1
  131. package/dist/consolidate.js.map +0 -1
  132. package/dist/correction-latency.d.ts.map +0 -1
  133. package/dist/correction-latency.js.map +0 -1
  134. package/dist/customer-notes.d.ts.map +0 -1
  135. package/dist/customer-notes.js.map +0 -1
  136. package/dist/dag.d.ts.map +0 -1
  137. package/dist/dag.js.map +0 -1
  138. package/dist/dashboard.d.ts.map +0 -1
  139. package/dist/dashboard.js.map +0 -1
  140. package/dist/db.d.ts.map +0 -1
  141. package/dist/db.js.map +0 -1
  142. package/dist/decisions.d.ts.map +0 -1
  143. package/dist/decisions.js.map +0 -1
  144. package/dist/dedupe.d.ts.map +0 -1
  145. package/dist/dedupe.js.map +0 -1
  146. package/dist/embedding-provider.d.ts.map +0 -1
  147. package/dist/embedding-provider.js.map +0 -1
  148. package/dist/embeddings.d.ts.map +0 -1
  149. package/dist/embeddings.js.map +0 -1
  150. package/dist/eval-suite.d.ts.map +0 -1
  151. package/dist/eval-suite.js.map +0 -1
  152. package/dist/eval.d.ts.map +0 -1
  153. package/dist/eval.js.map +0 -1
  154. package/dist/extensions/openclaw-plugin/index.js.map +0 -1
  155. package/dist/extract.d.ts.map +0 -1
  156. package/dist/extract.js.map +0 -1
  157. package/dist/forward-claim-detector.d.ts.map +0 -1
  158. package/dist/forward-claim-detector.js.map +0 -1
  159. package/dist/goals.d.ts.map +0 -1
  160. package/dist/goals.js.map +0 -1
  161. package/dist/graph-extract.d.ts.map +0 -1
  162. package/dist/graph-extract.js.map +0 -1
  163. package/dist/graph-recall.d.ts.map +0 -1
  164. package/dist/graph-recall.js.map +0 -1
  165. package/dist/graph-stream.d.ts.map +0 -1
  166. package/dist/graph-stream.js.map +0 -1
  167. package/dist/graph-view.d.ts.map +0 -1
  168. package/dist/graph-view.js.map +0 -1
  169. package/dist/graph.d.ts.map +0 -1
  170. package/dist/graph.js.map +0 -1
  171. package/dist/handoff.d.ts.map +0 -1
  172. package/dist/handoff.js.map +0 -1
  173. package/dist/hooks.d.ts.map +0 -1
  174. package/dist/hooks.js.map +0 -1
  175. package/dist/importers.d.ts.map +0 -1
  176. package/dist/importers.js.map +0 -1
  177. package/dist/incidents.d.ts.map +0 -1
  178. package/dist/incidents.js.map +0 -1
  179. package/dist/index.d.ts.map +0 -1
  180. package/dist/index.js.map +0 -1
  181. package/dist/invalidation.d.ts.map +0 -1
  182. package/dist/invalidation.js.map +0 -1
  183. package/dist/mcp/framing.d.ts.map +0 -1
  184. package/dist/mcp/framing.js.map +0 -1
  185. package/dist/mcp/server.d.ts.map +0 -1
  186. package/dist/mcp/server.js.map +0 -1
  187. package/dist/memory-value-weights.d.ts.map +0 -1
  188. package/dist/memory-value-weights.js.map +0 -1
  189. package/dist/memory-value.d.ts.map +0 -1
  190. package/dist/memory-value.js.map +0 -1
  191. package/dist/memory.d.ts.map +0 -1
  192. package/dist/memory.js.map +0 -1
  193. package/dist/multihop.d.ts.map +0 -1
  194. package/dist/multihop.js.map +0 -1
  195. package/dist/owner-validation.d.ts.map +0 -1
  196. package/dist/owner-validation.js.map +0 -1
  197. package/dist/path-context.d.ts.map +0 -1
  198. package/dist/path-context.js.map +0 -1
  199. package/dist/physics-config.d.ts.map +0 -1
  200. package/dist/physics-config.js.map +0 -1
  201. package/dist/physics-state.d.ts.map +0 -1
  202. package/dist/physics-state.js.map +0 -1
  203. package/dist/physics.d.ts.map +0 -1
  204. package/dist/physics.js.map +0 -1
  205. package/dist/policies.d.ts.map +0 -1
  206. package/dist/policies.js.map +0 -1
  207. package/dist/postinstall.d.ts.map +0 -1
  208. package/dist/postinstall.js.map +0 -1
  209. package/dist/predictions.d.ts.map +0 -1
  210. package/dist/predictions.js.map +0 -1
  211. package/dist/processes.d.ts.map +0 -1
  212. package/dist/processes.js.map +0 -1
  213. package/dist/project-briefs.d.ts.map +0 -1
  214. package/dist/project-briefs.js.map +0 -1
  215. package/dist/project-identity.d.ts.map +0 -1
  216. package/dist/project-identity.js.map +0 -1
  217. package/dist/provenance-coverage.d.ts.map +0 -1
  218. package/dist/provenance-coverage.js.map +0 -1
  219. package/dist/rate-limit.d.ts.map +0 -1
  220. package/dist/rate-limit.js.map +0 -1
  221. package/dist/raw-archive-mirror-cleanup.d.ts.map +0 -1
  222. package/dist/raw-archive-mirror-cleanup.js.map +0 -1
  223. package/dist/raw-archive.d.ts.map +0 -1
  224. package/dist/raw-archive.js.map +0 -1
  225. package/dist/recall-history.d.ts.map +0 -1
  226. package/dist/recall-history.js.map +0 -1
  227. package/dist/recall-scope.d.ts.map +0 -1
  228. package/dist/recall-scope.js.map +0 -1
  229. package/dist/recall-trace.d.ts.map +0 -1
  230. package/dist/recall-trace.js.map +0 -1
  231. package/dist/refine-llm.d.ts.map +0 -1
  232. package/dist/refine-llm.js.map +0 -1
  233. package/dist/reject-flow.d.ts.map +0 -1
  234. package/dist/reject-flow.js.map +0 -1
  235. package/dist/rejection.d.ts.map +0 -1
  236. package/dist/rejection.js.map +0 -1
  237. package/dist/replay.d.ts.map +0 -1
  238. package/dist/replay.js.map +0 -1
  239. package/dist/rerankers/cross-encoder.d.ts.map +0 -1
  240. package/dist/rerankers/cross-encoder.js.map +0 -1
  241. package/dist/rerankers/index.d.ts.map +0 -1
  242. package/dist/rerankers/index.js.map +0 -1
  243. package/dist/rerankers/jev.d.ts.map +0 -1
  244. package/dist/rerankers/jev.js.map +0 -1
  245. package/dist/rerankers/llm.d.ts.map +0 -1
  246. package/dist/rerankers/llm.js.map +0 -1
  247. package/dist/rerankers/types.d.ts.map +0 -1
  248. package/dist/rerankers/types.js.map +0 -1
  249. package/dist/rrf.d.ts.map +0 -1
  250. package/dist/rrf.js.map +0 -1
  251. package/dist/salience.d.ts.map +0 -1
  252. package/dist/salience.js.map +0 -1
  253. package/dist/scheduler.d.ts.map +0 -1
  254. package/dist/scheduler.js.map +0 -1
  255. package/dist/scope.d.ts.map +0 -1
  256. package/dist/scope.js.map +0 -1
  257. package/dist/search.d.ts.map +0 -1
  258. package/dist/search.js.map +0 -1
  259. package/dist/secret-detect.d.ts.map +0 -1
  260. package/dist/secret-detect.js.map +0 -1
  261. package/dist/server-detect.d.ts.map +0 -1
  262. package/dist/server-detect.js.map +0 -1
  263. package/dist/server.d.ts.map +0 -1
  264. package/dist/server.js.map +0 -1
  265. package/dist/shared.d.ts.map +0 -1
  266. package/dist/shared.js.map +0 -1
  267. package/dist/skills.d.ts.map +0 -1
  268. package/dist/skills.js.map +0 -1
  269. package/dist/sleep-redact.d.ts +0 -58
  270. package/dist/sleep-redact.d.ts.map +0 -1
  271. package/dist/sleep-redact.js +0 -80
  272. package/dist/sleep-redact.js.map +0 -1
  273. package/dist/src/ablation.js +0 -138
  274. package/dist/src/ablation.js.map +0 -1
  275. package/dist/src/ambient.js +0 -148
  276. package/dist/src/ambient.js.map +0 -1
  277. package/dist/src/api.js +0 -2109
  278. package/dist/src/api.js.map +0 -1
  279. package/dist/src/audit-prune.js +0 -109
  280. package/dist/src/audit-prune.js.map +0 -1
  281. package/dist/src/audit.js +0 -213
  282. package/dist/src/audit.js.map +0 -1
  283. package/dist/src/auth.js +0 -97
  284. package/dist/src/auth.js.map +0 -1
  285. package/dist/src/autolearn.js +0 -174
  286. package/dist/src/autolearn.js.map +0 -1
  287. package/dist/src/availability.js +0 -94
  288. package/dist/src/availability.js.map +0 -1
  289. package/dist/src/capture.js +0 -1346
  290. package/dist/src/capture.js.map +0 -1
  291. package/dist/src/card-detail.js +0 -15
  292. package/dist/src/card-detail.js.map +0 -1
  293. package/dist/src/card.js +0 -19
  294. package/dist/src/card.js.map +0 -1
  295. package/dist/src/cli.js +0 -9387
  296. package/dist/src/cli.js.map +0 -1
  297. package/dist/src/client.js +0 -237
  298. package/dist/src/client.js.map +0 -1
  299. package/dist/src/compare.js +0 -122
  300. package/dist/src/compare.js.map +0 -1
  301. package/dist/src/config.js +0 -135
  302. package/dist/src/config.js.map +0 -1
  303. package/dist/src/connectors/github/backfill.js +0 -281
  304. package/dist/src/connectors/github/backfill.js.map +0 -1
  305. package/dist/src/connectors/github/cli-impl.js +0 -234
  306. package/dist/src/connectors/github/cli-impl.js.map +0 -1
  307. package/dist/src/connectors/github/deletion.js +0 -85
  308. package/dist/src/connectors/github/deletion.js.map +0 -1
  309. package/dist/src/connectors/github/dlq.js +0 -190
  310. package/dist/src/connectors/github/dlq.js.map +0 -1
  311. package/dist/src/connectors/github/idempotency.js +0 -27
  312. package/dist/src/connectors/github/idempotency.js.map +0 -1
  313. package/dist/src/connectors/github/ingest.js +0 -156
  314. package/dist/src/connectors/github/ingest.js.map +0 -1
  315. package/dist/src/connectors/github/octokit-client.js +0 -70
  316. package/dist/src/connectors/github/octokit-client.js.map +0 -1
  317. package/dist/src/connectors/github/ratelimit.js +0 -31
  318. package/dist/src/connectors/github/ratelimit.js.map +0 -1
  319. package/dist/src/connectors/github/scope.js +0 -13
  320. package/dist/src/connectors/github/scope.js.map +0 -1
  321. package/dist/src/connectors/github/signature.js +0 -81
  322. package/dist/src/connectors/github/signature.js.map +0 -1
  323. package/dist/src/connectors/github/tenant-routing.js +0 -69
  324. package/dist/src/connectors/github/tenant-routing.js.map +0 -1
  325. package/dist/src/connectors/github/transform.js +0 -103
  326. package/dist/src/connectors/github/transform.js.map +0 -1
  327. package/dist/src/connectors/github/types.js +0 -100
  328. package/dist/src/connectors/github/types.js.map +0 -1
  329. package/dist/src/connectors/slack/backfill.js +0 -78
  330. package/dist/src/connectors/slack/backfill.js.map +0 -1
  331. package/dist/src/connectors/slack/deletion.js +0 -59
  332. package/dist/src/connectors/slack/deletion.js.map +0 -1
  333. package/dist/src/connectors/slack/dlq.js +0 -224
  334. package/dist/src/connectors/slack/dlq.js.map +0 -1
  335. package/dist/src/connectors/slack/idempotency.js +0 -31
  336. package/dist/src/connectors/slack/idempotency.js.map +0 -1
  337. package/dist/src/connectors/slack/ingest.js +0 -109
  338. package/dist/src/connectors/slack/ingest.js.map +0 -1
  339. package/dist/src/connectors/slack/ratelimit.js +0 -18
  340. package/dist/src/connectors/slack/ratelimit.js.map +0 -1
  341. package/dist/src/connectors/slack/scope.js +0 -13
  342. package/dist/src/connectors/slack/scope.js.map +0 -1
  343. package/dist/src/connectors/slack/signature.js +0 -27
  344. package/dist/src/connectors/slack/signature.js.map +0 -1
  345. package/dist/src/connectors/slack/tenant-routing.js +0 -41
  346. package/dist/src/connectors/slack/tenant-routing.js.map +0 -1
  347. package/dist/src/connectors/slack/transform.js +0 -47
  348. package/dist/src/connectors/slack/transform.js.map +0 -1
  349. package/dist/src/connectors/slack/types.js +0 -35
  350. package/dist/src/connectors/slack/types.js.map +0 -1
  351. package/dist/src/connectors/slack/web-client.js +0 -43
  352. package/dist/src/connectors/slack/web-client.js.map +0 -1
  353. package/dist/src/connectors/slack/workspaces.js +0 -62
  354. package/dist/src/connectors/slack/workspaces.js.map +0 -1
  355. package/dist/src/consolidate.js +0 -978
  356. package/dist/src/consolidate.js.map +0 -1
  357. package/dist/src/correction-latency.js +0 -74
  358. package/dist/src/correction-latency.js.map +0 -1
  359. package/dist/src/customer-notes.js +0 -325
  360. package/dist/src/customer-notes.js.map +0 -1
  361. package/dist/src/dag.js +0 -352
  362. package/dist/src/dag.js.map +0 -1
  363. package/dist/src/dashboard.js +0 -258
  364. package/dist/src/dashboard.js.map +0 -1
  365. package/dist/src/db.js +0 -2731
  366. package/dist/src/db.js.map +0 -1
  367. package/dist/src/decisions.js +0 -304
  368. package/dist/src/decisions.js.map +0 -1
  369. package/dist/src/dedupe.js +0 -141
  370. package/dist/src/dedupe.js.map +0 -1
  371. package/dist/src/embedding-provider.js +0 -314
  372. package/dist/src/embedding-provider.js.map +0 -1
  373. package/dist/src/embeddings.js +0 -543
  374. package/dist/src/embeddings.js.map +0 -1
  375. package/dist/src/eval-suite.js +0 -294
  376. package/dist/src/eval-suite.js.map +0 -1
  377. package/dist/src/eval.js +0 -187
  378. package/dist/src/eval.js.map +0 -1
  379. package/dist/src/extract.js +0 -117
  380. package/dist/src/extract.js.map +0 -1
  381. package/dist/src/forward-claim-detector.js +0 -117
  382. package/dist/src/forward-claim-detector.js.map +0 -1
  383. package/dist/src/goals.js +0 -399
  384. package/dist/src/goals.js.map +0 -1
  385. package/dist/src/graph-extract.js +0 -314
  386. package/dist/src/graph-extract.js.map +0 -1
  387. package/dist/src/graph-recall.js +0 -277
  388. package/dist/src/graph-recall.js.map +0 -1
  389. package/dist/src/graph-stream.js +0 -176
  390. package/dist/src/graph-stream.js.map +0 -1
  391. package/dist/src/graph-view.js +0 -310
  392. package/dist/src/graph-view.js.map +0 -1
  393. package/dist/src/graph.js +0 -762
  394. package/dist/src/graph.js.map +0 -1
  395. package/dist/src/handoff.js +0 -65
  396. package/dist/src/handoff.js.map +0 -1
  397. package/dist/src/hooks.js +0 -926
  398. package/dist/src/hooks.js.map +0 -1
  399. package/dist/src/importers.js +0 -881
  400. package/dist/src/importers.js.map +0 -1
  401. package/dist/src/incidents.js +0 -336
  402. package/dist/src/incidents.js.map +0 -1
  403. package/dist/src/index.js +0 -32
  404. package/dist/src/index.js.map +0 -1
  405. package/dist/src/invalidation.js +0 -129
  406. package/dist/src/invalidation.js.map +0 -1
  407. package/dist/src/mcp/framing.js +0 -45
  408. package/dist/src/mcp/framing.js.map +0 -1
  409. package/dist/src/mcp/server.js +0 -1298
  410. package/dist/src/mcp/server.js.map +0 -1
  411. package/dist/src/memory-value-weights.js +0 -31
  412. package/dist/src/memory-value-weights.js.map +0 -1
  413. package/dist/src/memory-value.js +0 -261
  414. package/dist/src/memory-value.js.map +0 -1
  415. package/dist/src/memory.js +0 -425
  416. package/dist/src/memory.js.map +0 -1
  417. package/dist/src/multihop.js +0 -35
  418. package/dist/src/multihop.js.map +0 -1
  419. package/dist/src/owner-validation.js +0 -56
  420. package/dist/src/owner-validation.js.map +0 -1
  421. package/dist/src/path-context.js +0 -48
  422. package/dist/src/path-context.js.map +0 -1
  423. package/dist/src/physics-config.js +0 -26
  424. package/dist/src/physics-config.js.map +0 -1
  425. package/dist/src/physics-state.js +0 -172
  426. package/dist/src/physics-state.js.map +0 -1
  427. package/dist/src/physics.js +0 -378
  428. package/dist/src/physics.js.map +0 -1
  429. package/dist/src/policies.js +0 -414
  430. package/dist/src/policies.js.map +0 -1
  431. package/dist/src/postinstall.js +0 -101
  432. package/dist/src/postinstall.js.map +0 -1
  433. package/dist/src/predictions.js +0 -629
  434. package/dist/src/predictions.js.map +0 -1
  435. package/dist/src/processes.js +0 -349
  436. package/dist/src/processes.js.map +0 -1
  437. package/dist/src/project-briefs.js +0 -492
  438. package/dist/src/project-briefs.js.map +0 -1
  439. package/dist/src/project-identity.js +0 -200
  440. package/dist/src/project-identity.js.map +0 -1
  441. package/dist/src/provenance-coverage.js +0 -23
  442. package/dist/src/provenance-coverage.js.map +0 -1
  443. package/dist/src/rate-limit.js +0 -60
  444. package/dist/src/rate-limit.js.map +0 -1
  445. package/dist/src/raw-archive-mirror-cleanup.js +0 -55
  446. package/dist/src/raw-archive-mirror-cleanup.js.map +0 -1
  447. package/dist/src/raw-archive.js +0 -91
  448. package/dist/src/raw-archive.js.map +0 -1
  449. package/dist/src/recall-history.js +0 -235
  450. package/dist/src/recall-history.js.map +0 -1
  451. package/dist/src/recall-scope.js +0 -89
  452. package/dist/src/recall-scope.js.map +0 -1
  453. package/dist/src/recall-trace.js +0 -186
  454. package/dist/src/recall-trace.js.map +0 -1
  455. package/dist/src/refine-llm.js +0 -156
  456. package/dist/src/refine-llm.js.map +0 -1
  457. package/dist/src/reject-flow.js +0 -209
  458. package/dist/src/reject-flow.js.map +0 -1
  459. package/dist/src/rejection.js +0 -160
  460. package/dist/src/rejection.js.map +0 -1
  461. package/dist/src/replay.js +0 -122
  462. package/dist/src/replay.js.map +0 -1
  463. package/dist/src/rerankers/cross-encoder.js +0 -137
  464. package/dist/src/rerankers/cross-encoder.js.map +0 -1
  465. package/dist/src/rerankers/index.js +0 -20
  466. package/dist/src/rerankers/index.js.map +0 -1
  467. package/dist/src/rerankers/jev.js +0 -119
  468. package/dist/src/rerankers/jev.js.map +0 -1
  469. package/dist/src/rerankers/llm.js +0 -80
  470. package/dist/src/rerankers/llm.js.map +0 -1
  471. package/dist/src/rerankers/types.js +0 -2
  472. package/dist/src/rerankers/types.js.map +0 -1
  473. package/dist/src/rrf.js +0 -61
  474. package/dist/src/rrf.js.map +0 -1
  475. package/dist/src/salience.js +0 -74
  476. package/dist/src/salience.js.map +0 -1
  477. package/dist/src/scheduler.js +0 -77
  478. package/dist/src/scheduler.js.map +0 -1
  479. package/dist/src/scope.js +0 -35
  480. package/dist/src/scope.js.map +0 -1
  481. package/dist/src/search.js +0 -1003
  482. package/dist/src/search.js.map +0 -1
  483. package/dist/src/secret-detect.js +0 -95
  484. package/dist/src/secret-detect.js.map +0 -1
  485. package/dist/src/server-detect.js +0 -231
  486. package/dist/src/server-detect.js.map +0 -1
  487. package/dist/src/server.js +0 -3255
  488. package/dist/src/server.js.map +0 -1
  489. package/dist/src/shared.js +0 -502
  490. package/dist/src/shared.js.map +0 -1
  491. package/dist/src/skills.js +0 -346
  492. package/dist/src/skills.js.map +0 -1
  493. package/dist/src/sleep-redact.js +0 -80
  494. package/dist/src/sleep-redact.js.map +0 -1
  495. package/dist/src/sso.js +0 -22
  496. package/dist/src/sso.js.map +0 -1
  497. package/dist/src/stdin.js +0 -41
  498. package/dist/src/stdin.js.map +0 -1
  499. package/dist/src/store.js +0 -3749
  500. package/dist/src/store.js.map +0 -1
  501. package/dist/src/tenant.js +0 -17
  502. package/dist/src/tenant.js.map +0 -1
  503. package/dist/src/trace.js +0 -72
  504. package/dist/src/trace.js.map +0 -1
  505. package/dist/src/version.js +0 -40
  506. package/dist/src/version.js.map +0 -1
  507. package/dist/src/working-memory.js +0 -157
  508. package/dist/src/working-memory.js.map +0 -1
  509. package/dist/src/yaml.js +0 -107
  510. package/dist/src/yaml.js.map +0 -1
  511. package/dist/sso.d.ts +0 -13
  512. package/dist/sso.d.ts.map +0 -1
  513. package/dist/sso.js +0 -22
  514. package/dist/sso.js.map +0 -1
  515. package/dist/stdin.d.ts.map +0 -1
  516. package/dist/stdin.js.map +0 -1
  517. package/dist/store.d.ts.map +0 -1
  518. package/dist/store.js.map +0 -1
  519. package/dist/tenant.d.ts.map +0 -1
  520. package/dist/tenant.js.map +0 -1
  521. package/dist/trace.d.ts.map +0 -1
  522. package/dist/trace.js.map +0 -1
  523. package/dist/version.d.ts.map +0 -1
  524. package/dist/version.js.map +0 -1
  525. package/dist/working-memory.d.ts.map +0 -1
  526. package/dist/working-memory.js.map +0 -1
  527. package/dist/yaml.d.ts.map +0 -1
  528. package/dist/yaml.js.map +0 -1
package/dist/src/hooks.js DELETED
@@ -1,926 +0,0 @@
1
- /**
2
- * Hook install/uninstall for AI coding tools.
3
- *
4
- * Two integration models live in this file:
5
- *
6
- * 1. JSON-hook install (Claude Code only). Writes a `hooks` block into the
7
- * tool's settings.json with two entries:
8
- * - SessionEnd: `hippo session-end --log-file <path>` - spawns a detached
9
- * child that runs `hippo sleep` then `hippo capture --last-session` in
10
- * sequence, writing both outputs to the log file. The parent returns in
11
- * <100ms so the TUI teardown can't kill the child before it finishes.
12
- * - SessionStart: `hippo last-sleep --path <path>` - prints the log
13
- * written by the previous session's detached worker and then clears it,
14
- * so the user actually sees what was consolidated.
15
- * Earlier Claude Code forms are detected and migrated automatically:
16
- * - < 0.20.2: `Stop` hook firing `hippo sleep` on every assistant turn.
17
- * - < 0.21.0: bare `hippo sleep` in SessionEnd, no `--log-file`.
18
- * - 0.22.x: separate sleep + capture SessionEnd entries.
19
- *
20
- * 2. Plugin install (OpenCode only). OpenCode does NOT share Claude Code's
21
- * JSON-hook schema — its config has `additionalProperties: false` and no
22
- * `hooks` key, so v1.10.x-v1.11.1's JSON-hook installer broke opencode
23
- * launch (issue #24). Hippo now installs a TypeScript plugin at
24
- * `~/.config/opencode/plugins/hippo.ts` subscribing to opencode's
25
- * `session.idle` (→ `hippo session-end`) and `session.created` (→
26
- * `hippo last-sleep`) events. See OPENCODE_PLUGIN_SOURCE below for the
27
- * plugin file content + design rationale; see installOpencodePlugin for
28
- * the installer + the migration that removes any pre-existing broken
29
- * `hooks` block from opencode.json.
30
- */
31
- import * as fs from 'fs';
32
- import * as os from 'os';
33
- import * as path from 'path';
34
- import { fileURLToPath } from 'url';
35
- /** JSON-value string check. `constructor` narrows a primitive via its boxed wrapper
36
- * instead of inspecting the `typeof` tag (anti-slop/no-runtime-typeof); equivalent to
37
- * `typeof value === 'string'` for every value JSON.parse can ever produce. */
38
- function isJsonString(value) {
39
- return value !== undefined && value !== null && value.constructor === String;
40
- }
41
- /** JSON-value plain-object check (excludes arrays and null), typeof-free for the same
42
- * reason as isJsonString above. */
43
- function isJsonObject(value) {
44
- return value !== undefined && value !== null && !Array.isArray(value) && value.constructor === Object;
45
- }
46
- const HIPPO_SLEEP_MARKER = 'hippo sleep';
47
- const HIPPO_LAST_SLEEP_MARKER = 'hippo last-sleep';
48
- const HIPPO_CAPTURE_MARKER = 'hippo capture --last-session';
49
- const HIPPO_SESSION_END_MARKER = 'hippo session-end';
50
- const HIPPO_PINNED_INJECT_MARKER = 'hippo context --pinned-only';
51
- const HIPPO_PINNED_INJECT_COMMAND = 'hippo context --pinned-only --include-recent 5 --format additional-context';
52
- const HIPPO_CODEX_WRAPPER_MARKER = 'hippo codex wrapper';
53
- const HIPPO_PRE_COMPACT_MARKER = 'hippo pre-compact';
54
- const HIPPO_COMPACT_RESUME_MARKER = 'hippo compact-resume';
55
- const HIPPO_OPENCODE_PLUGIN_MARKER = 'HIPPO_OPENCODE_PLUGIN_V1';
56
- /**
57
- * The opencode plugin file we install at ~/.config/opencode/plugins/hippo.ts.
58
- *
59
- * Per https://opencode.ai/docs/plugins/, plugins are TS/JS modules exporting an
60
- * async function returning hooks. We subscribe to `event` and route:
61
- * session.idle → `hippo session-end` (Claude Code's SessionEnd equiv)
62
- * session.created → `hippo last-sleep` (Claude Code's SessionStart equiv)
63
- *
64
- * Design choices forced by plan-eng-critic Rev 0 review (2026-05-23):
65
- *
66
- * 1. No `import type { Plugin } from "@opencode-ai/plugin"`. The package's npm
67
- * publication status was unverifiable from the build sandbox (npmjs.com
68
- * returned 403); an unresolved type-only import would still crash the TS
69
- * runtime opencode uses to load the plugin. opencode infers plugin shape
70
- * from the returned object, so the type was convenience-only.
71
- *
72
- * 2. Defensive `typeof $ !== 'function'` guard. opencode runs in Bun (where
73
- * `$` is the shell-template helper), but a future Node-mode deployment
74
- * would have `$` undefined in the destructured context and the plugin
75
- * would throw on every session.idle, killing opencode sessions in a
76
- * hard-to-recover way (the idempotence marker prevents auto-reinstall).
77
- * Fail closed, let opencode continue.
78
- *
79
- * 3. `.quiet().nothrow()` on each `$\`...\`` so a missing hippo binary
80
- * (e.g. PATH-misconfigured user) does NOT throw out of the event handler.
81
- * The surrounding try/catch is belt-and-braces.
82
- *
83
- * 4. UserPromptSubmit equivalent NOT wired. opencode's `message.updated`
84
- * fires per-token, not per-prompt-submit; no clean per-prompt event.
85
- * Users wanting pinned-context auto-injection can call `hippo context`
86
- * via the MCP server (`hippo mcp`).
87
- *
88
- * 5. Versioned marker `HIPPO_OPENCODE_PLUGIN_V1` allows future versions to
89
- * overwrite cleanly. The installer's idempotence check requires BOTH
90
- * marker match AND content equality, so a plugin-source revision under
91
- * the same V1 marker re-writes the file on next install.
92
- */
93
- export const OPENCODE_PLUGIN_SOURCE = `// ${HIPPO_OPENCODE_PLUGIN_MARKER}
94
- // hippo-memory opencode plugin. DO NOT EDIT — regenerated on every
95
- // \`hippo hook install opencode\` from src/hooks.ts OPENCODE_PLUGIN_SOURCE
96
- // in https://github.com/kitfunso/hippo-memory. Local changes will be lost.
97
-
98
- export const HippoPlugin = async ({ $ }) => {
99
- return {
100
- event: async ({ event }) => {
101
- // Defense in depth: opencode currently runs in Bun where $ is the shell
102
- // template helper. A non-Bun runtime would have $ as undefined; fail
103
- // closed instead of crashing the host session.
104
- if (typeof $ !== "function") return;
105
- try {
106
- if (event.type === "session.idle") {
107
- await $\`hippo session-end\`.quiet().nothrow();
108
- } else if (event.type === "session.created") {
109
- await $\`hippo last-sleep\`.quiet().nothrow();
110
- }
111
- } catch {
112
- // hippo CLI not on PATH or other failure — never crash the host session.
113
- }
114
- },
115
- };
116
- };
117
- `;
118
- export { HIPPO_OPENCODE_PLUGIN_MARKER };
119
- function homeDir() {
120
- return process.env.HOME || process.env.USERPROFILE || os.homedir();
121
- }
122
- /**
123
- * Default log path consumed by `hippo last-sleep`. Shared fallback when
124
- * a caller doesn't pass --path explicitly.
125
- */
126
- export function defaultSleepLogPath() {
127
- return path.join(homeDir(), '.hippo', 'logs', 'last-sleep.log');
128
- }
129
- /**
130
- * Diagnostic-only log path for `hippo pre-compact`. Deliberately separate
131
- * from the SessionEnd sleep log: `hippo last-sleep` truncates that file on
132
- * every SessionStart, which would wipe pre-compact lines before anyone
133
- * could read them. Nothing consumes this file programmatically — it exists
134
- * for manual troubleshooting only. Overridden by `--log-file`.
135
- */
136
- export function defaultPreCompactLogPath() {
137
- return path.join(homeDir(), '.hippo', 'logs', 'pre-compact.log');
138
- }
139
- export function resolveCodexWrapperPaths() {
140
- const home = homeDir();
141
- const codexHome = path.join(home, '.codex');
142
- const wrapperDir = path.join(home, '.hippo', 'bin');
143
- return {
144
- wrapperDir,
145
- metadataPath: path.join(home, '.hippo', 'integrations', 'codex.json'),
146
- wrapperCmdPath: path.join(wrapperDir, 'codex.cmd'),
147
- wrapperPs1Path: path.join(wrapperDir, 'codex.ps1'),
148
- wrapperShPath: path.join(wrapperDir, 'codex'),
149
- logFile: path.join(home, '.hippo', 'logs', 'codex-sleep.log'),
150
- runsDir: path.join(home, '.hippo', 'runs', 'codex'),
151
- historyPath: path.join(codexHome, 'history.jsonl'),
152
- sessionsDir: path.join(codexHome, 'sessions'),
153
- };
154
- }
155
- function pathEquals(a, b) {
156
- return path.resolve(a).toLowerCase() === path.resolve(b).toLowerCase();
157
- }
158
- function readCodexWrapperMetadata() {
159
- const { metadataPath } = resolveCodexWrapperPaths();
160
- if (!fs.existsSync(metadataPath))
161
- return null;
162
- try {
163
- // This optimistic parse is never trusted directly — every call site reads fields off
164
- // the result only after isCodexWrapperMetadataValid has runtime-checked each string
165
- // field and the referenced paths.
166
- const parsed = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
167
- return parsed;
168
- }
169
- catch {
170
- return null;
171
- }
172
- }
173
- function readTextFile(filePath) {
174
- try {
175
- return fs.readFileSync(filePath, 'utf8');
176
- }
177
- catch {
178
- return null;
179
- }
180
- }
181
- function isHippoCodexWrapperFile(filePath) {
182
- if (!fs.existsSync(filePath))
183
- return false;
184
- const text = readTextFile(filePath);
185
- return text !== null && text.includes(HIPPO_CODEX_WRAPPER_MARKER);
186
- }
187
- function isCodexWrapperMetadataValid(metadata) {
188
- if (!metadata)
189
- return false;
190
- return (isJsonString(metadata.originalCodexPath) &&
191
- isJsonString(metadata.realCodexPath) &&
192
- isJsonString(metadata.commandPath) &&
193
- isJsonString(metadata.backupPath) &&
194
- fs.existsSync(metadata.realCodexPath) &&
195
- fs.existsSync(metadata.backupPath) &&
196
- isHippoCodexWrapperFile(metadata.commandPath));
197
- }
198
- function resolveHippoCliPath() {
199
- return fileURLToPath(new URL('../bin/hippo.js', import.meta.url));
200
- }
201
- function quoteForShell(value) {
202
- return `"${value.replace(/(["\\$`])/g, '\\$1')}"`;
203
- }
204
- function quoteForPowerShell(value) {
205
- return `'${value.replace(/'/g, "''")}'`;
206
- }
207
- function quoteForCmd(value) {
208
- return `"${value.replace(/"/g, '""')}"`;
209
- }
210
- function resolveCodexInstallPlan(originalCodexPath) {
211
- const dir = path.dirname(originalCodexPath);
212
- const ext = path.extname(originalCodexPath).toLowerCase();
213
- const name = path.basename(originalCodexPath, ext);
214
- const backupPath = path.join(dir, `${name}.hippo-real${ext}`);
215
- if (process.platform === 'win32' && ext === '.exe') {
216
- return {
217
- commandPath: path.join(dir, `${name}.cmd`),
218
- backupPath,
219
- installMode: 'cmd-shim',
220
- };
221
- }
222
- return {
223
- commandPath: originalCodexPath,
224
- backupPath,
225
- installMode: 'same-path',
226
- };
227
- }
228
- function writeCodexLauncherWrapper(commandPath) {
229
- const ext = path.extname(commandPath).toLowerCase();
230
- const nodePath = process.execPath;
231
- const hippoCliPath = resolveHippoCliPath();
232
- if (process.platform === 'win32' && ext === '.ps1') {
233
- writeExecutableFile(commandPath, [
234
- `# ${HIPPO_CODEX_WRAPPER_MARKER}`,
235
- `& ${quoteForPowerShell(nodePath)} ${quoteForPowerShell(hippoCliPath)} codex-run -- @args`,
236
- '',
237
- ].join('\n'));
238
- return;
239
- }
240
- if (process.platform === 'win32' && (ext === '.cmd' || ext === '.bat')) {
241
- writeExecutableFile(commandPath, [
242
- '@echo off',
243
- `REM ${HIPPO_CODEX_WRAPPER_MARKER}`,
244
- `${quoteForCmd(nodePath)} ${quoteForCmd(hippoCliPath)} codex-run -- %*`,
245
- '',
246
- ].join('\r\n'));
247
- return;
248
- }
249
- writeExecutableFile(commandPath, [
250
- '#!/usr/bin/env sh',
251
- `# ${HIPPO_CODEX_WRAPPER_MARKER}`,
252
- `exec ${quoteForShell(nodePath)} ${quoteForShell(hippoCliPath)} codex-run -- "$@"`,
253
- '',
254
- ].join('\n'));
255
- }
256
- function cleanupLegacyCodexPathWrappers(paths) {
257
- for (const filePath of [paths.wrapperCmdPath, paths.wrapperPs1Path, paths.wrapperShPath]) {
258
- if (fs.existsSync(filePath))
259
- fs.rmSync(filePath, { force: true });
260
- }
261
- }
262
- export function detectRealCodexPath() {
263
- const metadata = readCodexWrapperMetadata();
264
- if (isCodexWrapperMetadataValid(metadata))
265
- return metadata.realCodexPath;
266
- const { wrapperDir } = resolveCodexWrapperPaths();
267
- const entries = (process.env.PATH ?? '')
268
- .split(path.delimiter)
269
- .map((entry) => entry.trim())
270
- .filter(Boolean)
271
- .filter((entry) => !pathEquals(entry, wrapperDir));
272
- const names = process.platform === 'win32'
273
- ? ['codex.cmd', 'codex.ps1', 'codex.exe', 'codex']
274
- : ['codex'];
275
- for (const entry of entries) {
276
- for (const name of names) {
277
- const candidate = path.join(entry, name);
278
- if (fs.existsSync(candidate))
279
- return candidate;
280
- }
281
- }
282
- return null;
283
- }
284
- function ensureDir(dir) {
285
- if (!fs.existsSync(dir))
286
- fs.mkdirSync(dir, { recursive: true });
287
- }
288
- function writeExecutableFile(filePath, content) {
289
- fs.writeFileSync(filePath, content, 'utf8');
290
- try {
291
- fs.chmodSync(filePath, 0o755);
292
- }
293
- catch {
294
- // chmod is best-effort on Windows
295
- }
296
- }
297
- export function installCodexWrapper(realCodexPath) {
298
- const existingMetadata = readCodexWrapperMetadata();
299
- if (isCodexWrapperMetadataValid(existingMetadata) && !realCodexPath) {
300
- cleanupLegacyCodexPathWrappers(resolveCodexWrapperPaths());
301
- return {
302
- installed: true,
303
- metadataPath: resolveCodexWrapperPaths().metadataPath,
304
- realCodexPath: existingMetadata.realCodexPath,
305
- commandPath: existingMetadata.commandPath,
306
- backupPath: existingMetadata.backupPath,
307
- installMode: existingMetadata.installMode,
308
- };
309
- }
310
- const resolvedRealCodexPath = realCodexPath ?? detectRealCodexPath();
311
- if (!resolvedRealCodexPath) {
312
- throw new Error('Could not locate the real Codex executable on PATH.');
313
- }
314
- const paths = resolveCodexWrapperPaths();
315
- ensureDir(path.dirname(paths.metadataPath));
316
- ensureDir(path.dirname(paths.logFile));
317
- ensureDir(paths.runsDir);
318
- cleanupLegacyCodexPathWrappers(paths);
319
- const plan = resolveCodexInstallPlan(resolvedRealCodexPath);
320
- ensureDir(path.dirname(plan.commandPath));
321
- if (isCodexWrapperMetadataValid(existingMetadata)) {
322
- uninstallCodexWrapper();
323
- }
324
- if (!fs.existsSync(plan.backupPath)) {
325
- fs.renameSync(resolvedRealCodexPath, plan.backupPath);
326
- }
327
- writeCodexLauncherWrapper(plan.commandPath);
328
- const metadata = {
329
- originalCodexPath: resolvedRealCodexPath,
330
- realCodexPath: plan.backupPath,
331
- commandPath: plan.commandPath,
332
- backupPath: plan.backupPath,
333
- installMode: plan.installMode,
334
- logFile: paths.logFile,
335
- historyPath: paths.historyPath,
336
- sessionsDir: paths.sessionsDir,
337
- installedAt: new Date().toISOString(),
338
- };
339
- fs.writeFileSync(paths.metadataPath, JSON.stringify(metadata, null, 2) + '\n', 'utf8');
340
- return {
341
- installed: true,
342
- metadataPath: paths.metadataPath,
343
- realCodexPath: metadata.realCodexPath,
344
- commandPath: metadata.commandPath,
345
- backupPath: metadata.backupPath,
346
- installMode: metadata.installMode,
347
- };
348
- }
349
- export function uninstallCodexWrapper() {
350
- const paths = resolveCodexWrapperPaths();
351
- let changed = false;
352
- const metadata = readCodexWrapperMetadata();
353
- if (metadata) {
354
- if (fs.existsSync(metadata.commandPath) && isHippoCodexWrapperFile(metadata.commandPath)) {
355
- fs.rmSync(metadata.commandPath, { force: true });
356
- changed = true;
357
- }
358
- if (fs.existsSync(metadata.backupPath)) {
359
- fs.renameSync(metadata.backupPath, metadata.originalCodexPath);
360
- changed = true;
361
- }
362
- }
363
- cleanupLegacyCodexPathWrappers(paths);
364
- if (fs.existsSync(paths.metadataPath)) {
365
- fs.rmSync(paths.metadataPath, { force: true });
366
- changed = true;
367
- }
368
- return changed;
369
- }
370
- export function ensureCodexWrapperInstalled() {
371
- const metadata = readCodexWrapperMetadata();
372
- if (isCodexWrapperMetadataValid(metadata)) {
373
- cleanupLegacyCodexPathWrappers(resolveCodexWrapperPaths());
374
- return {
375
- status: 'already-installed',
376
- metadataPath: resolveCodexWrapperPaths().metadataPath,
377
- realCodexPath: metadata.realCodexPath,
378
- commandPath: metadata.commandPath,
379
- backupPath: metadata.backupPath,
380
- };
381
- }
382
- if (metadata) {
383
- uninstallCodexWrapper();
384
- }
385
- const detectedRealCodexPath = detectRealCodexPath();
386
- if (!detectedRealCodexPath) {
387
- return { status: 'not-found' };
388
- }
389
- const result = installCodexWrapper(detectedRealCodexPath);
390
- return {
391
- status: 'installed',
392
- metadataPath: result.metadataPath,
393
- realCodexPath: result.realCodexPath,
394
- commandPath: result.commandPath,
395
- backupPath: result.backupPath,
396
- };
397
- }
398
- /**
399
- * True if Codex wrapper metadata exists on this machine, i.e. the user opted
400
- * in to the wrapper at some point (via `hippo hook install codex`).
401
- */
402
- export function isCodexWrapperInstalled() {
403
- return readCodexWrapperMetadata() !== null;
404
- }
405
- /**
406
- * Repair-only variant of `ensureCodexWrapperInstalled`: re-ensures the wrapper
407
- * ONLY when wrapper metadata already exists — that metadata is the user's
408
- * opt-in record. Never performs a first install. Replacing another vendor's
409
- * binary must stay behind the explicit `hippo hook install codex` command;
410
- * doing it from postinstall or routine commands is a consent violation and
411
- * reads as binary hijacking to security scanners (issue #133).
412
- */
413
- export function repairCodexWrapperIfInstalled() {
414
- if (readCodexWrapperMetadata() === null) {
415
- return { status: 'not-found' };
416
- }
417
- return ensureCodexWrapperInstalled();
418
- }
419
- function collectFiles(dir) {
420
- if (!fs.existsSync(dir))
421
- return [];
422
- const out = [];
423
- const stack = [dir];
424
- while (stack.length > 0) {
425
- const current = stack.pop();
426
- if (current === undefined)
427
- break;
428
- for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
429
- const full = path.join(current, entry.name);
430
- if (entry.isDirectory()) {
431
- stack.push(full);
432
- }
433
- else if (entry.isFile()) {
434
- out.push(full);
435
- }
436
- }
437
- }
438
- return out;
439
- }
440
- function readCodexSessionIdsFromHistoryDelta(historyPath, startOffsetBytes) {
441
- if (!fs.existsSync(historyPath))
442
- return [];
443
- const raw = fs.readFileSync(historyPath);
444
- if (startOffsetBytes >= raw.length)
445
- return [];
446
- const delta = raw.subarray(startOffsetBytes).toString('utf8');
447
- const seen = new Set();
448
- const ordered = [];
449
- for (const line of delta.split('\n')) {
450
- if (!line.trim())
451
- continue;
452
- try {
453
- const parsed = JSON.parse(line);
454
- const sessionId = parsed.session_id;
455
- if (isJsonString(sessionId) && sessionId && !seen.has(sessionId)) {
456
- seen.add(sessionId);
457
- ordered.push(sessionId);
458
- }
459
- }
460
- catch {
461
- // ignore malformed JSONL lines
462
- }
463
- }
464
- return ordered;
465
- }
466
- function findCodexTranscriptBySessionId(sessionsDir, sessionId) {
467
- const matches = collectFiles(sessionsDir).filter((filePath) => filePath.endsWith('.jsonl') && filePath.includes(sessionId));
468
- if (matches.length === 0)
469
- return null;
470
- matches.sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs);
471
- return matches[0];
472
- }
473
- function findNewestCodexTranscriptSince(sessionsDir, startedAtMs) {
474
- const matches = collectFiles(sessionsDir)
475
- .filter((filePath) => filePath.endsWith('.jsonl'))
476
- .map((filePath) => ({ filePath, mtimeMs: fs.statSync(filePath).mtimeMs }))
477
- .filter((entry) => entry.mtimeMs >= startedAtMs)
478
- .sort((a, b) => b.mtimeMs - a.mtimeMs);
479
- return matches[0]?.filePath ?? null;
480
- }
481
- export function resolveCodexSessionTranscript(options) {
482
- const { codexHome, historyPath, startOffsetBytes, startedAtMs } = options;
483
- const sessionsDir = path.join(codexHome, 'sessions');
484
- for (const sessionId of readCodexSessionIdsFromHistoryDelta(historyPath, startOffsetBytes).reverse()) {
485
- const transcript = findCodexTranscriptBySessionId(sessionsDir, sessionId);
486
- if (transcript)
487
- return transcript;
488
- }
489
- return findNewestCodexTranscriptSince(sessionsDir, startedAtMs);
490
- }
491
- export function resolveJsonHookPaths(target) {
492
- const home = homeDir();
493
- const logsDir = path.join(home, '.hippo', 'logs');
494
- switch (target) {
495
- case 'claude-code':
496
- return {
497
- settings: path.join(home, '.claude', 'settings.json'),
498
- logFile: path.join(logsDir, 'claude-code-sleep.log'),
499
- display: 'Claude Code',
500
- };
501
- }
502
- }
503
- function hookArrayContains(hookArray, marker) {
504
- if (!Array.isArray(hookArray))
505
- return false;
506
- return JSON.stringify(hookArray).includes(marker);
507
- }
508
- function addIncludeRecentToPinnedCommand(command) {
509
- if (!command.includes(HIPPO_PINNED_INJECT_MARKER) || command.includes('--include-recent'))
510
- return command;
511
- return command.includes(' --format ')
512
- ? command.replace(' --format ', ' --include-recent 5 --format ')
513
- : `${command} --include-recent 5`;
514
- }
515
- function migratePinnedInjectRecentCommands(hookArray) {
516
- if (!Array.isArray(hookArray))
517
- return false;
518
- let changed = false;
519
- for (const entry of hookArray) {
520
- if (!isJsonObject(entry))
521
- continue;
522
- const innerHooks = entry.hooks;
523
- if (!Array.isArray(innerHooks))
524
- continue;
525
- for (const hook of innerHooks) {
526
- if (!isJsonObject(hook))
527
- continue;
528
- if (!isJsonString(hook.command))
529
- continue;
530
- const next = addIncludeRecentToPinnedCommand(hook.command);
531
- if (next !== hook.command) {
532
- hook.command = next;
533
- changed = true;
534
- }
535
- }
536
- }
537
- return changed;
538
- }
539
- function hasCurrentSessionEnd(hookArray) {
540
- return hookArrayContains(hookArray, HIPPO_SESSION_END_MARKER);
541
- }
542
- /**
543
- * Returns true when `hooks.SessionEnd` still contains either of the legacy
544
- * v0.22.x split entries (bare `hippo sleep` / `hippo capture --last-session`)
545
- * without the current consolidated `hippo session-end` entry.
546
- */
547
- function hasLegacySplitSessionEnd(hookArray) {
548
- if (!Array.isArray(hookArray))
549
- return false;
550
- const serialized = JSON.stringify(hookArray);
551
- const hasSleep = serialized.includes(HIPPO_SLEEP_MARKER);
552
- const hasCapture = serialized.includes(HIPPO_CAPTURE_MARKER);
553
- return (hasSleep || hasCapture) && !serialized.includes(HIPPO_SESSION_END_MARKER);
554
- }
555
- export function installJsonHooks(target) {
556
- const { settings: settingsPath, logFile } = resolveJsonHookPaths(target);
557
- const dir = path.dirname(settingsPath);
558
- if (!fs.existsSync(dir))
559
- fs.mkdirSync(dir, { recursive: true });
560
- let settings = {};
561
- if (fs.existsSync(settingsPath)) {
562
- try {
563
- settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
564
- }
565
- catch {
566
- return {
567
- target,
568
- settingsPath,
569
- installedSessionEnd: false,
570
- installedSessionStart: false,
571
- installedUserPromptSubmit: false,
572
- installedPreCompact: false,
573
- installedCompactResume: false,
574
- migratedPinnedInjectRecent: false,
575
- migratedFromStop: false,
576
- migratedLegacySessionEnd: false,
577
- migratedSplitSessionEnd: false,
578
- };
579
- }
580
- }
581
- if (!settings.hooks)
582
- settings.hooks = {};
583
- // SAFETY: settings.hooks is either freshly initialised to {} on the line above, or an
584
- // existing value from settings.json — Claude Code's own schema always writes an object
585
- // there; each event key below is still re-validated with Array.isArray before use.
586
- const hooks = settings.hooks;
587
- let migratedFromStop = false;
588
- if (Array.isArray(hooks.Stop) && hookArrayContains(hooks.Stop, HIPPO_SLEEP_MARKER)) {
589
- hooks.Stop = hooks.Stop.filter((entry) => !JSON.stringify(entry).includes(HIPPO_SLEEP_MARKER));
590
- if (hooks.Stop.length === 0)
591
- delete hooks.Stop;
592
- migratedFromStop = true;
593
- }
594
- // Migrate legacy SessionEnd forms:
595
- // - pre-0.21 bare `hippo sleep`
596
- // - 0.21.x+ `hippo sleep --log-file` split across two entries
597
- // - 0.22.x `hippo capture --last-session --log-file` second entry
598
- // All of these get collapsed into the single `hippo session-end` entry.
599
- let migratedLegacySessionEnd = false;
600
- let migratedSplitSessionEnd = false;
601
- if (Array.isArray(hooks.SessionEnd) && hasLegacySplitSessionEnd(hooks.SessionEnd)) {
602
- const before = hooks.SessionEnd.length;
603
- hooks.SessionEnd = hooks.SessionEnd.filter((entry) => {
604
- const s = JSON.stringify(entry);
605
- return !s.includes(HIPPO_SLEEP_MARKER) && !s.includes(HIPPO_CAPTURE_MARKER);
606
- });
607
- if (hooks.SessionEnd.length === 0)
608
- delete hooks.SessionEnd;
609
- // If the removed entries used the log-file pattern (0.21.x-0.22.x) we
610
- // call it a "split" migration; otherwise it was the older bare form.
611
- migratedSplitSessionEnd = true;
612
- migratedLegacySessionEnd = before > 1;
613
- }
614
- let installedSessionEnd = false;
615
- if (!hasCurrentSessionEnd(hooks.SessionEnd)) {
616
- if (!Array.isArray(hooks.SessionEnd))
617
- hooks.SessionEnd = [];
618
- hooks.SessionEnd.push({
619
- hooks: [
620
- {
621
- type: 'command',
622
- command: `hippo session-end --log-file "${logFile}"`,
623
- timeout: 5,
624
- },
625
- ],
626
- });
627
- installedSessionEnd = true;
628
- }
629
- let installedSessionStart = false;
630
- if (!hookArrayContains(hooks.SessionStart, HIPPO_LAST_SLEEP_MARKER)) {
631
- if (!Array.isArray(hooks.SessionStart))
632
- hooks.SessionStart = [];
633
- hooks.SessionStart.push({
634
- hooks: [
635
- {
636
- type: 'command',
637
- command: `hippo last-sleep --path "${logFile}"`,
638
- timeout: 5,
639
- },
640
- ],
641
- });
642
- installedSessionStart = true;
643
- }
644
- // Mid-session pinned-rule re-injection: UserPromptSubmit runs every turn,
645
- // so pinned memories stay in context even after the model would otherwise
646
- // "forget" them in a long session. Include the fresh write tail so lessons
647
- // saved earlier in the same session become visible on the next prompt even
648
- // before the user pins them explicitly.
649
- let installedUserPromptSubmit = false;
650
- const migratedPinnedInjectRecent = migratePinnedInjectRecentCommands(hooks.UserPromptSubmit);
651
- if (!hookArrayContains(hooks.UserPromptSubmit, HIPPO_PINNED_INJECT_MARKER)) {
652
- if (!Array.isArray(hooks.UserPromptSubmit))
653
- hooks.UserPromptSubmit = [];
654
- hooks.UserPromptSubmit.push({
655
- hooks: [
656
- {
657
- type: 'command',
658
- command: HIPPO_PINNED_INJECT_COMMAND,
659
- timeout: 5,
660
- },
661
- ],
662
- });
663
- installedUserPromptSubmit = true;
664
- }
665
- // PreCompact: fires on manual AND auto compaction (no matcher). Writes a
666
- // working-state snapshot before the transcript summary drops detail.
667
- // Exit-0 contract lives in the verb itself (src/capture.ts cmdPreCompact),
668
- // not here — this is install-time wiring only.
669
- let installedPreCompact = false;
670
- if (!hookArrayContains(hooks.PreCompact, HIPPO_PRE_COMPACT_MARKER)) {
671
- if (!Array.isArray(hooks.PreCompact))
672
- hooks.PreCompact = [];
673
- hooks.PreCompact.push({
674
- hooks: [
675
- {
676
- type: 'command',
677
- command: `hippo pre-compact --log-file "${defaultPreCompactLogPath()}"`,
678
- timeout: 30,
679
- },
680
- ],
681
- });
682
- installedPreCompact = true;
683
- }
684
- // SessionStart(compact): a SECOND SessionStart entry alongside the
685
- // un-matched last-sleep entry above. The matcher is an optimization, not
686
- // a dependency — compact-resume itself checks payload.source too, so an
687
- // older Claude Code that ignores the matcher just runs a silent no-op on
688
- // normal starts. Marker check keys on the command string, so this stays
689
- // idempotent alongside the sibling last-sleep entry.
690
- let installedCompactResume = false;
691
- if (!hookArrayContains(hooks.SessionStart, HIPPO_COMPACT_RESUME_MARKER)) {
692
- if (!Array.isArray(hooks.SessionStart))
693
- hooks.SessionStart = [];
694
- hooks.SessionStart.push({
695
- matcher: 'compact',
696
- hooks: [
697
- {
698
- type: 'command',
699
- command: 'hippo compact-resume',
700
- timeout: 10,
701
- },
702
- ],
703
- });
704
- installedCompactResume = true;
705
- }
706
- if (installedSessionEnd ||
707
- installedSessionStart ||
708
- installedUserPromptSubmit ||
709
- installedPreCompact ||
710
- installedCompactResume ||
711
- migratedPinnedInjectRecent ||
712
- migratedFromStop ||
713
- migratedLegacySessionEnd ||
714
- migratedSplitSessionEnd) {
715
- fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
716
- }
717
- return {
718
- target,
719
- settingsPath,
720
- installedSessionEnd,
721
- installedSessionStart,
722
- installedUserPromptSubmit,
723
- installedPreCompact,
724
- installedCompactResume,
725
- migratedPinnedInjectRecent,
726
- migratedFromStop,
727
- migratedLegacySessionEnd,
728
- migratedSplitSessionEnd,
729
- };
730
- }
731
- export function uninstallJsonHooks(target) {
732
- const { settings: settingsPath } = resolveJsonHookPaths(target);
733
- if (!fs.existsSync(settingsPath))
734
- return false;
735
- let settings;
736
- try {
737
- settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
738
- }
739
- catch {
740
- return false;
741
- }
742
- // SAFETY: Claude Code's settings.json always stores `hooks` as an object when
743
- // present; each event key below is still re-validated with Array.isArray before use.
744
- const hooks = settings.hooks;
745
- if (!hooks)
746
- return false;
747
- let changed = false;
748
- const markersByKey = {
749
- SessionEnd: [HIPPO_SESSION_END_MARKER, HIPPO_SLEEP_MARKER, HIPPO_CAPTURE_MARKER],
750
- // Both the un-matched last-sleep entry and the matcher:'compact'
751
- // compact-resume entry live under the SessionStart key; the matcher
752
- // field doesn't affect this substring match, so removal covers both.
753
- SessionStart: [HIPPO_LAST_SLEEP_MARKER, HIPPO_COMPACT_RESUME_MARKER],
754
- UserPromptSubmit: [HIPPO_PINNED_INJECT_MARKER],
755
- PreCompact: [HIPPO_PRE_COMPACT_MARKER],
756
- Stop: [HIPPO_SLEEP_MARKER],
757
- };
758
- for (const [key, markers] of Object.entries(markersByKey)) {
759
- if (!Array.isArray(hooks[key]))
760
- continue;
761
- const before = hooks[key].length;
762
- hooks[key] = hooks[key].filter((entry) => !markers.some((m) => JSON.stringify(entry).includes(m)));
763
- if (hooks[key].length !== before) {
764
- changed = true;
765
- if (hooks[key].length === 0)
766
- delete hooks[key];
767
- }
768
- }
769
- if (!changed)
770
- return false;
771
- if (Object.keys(hooks).length === 0)
772
- delete settings.hooks;
773
- fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
774
- return true;
775
- }
776
- export function resolveOpencodePluginPath() {
777
- return path.join(homeDir(), '.config', 'opencode', 'plugins', 'hippo.ts');
778
- }
779
- function resolveOpencodeConfigPath() {
780
- return path.join(homeDir(), '.config', 'opencode', 'opencode.json');
781
- }
782
- /**
783
- * Return true iff a single hook-array entry's command string starts with
784
- * `hippo ` (the verb-prefix). Used to surgically remove only hippo-owned
785
- * commands when migrating an opencode.json. We own the install side, so only
786
- * the canonical `hippo <verb>` form needs to match — and only canonical verbs
787
- * hippo itself installs (session-end, last-sleep, sleep, capture, context),
788
- * not any third-party tool that happens to be named `hippo`.
789
- *
790
- * Critic-mandated structural check (Rev 0): substring matching against
791
- * arbitrary user content is unsafe — a user's
792
- * `echo "remember to hippo sleep your laptop"` is not a hippo-owned hook.
793
- *
794
- * Per-hook (not per-entry) granularity (Rev 1 review): an entry whose inner
795
- * hooks array mixes hippo-installed commands with user-authored commands
796
- * must NOT lose the user-authored commands. The migration filters the inner
797
- * array per-hook, then drops the entry only when its inner array is empty.
798
- */
799
- const HIPPO_OWNED_COMMAND_RE = /^\s*hippo\s+(session-end|last-sleep|sleep|capture|context)\b/;
800
- function hookIsHippoOwned(hook) {
801
- if (!isJsonObject(hook))
802
- return false;
803
- const cmd = hook.command;
804
- return isJsonString(cmd) && HIPPO_OWNED_COMMAND_RE.test(cmd);
805
- }
806
- /**
807
- * Structurally strip every hippo-owned hook from opencode.json's hooks key.
808
- * Returns one of:
809
- * { migrated: true, jsonRepairFailed: false } — at least one hook removed.
810
- * { migrated: false, jsonRepairFailed: false } — file fine, nothing to do.
811
- * { migrated: false, jsonRepairFailed: true } — file present but unparseable.
812
- *
813
- * Per-hook surgery:
814
- * - For each entry in each event-key array, filter the inner `hooks` array
815
- * to remove hippo-owned hooks only. User-authored hooks in the same
816
- * inner array are preserved.
817
- * - When an entry's inner `hooks` array becomes empty, that entry is
818
- * removed from the outer array.
819
- * - When an event-key array becomes empty, the key is deleted.
820
- * - When the top-level `hooks` object becomes empty, it is deleted.
821
- * - Other keys (theme, etc.) are always preserved.
822
- */
823
- function migrateLegacyOpencodeHooksBlock() {
824
- const configPath = resolveOpencodeConfigPath();
825
- if (!fs.existsSync(configPath))
826
- return { migrated: false, jsonRepairFailed: false };
827
- let settings;
828
- try {
829
- settings = JSON.parse(fs.readFileSync(configPath, 'utf8'));
830
- }
831
- catch {
832
- return { migrated: false, jsonRepairFailed: true };
833
- }
834
- const hooks = settings.hooks;
835
- // Non-object hooks values (string, array, null) are user content we don't
836
- // recognise — leave them alone, return migrated=false.
837
- if (!isJsonObject(hooks)) {
838
- return { migrated: false, jsonRepairFailed: false };
839
- }
840
- const hooksObj = hooks;
841
- let changed = false;
842
- for (const key of Object.keys(hooksObj)) {
843
- if (!Array.isArray(hooksObj[key]))
844
- continue;
845
- const survivingEntries = [];
846
- for (const entry of hooksObj[key]) {
847
- if (!isJsonObject(entry)) {
848
- survivingEntries.push(entry);
849
- continue;
850
- }
851
- const innerHooks = entry.hooks;
852
- if (!Array.isArray(innerHooks)) {
853
- survivingEntries.push(entry);
854
- continue;
855
- }
856
- const beforeInner = innerHooks.length;
857
- const survivingInner = innerHooks.filter((h) => !hookIsHippoOwned(h));
858
- if (survivingInner.length !== beforeInner)
859
- changed = true;
860
- if (survivingInner.length === 0)
861
- continue; // drop entry, nothing left
862
- entry.hooks = survivingInner;
863
- survivingEntries.push(entry);
864
- }
865
- if (survivingEntries.length !== hooksObj[key].length)
866
- changed = true;
867
- hooksObj[key] = survivingEntries;
868
- if (hooksObj[key].length === 0)
869
- delete hooksObj[key];
870
- }
871
- if (!changed)
872
- return { migrated: false, jsonRepairFailed: false };
873
- if (Object.keys(hooksObj).length === 0)
874
- delete settings.hooks;
875
- fs.writeFileSync(configPath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
876
- return { migrated: true, jsonRepairFailed: false };
877
- }
878
- export function installOpencodePlugin() {
879
- const pluginPath = resolveOpencodePluginPath();
880
- const { migrated, jsonRepairFailed } = migrateLegacyOpencodeHooksBlock();
881
- // Idempotence: skip the write only if BOTH the marker is present AND the
882
- // content matches the current source. Marker-only matches (with stale
883
- // content) overwrite cleanly so future plugin-source patches reach
884
- // existing installs.
885
- if (fs.existsSync(pluginPath)) {
886
- const existing = fs.readFileSync(pluginPath, 'utf8');
887
- if (existing.includes(HIPPO_OPENCODE_PLUGIN_MARKER) && existing === OPENCODE_PLUGIN_SOURCE) {
888
- return { installed: false, pluginPath, migratedLegacyHooks: migrated, jsonRepairFailed };
889
- }
890
- }
891
- fs.mkdirSync(path.dirname(pluginPath), { recursive: true });
892
- fs.writeFileSync(pluginPath, OPENCODE_PLUGIN_SOURCE, 'utf8');
893
- return { installed: true, pluginPath, migratedLegacyHooks: migrated, jsonRepairFailed };
894
- }
895
- export function uninstallOpencodePlugin() {
896
- const pluginPath = resolveOpencodePluginPath();
897
- let removedFile = false;
898
- if (fs.existsSync(pluginPath)) {
899
- const existing = fs.readFileSync(pluginPath, 'utf8');
900
- if (existing.includes(HIPPO_OPENCODE_PLUGIN_MARKER)) {
901
- fs.unlinkSync(pluginPath);
902
- removedFile = true;
903
- }
904
- }
905
- // Always run the legacy migration on uninstall — the downgrade path (user
906
- // removing hippo entirely) must leave opencode launchable.
907
- const { migrated } = migrateLegacyOpencodeHooksBlock();
908
- return removedFile || migrated;
909
- }
910
- /**
911
- * Detect which AI coding tools are installed based on config directory presence.
912
- * Used by `hippo setup` to decide which JSON-hook installs to run.
913
- */
914
- export function detectInstalledTools() {
915
- const home = homeDir();
916
- const exists = (...parts) => fs.existsSync(path.join(home, ...parts));
917
- return [
918
- { name: 'claude-code', configDir: '~/.claude', detected: exists('.claude'), kind: 'json-hook' },
919
- { name: 'opencode', configDir: '~/.config/opencode', detected: exists('.config', 'opencode'), kind: 'plugin', notes: 'installs a TS plugin at ~/.config/opencode/plugins/hippo.ts' },
920
- { name: 'openclaw', configDir: '~/.openclaw', detected: exists('.openclaw'), kind: 'plugin', notes: 'install via `openclaw plugins install hippo-memory`' },
921
- { name: 'codex', configDir: '~/.codex', detected: exists('.codex'), kind: 'wrapper', notes: 'wraps the detected codex launcher for session-end consolidation' },
922
- { name: 'cursor', configDir: '~/.cursor', detected: exists('.cursor'), kind: 'markdown-instruction', notes: 'no hook API - patches .cursorrules in the project' },
923
- { name: 'pi', configDir: '~/.pi', detected: exists('.pi'), kind: 'markdown-instruction', notes: 'no hook API - patches AGENTS.md in the project' },
924
- ];
925
- }
926
- //# sourceMappingURL=hooks.js.map