failproofai 0.0.14 → 0.0.15-beta.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 (271) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +6 -6
  3. package/.next/standalone/.next/prerender-manifest.json +3 -3
  4. package/.next/standalone/.next/required-server-files.json +2 -2
  5. package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +3 -3
  6. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  7. package/.next/standalone/.next/server/app/_global-error/page.js +2 -2
  8. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  9. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  11. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  12. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  13. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  14. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
  15. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  16. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  17. package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +3 -3
  18. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  19. package/.next/standalone/.next/server/app/_not-found/page.js +2 -2
  20. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  21. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  22. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  23. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  24. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  25. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  26. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
  27. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  28. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  29. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  30. package/.next/standalone/.next/server/app/api/audit/invite/route.js +1 -1
  31. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/api/audit/run/route.js +1 -1
  33. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/api/auth/login-request/route.js +1 -1
  35. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +1 -1
  37. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  38. package/.next/standalone/.next/server/app/api/auth/logout/route.js +1 -1
  39. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/api/auth/reminder/route.js +1 -1
  41. package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -1
  42. package/.next/standalone/.next/server/app/api/auth/status/route.js +1 -1
  43. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js +1 -1
  45. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  46. package/.next/standalone/.next/server/app/audit/page/build-manifest.json +3 -3
  47. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  48. package/.next/standalone/.next/server/app/audit/page.js +2 -2
  49. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  50. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  51. package/.next/standalone/.next/server/app/index.html +1 -1
  52. package/.next/standalone/.next/server/app/index.rsc +15 -15
  53. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  54. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  55. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  56. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
  57. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  58. package/.next/standalone/.next/server/app/page/build-manifest.json +3 -3
  59. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  60. package/.next/standalone/.next/server/app/page.js +2 -2
  61. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  62. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  63. package/.next/standalone/.next/server/app/policies/page/build-manifest.json +3 -3
  64. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
  65. package/.next/standalone/.next/server/app/policies/page.js +2 -2
  66. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  67. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  68. package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +3 -3
  69. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  70. package/.next/standalone/.next/server/app/project/[name]/page.js +4 -4
  71. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  72. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  73. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +3 -3
  74. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  75. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  76. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +4 -4
  77. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  78. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  79. package/.next/standalone/.next/server/app/projects/page/build-manifest.json +3 -3
  80. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  81. package/.next/standalone/.next/server/app/projects/page.js +3 -3
  82. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  83. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  84. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-219ec._.js +1 -1
  85. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0hv08mx._.js → [root-of-the-server]__0-dh5jy._.js} +1 -1
  86. package/.next/standalone/.next/server/chunks/[root-of-the-server]__04_h-a5._.js +1 -1
  87. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06cuf1y._.js +1 -1
  88. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0obaznk._.js → [root-of-the-server]__0h3lfmp._.js} +1 -1
  89. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0jnjf2t._.js +1 -1
  90. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0xvsnvt._.js → [root-of-the-server]__0l4vuqm._.js} +1 -1
  91. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0longh-._.js +3 -0
  92. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0sb_5m8._.js +4 -4
  93. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0xuaoik._.js +6 -4
  94. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1hkdkmz._.js → [root-of-the-server]__10oa-v9._.js} +1 -1
  95. package/.next/standalone/.next/server/chunks/[root-of-the-server]__16le-kd._.js +1 -1
  96. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1i9rknc._.js → [root-of-the-server]__18d-9oi._.js} +1 -1
  97. package/.next/standalone/.next/server/chunks/[root-of-the-server]__19120tr._.js +3 -0
  98. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1fwl2mz._.js +1 -1
  99. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1is3glr._.js +3 -0
  100. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1myjm-d._.js +1 -1
  101. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +6 -6
  102. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_01r25oi._.js +1 -1
  103. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_09z9-p7._.js +1 -1
  104. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  105. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0hdsupo._.js → [root-of-the-server]__0114ewg._.js} +3 -3
  106. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01od0m6._.js +3 -0
  107. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02r5bgf._.js +4 -0
  108. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1s2b6h0._.js → [root-of-the-server]__04o-kw7._.js} +2 -2
  109. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e8sjqm._.js +4 -0
  110. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0lkzqax._.js +4 -0
  111. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0lpvwqm._.js +21 -0
  112. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0ynf7tx._.js → [root-of-the-server]__0qucxyj._.js} +3 -3
  113. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0u02miy._.js +4 -0
  114. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0uno39i._.js +3 -0
  115. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__170799-._.js +8 -8
  116. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__00cz9as._.js → [root-of-the-server]__1apb7k_._.js} +1 -1
  117. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ath6v_._.js +4 -0
  118. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1i21qhv._.js +3 -0
  119. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1nq7ivq._.js +1 -1
  120. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1py795m._.js +3 -0
  121. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1qapotl._.js +3 -0
  122. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1zqz4v8._.js +4 -0
  123. package/.next/standalone/.next/server/chunks/ssr/_077y5np._.js +3 -0
  124. package/.next/standalone/.next/server/chunks/ssr/_1-3unkg._.js +3 -0
  125. package/.next/standalone/.next/server/chunks/ssr/_1e19atl._.js +3 -0
  126. package/.next/standalone/.next/server/chunks/ssr/_1m_p7pi._.js +3 -0
  127. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  128. package/.next/standalone/.next/server/chunks/ssr/app_audit_loading_tsx_1j1kc6j._.js +1 -1
  129. package/.next/standalone/.next/server/chunks/ssr/app_components_project-list_tsx_1ke6anr._.js +3 -0
  130. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  131. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
  132. package/.next/standalone/.next/server/chunks/ssr/lib_0xkhw_v._.js +1 -1
  133. package/.next/standalone/.next/server/chunks/ssr/lib_hermes-projects_ts_05b8-it._.js +1 -1
  134. package/.next/standalone/.next/server/chunks/ssr/lib_openclaw-projects_ts_0qxq3bp._.js +1 -1
  135. package/.next/standalone/.next/server/chunks/ssr/{node_modules_html-to-image_es_index_0gkzjaa.js → node_modules_html-to-image_es_index_0w82veb.js} +1 -1
  136. package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_11bnuzn._.js +1 -1
  137. package/.next/standalone/.next/server/middleware-build-manifest.js +6 -6
  138. package/.next/standalone/.next/server/pages/404.html +1 -1
  139. package/.next/standalone/.next/server/pages/500.html +1 -1
  140. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  141. package/.next/standalone/.next/server/server-reference-manifest.json +10 -10
  142. package/.next/standalone/.next/static/chunks/0hn30_j22wpp_.js +6 -0
  143. package/.next/standalone/.next/static/chunks/{3s8aaig91937v.js → 1_20f96f1253b.js} +1 -1
  144. package/.next/standalone/.next/static/chunks/1hdhteui932bq.js +1 -0
  145. package/.next/standalone/.next/static/chunks/{33u59vf_8xpd-.js → 1j2xm011_aoae.js} +1 -1
  146. package/.next/standalone/.next/static/chunks/1qzsbft-jtnf8.js +1 -0
  147. package/.next/standalone/.next/static/chunks/{3-ogr79xqbw0h.js → 2mazwb1qmur1p.js} +1 -1
  148. package/.next/standalone/.next/static/chunks/2pujpnfx4pws6.css +2 -0
  149. package/.next/standalone/.next/static/chunks/2xbkqlma_-61k.js +1 -0
  150. package/.next/standalone/.next/static/chunks/{29o4j32z643_a.js → 2y7acsw0--8xf.js} +1 -1
  151. package/.next/standalone/.next/static/chunks/3060a-0fayz96.js +1 -0
  152. package/.next/standalone/.next/static/chunks/312ihvhxeuoi_.js +1 -0
  153. package/.next/standalone/.next/static/chunks/31c084gsop1bb.js +1 -0
  154. package/.next/standalone/.next/static/chunks/{1ua5armwfph8o.js → 31fmsp1soxi07.js} +1 -1
  155. package/.next/standalone/.next/static/chunks/{02jcotghcxrbu.js → 3kmwfieo15mr2.js} +1 -1
  156. package/.next/standalone/.next/static/chunks/{2uh_4k4m296z5.js → 3q9y67-fobgpc.js} +1 -1
  157. package/.next/standalone/.next/static/chunks/{turbopack-10hj8t5pf33tu.js → turbopack-1lsv92x7klwrn.js} +1 -1
  158. package/.next/standalone/app/actions/get-hooks-config.ts +85 -0
  159. package/.next/standalone/app/components/project-list.tsx +229 -42
  160. package/.next/standalone/app/policies/hooks-client.tsx +112 -14
  161. package/.next/standalone/app/project/[name]/page.tsx +12 -2
  162. package/.next/standalone/integration-suite/README.md +43 -1
  163. package/.next/standalone/integration-suite/ci-entrypoint.sh +21 -6
  164. package/.next/standalone/integration-suite/install-clis.sh +58 -13
  165. package/.next/standalone/integration-suite/probe-cli.sh +51 -11
  166. package/.next/standalone/integration-suite/report.js +52 -6
  167. package/.next/standalone/integration-suite/run.sh +55 -3
  168. package/.next/standalone/lib/hermes-profiles.ts +156 -0
  169. package/.next/standalone/lib/hermes-projects.ts +91 -25
  170. package/.next/standalone/lib/hermes-sessions.ts +65 -10
  171. package/.next/standalone/lib/openclaw-projects.ts +111 -18
  172. package/.next/standalone/lib/openclaw-sessions.ts +20 -0
  173. package/.next/standalone/lib/paths.ts +36 -0
  174. package/.next/standalone/lib/project-tree.ts +193 -0
  175. package/.next/standalone/lib/projects.ts +22 -0
  176. package/.next/standalone/node_modules/@next/env/package.json +1 -1
  177. package/.next/standalone/node_modules/next/dist/build/next-config-ts/transpile-config.js +3 -114
  178. package/.next/standalone/node_modules/next/dist/build/swc/index.js +1 -1
  179. package/.next/standalone/node_modules/next/dist/cli/next-test.js +2 -1
  180. package/.next/standalone/node_modules/next/dist/compiled/http-proxy/index.js +5 -5
  181. package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js +11 -10
  182. package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js +11 -10
  183. package/.next/standalone/node_modules/next/dist/compiled/next-server/app-route-turbo.runtime.prod.js +2 -2
  184. package/.next/standalone/node_modules/next/dist/compiled/next-server/pages-turbo.runtime.prod.js +9 -9
  185. package/.next/standalone/node_modules/next/dist/lib/install-dependencies.js +1 -1
  186. package/.next/standalone/node_modules/next/dist/lib/patch-incorrect-lockfile.js +3 -3
  187. package/.next/standalone/node_modules/next/dist/lib/typescript/loadTsConfig.js +181 -0
  188. package/.next/standalone/node_modules/next/dist/lib/typescript/missingDependencyError.js +1 -1
  189. package/.next/standalone/node_modules/next/dist/lib/typescript/runTypeCheckCli.js +53 -0
  190. package/.next/standalone/node_modules/next/dist/lib/typescript/runTypeScriptCli.js +256 -0
  191. package/.next/standalone/node_modules/next/dist/lib/verify-typescript-setup.js +97 -56
  192. package/.next/standalone/node_modules/next/dist/server/app-render/action-handler.js +129 -34
  193. package/.next/standalone/node_modules/next/dist/server/app-render/manifests-singleton.js +52 -4
  194. package/.next/standalone/node_modules/next/dist/server/config-schema.js +1 -1
  195. package/.next/standalone/node_modules/next/dist/server/config-shared.js +1 -2
  196. package/.next/standalone/node_modules/next/dist/server/config.js +1 -1
  197. package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-turbopack.js +2 -2
  198. package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-webpack.js +1 -1
  199. package/.next/standalone/node_modules/next/dist/server/image-optimizer.js +8 -27
  200. package/.next/standalone/node_modules/next/dist/server/lib/app-info-log.js +1 -1
  201. package/.next/standalone/node_modules/next/dist/server/lib/incremental-cache/index.js +90 -53
  202. package/.next/standalone/node_modules/next/dist/server/lib/patch-fetch.js +15 -2
  203. package/.next/standalone/node_modules/next/dist/server/lib/router-utils/proxy-request.js +4 -0
  204. package/.next/standalone/node_modules/next/dist/server/lib/start-server.js +1 -1
  205. package/.next/standalone/node_modules/next/dist/server/web/spec-extension/unstable-cache.js +1 -1
  206. package/.next/standalone/node_modules/next/dist/shared/lib/errors/canary-only-config-error.js +1 -1
  207. package/.next/standalone/node_modules/next/dist/shared/lib/router/utils/prepare-destination.js +2 -1
  208. package/.next/standalone/node_modules/next/dist/shared/lib/server-reference-info.js +12 -0
  209. package/.next/standalone/node_modules/next/dist/telemetry/anonymous-meta.js +1 -1
  210. package/.next/standalone/node_modules/next/dist/telemetry/events/swc-load-failure.js +1 -1
  211. package/.next/standalone/node_modules/next/dist/telemetry/events/version.js +2 -2
  212. package/.next/standalone/node_modules/next/package.json +10 -10
  213. package/.next/standalone/package.json +7 -6
  214. package/.next/standalone/pi-extension/index.ts +38 -5
  215. package/.next/standalone/server.js +1 -1
  216. package/dist/cli.mjs +623 -308
  217. package/lib/hermes-profiles.ts +156 -0
  218. package/lib/hermes-projects.ts +91 -25
  219. package/lib/hermes-sessions.ts +65 -10
  220. package/lib/openclaw-projects.ts +111 -18
  221. package/lib/openclaw-sessions.ts +20 -0
  222. package/lib/paths.ts +36 -0
  223. package/lib/project-tree.ts +193 -0
  224. package/lib/projects.ts +22 -0
  225. package/package.json +7 -6
  226. package/pi-extension/index.ts +38 -5
  227. package/scripts/launch.ts +7 -0
  228. package/src/audit/cli-adapters/hermes.ts +6 -3
  229. package/src/audit/cli-adapters/openclaw.ts +17 -13
  230. package/src/hooks/configure-wizard.ts +24 -2
  231. package/src/hooks/custom-hooks-loader.ts +58 -4
  232. package/src/hooks/enforcement-capability.ts +266 -0
  233. package/src/hooks/handler.ts +12 -1
  234. package/src/hooks/hook-activity-store.ts +14 -0
  235. package/src/hooks/hooks-config.ts +59 -1
  236. package/src/hooks/integrations.ts +123 -19
  237. package/src/hooks/manager.ts +93 -27
  238. package/src/hooks/policy-evaluator.ts +59 -7
  239. package/src/hooks/policy-types.ts +26 -0
  240. package/src/hooks/types.ts +50 -2
  241. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q2nbsl._.js +0 -3
  242. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1d9qen3._.js +0 -3
  243. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1mrihkj._.js +0 -3
  244. package/.next/standalone/.next/server/chunks/lib_openclaw-projects_ts_0gc-p24._.js +0 -3
  245. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__015_i4t._.js +0 -4
  246. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__030k0c6._.js +0 -3
  247. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__03lv-pe._.js +0 -4
  248. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__042d3cd._.js +0 -3
  249. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__09q1168._.js +0 -3
  250. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qeuy9c._.js +0 -4
  251. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s89hoe._.js +0 -4
  252. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0zf8xlq._.js +0 -3
  253. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17ai7sy._.js +0 -4
  254. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1d8omgc._.js +0 -3
  255. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1fax1sl._.js +0 -19
  256. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1tkjqka._.js +0 -4
  257. package/.next/standalone/.next/server/chunks/ssr/_05whahf._.js +0 -3
  258. package/.next/standalone/.next/server/chunks/ssr/_0_9_ytf._.js +0 -3
  259. package/.next/standalone/.next/server/chunks/ssr/_1kje4fm._.js +0 -3
  260. package/.next/standalone/.next/server/chunks/ssr/_1p0-leb._.js +0 -3
  261. package/.next/standalone/.next/static/chunks/06z_ex1ts3n4s.js +0 -1
  262. package/.next/standalone/.next/static/chunks/0o0ut0ugd0_-s.js +0 -1
  263. package/.next/standalone/.next/static/chunks/0xl97x-874k-u.js +0 -1
  264. package/.next/standalone/.next/static/chunks/19d7hqx8udopz.js +0 -1
  265. package/.next/standalone/.next/static/chunks/36j05kb2x323i.css +0 -2
  266. package/.next/standalone/.next/static/chunks/370sj2lgkw5ey.js +0 -1
  267. package/.next/standalone/.next/static/chunks/3w7g0n0iwwnbs.js +0 -1
  268. package/.next/standalone/.next/static/chunks/42oeva1-w0z2d.js +0 -6
  269. /package/.next/standalone/.next/static/{WQRKgSfFekLcC_pvyzp4S → QFmU1xD4R9N_HVfwccP6A}/_buildManifest.js +0 -0
  270. /package/.next/standalone/.next/static/{WQRKgSfFekLcC_pvyzp4S → QFmU1xD4R9N_HVfwccP6A}/_clientMiddlewareManifest.js +0 -0
  271. /package/.next/standalone/.next/static/{WQRKgSfFekLcC_pvyzp4S → QFmU1xD4R9N_HVfwccP6A}/_ssgManifest.js +0 -0
package/dist/cli.mjs CHANGED
@@ -19,7 +19,7 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
19
19
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
20
20
 
21
21
  // package.json
22
- var version2 = "0.0.14";
22
+ var version2 = "0.0.15-beta.0";
23
23
  var init_package = () => {};
24
24
 
25
25
  // src/posthog-key.ts
@@ -156,7 +156,7 @@ var init_telemetry_id = __esm(() => {
156
156
  });
157
157
 
158
158
  // src/hooks/types.ts
159
- var HOOK_SCOPES, INTEGRATION_TYPES, CODEX_HOOK_SCOPES, CODEX_HOOK_EVENT_TYPES, CODEX_EVENT_MAP, CODEX_TOOL_MAP, HERMES_TOOL_MAP, HERMES_TOOL_INPUT_MAP, HERMES_HOOK_SCOPES, HERMES_HOOK_EVENT_TYPES, HERMES_EVENT_MAP, COPILOT_HOOK_SCOPES, COPILOT_HOOK_EVENT_TYPES, COPILOT_TOOL_MAP, COPILOT_TOOL_INPUT_MAP, CURSOR_HOOK_SCOPES, CURSOR_HOOK_EVENT_TYPES, CURSOR_EVENT_MAP, CURSOR_TOOL_MAP, OPENCODE_HOOK_SCOPES, OPENCODE_HOOK_EVENT_TYPES, OPENCODE_TOOL_MAP, OPENCODE_TOOL_INPUT_MAP, PI_HOOK_SCOPES, PI_HOOK_EVENT_TYPES, PI_EVENT_MAP, PI_TOOL_MAP, PI_TOOL_INPUT_MAP, OPENCLAW_HOOK_SCOPES, OPENCLAW_HOOK_EVENT_TYPES, OPENCLAW_EVENT_MAP, OPENCLAW_TOOL_MAP, OPENCLAW_TOOL_INPUT_MAP, FACTORY_HOOK_SCOPES, FACTORY_HOOK_EVENT_TYPES, FACTORY_TOOL_MAP, DEVIN_HOOK_SCOPES, DEVIN_HOOK_EVENT_TYPES, DEVIN_TOOL_MAP, ANTIGRAVITY_HOOK_SCOPES, ANTIGRAVITY_HOOK_EVENT_TYPES, ANTIGRAVITY_EVENT_MAP, ANTIGRAVITY_TOOL_MAP, ANTIGRAVITY_TOOL_INPUT_MAP, GOOSE_HOOK_SCOPES, GOOSE_HOOK_EVENT_TYPES, GOOSE_TOOL_MAP, GOOSE_TOOL_INPUT_MAP, HOOK_EVENT_TYPES, FAILPROOFAI_HOOK_MARKER = "__failproofai_hook__";
159
+ var HOOK_SCOPES, INTEGRATION_TYPES, CODEX_HOOK_SCOPES, CODEX_HOOK_EVENT_TYPES, CODEX_EVENT_MAP, CODEX_TOOL_MAP, HERMES_TOOL_MAP, HERMES_TOOL_INPUT_MAP, HERMES_HOOK_SCOPES, HERMES_HOOK_EVENT_TYPES, HERMES_EVENT_MAP, COPILOT_HOOK_SCOPES, COPILOT_HOOK_EVENT_TYPES, COPILOT_TOOL_MAP, COPILOT_TOOL_INPUT_MAP, CURSOR_HOOK_SCOPES, CURSOR_HOOK_EVENT_TYPES, CURSOR_EVENT_MAP, CURSOR_TOOL_MAP, OPENCODE_HOOK_SCOPES, OPENCODE_HOOK_EVENT_TYPES, OPENCODE_TOOL_MAP, OPENCODE_TOOL_INPUT_MAP, PI_HOOK_SCOPES, PI_HOOK_EVENT_TYPES, PI_EVENT_MAP, PI_TOOL_MAP, PI_TOOL_INPUT_MAP, OPENCLAW_HOOK_SCOPES, OPENCLAW_HOOK_EVENT_TYPES, OPENCLAW_EVENT_MAP, OPENCLAW_TOOL_MAP, OPENCLAW_TOOL_INPUT_MAP, FACTORY_HOOK_SCOPES, FACTORY_HOOK_EVENT_TYPES, FACTORY_TOOL_MAP, DEVIN_HOOK_SCOPES, DEVIN_HOOK_EVENT_TYPES, DEVIN_TOOL_MAP, ANTIGRAVITY_HOOK_SCOPES, ANTIGRAVITY_HOOK_EVENT_TYPES, ANTIGRAVITY_EVENT_MAP, ANTIGRAVITY_TOOL_MAP, ANTIGRAVITY_TOOL_INPUT_MAP, GOOSE_HOOK_SCOPES, GOOSE_HOOK_EVENT_TYPES, GOOSE_TOOL_MAP, GOOSE_TOOL_INPUT_MAP, HOOK_EVENT_TYPES, CLAUDE_INSTALL_EVENT_TYPES, FAILPROOFAI_HOOK_MARKER = "__failproofai_hook__";
160
160
  var init_types = __esm(() => {
161
161
  HOOK_SCOPES = ["user", "project", "local"];
162
162
  INTEGRATION_TYPES = ["claude", "codex", "copilot", "cursor", "opencode", "pi", "hermes", "openclaw", "factory", "devin", "antigravity", "goose"];
@@ -516,6 +516,7 @@ var init_types = __esm(() => {
516
516
  "PostToolBatch",
517
517
  "Setup"
518
518
  ];
519
+ CLAUDE_INSTALL_EVENT_TYPES = HOOK_EVENT_TYPES.filter((e) => e !== "WorktreeCreate");
519
520
  });
520
521
 
521
522
  // src/hooks/tool-name-canonicalize.ts
@@ -775,6 +776,31 @@ function writeScopedHooksConfig(config, scope, cwd) {
775
776
  writeFileSync(configPath, JSON.stringify(config, null, 2) + `
776
777
  `, "utf8");
777
778
  }
779
+ function syncConventionPolicies(entries, scope, cwd) {
780
+ const configPath = getConfigPathForScope(scope, cwd);
781
+ if (!existsSync2(configPath) && entries.length === 0)
782
+ return false;
783
+ if (existsSync2(configPath)) {
784
+ try {
785
+ JSON.parse(readFileSync(configPath, "utf8"));
786
+ } catch {
787
+ hookLogWarn(`not recording convention policies: ${configPath} is not valid JSON — ` + `fix the syntax error and re-run. Nothing was written.`);
788
+ return false;
789
+ }
790
+ }
791
+ const config = readScopedHooksConfig(scope, cwd);
792
+ const sorted = [...entries].sort((a, b) => a.file.localeCompare(b.file));
793
+ const next = { ...config };
794
+ if (sorted.length === 0)
795
+ delete next.conventionPolicies;
796
+ else
797
+ next.conventionPolicies = sorted;
798
+ if (JSON.stringify(next.conventionPolicies ?? null) === JSON.stringify(config.conventionPolicies ?? null)) {
799
+ return false;
800
+ }
801
+ writeScopedHooksConfig(next, scope, cwd);
802
+ return true;
803
+ }
778
804
  var init_hooks_config = __esm(() => {
779
805
  init_hook_logger();
780
806
  });
@@ -2752,6 +2778,16 @@ You MUST complete the above action NOW. Do NOT ask the user for confirmation —
2752
2778
  decision: "deny"
2753
2779
  };
2754
2780
  }
2781
+ if (eventType === "UserPromptSubmit") {
2782
+ return {
2783
+ exitCode: 0,
2784
+ stdout: JSON.stringify({ continue: false, user_message: blockedMessage }),
2785
+ stderr: "",
2786
+ policyName: policy.name,
2787
+ reason,
2788
+ decision: "deny"
2789
+ };
2790
+ }
2755
2791
  const response = {
2756
2792
  permission: "deny",
2757
2793
  user_message: blockedMessage,
@@ -2928,6 +2964,28 @@ You MUST complete the above action NOW. Do NOT ask the user for confirmation —
2928
2964
  decision: "deny"
2929
2965
  };
2930
2966
  }
2967
+ if (session?.cli === "copilot") {
2968
+ if (eventType === "UserPromptSubmit") {
2969
+ return {
2970
+ exitCode: 0,
2971
+ stdout: JSON.stringify({ decision: "block", reason: blockedMessage }),
2972
+ stderr: "",
2973
+ policyName: policy.name,
2974
+ reason,
2975
+ decision: "deny"
2976
+ };
2977
+ }
2978
+ if (eventType === "PermissionRequest") {
2979
+ return {
2980
+ exitCode: 0,
2981
+ stdout: JSON.stringify({ behavior: "deny", message: blockedMessage }),
2982
+ stderr: "",
2983
+ policyName: policy.name,
2984
+ reason,
2985
+ decision: "deny"
2986
+ };
2987
+ }
2988
+ }
2931
2989
  if (eventType === "PermissionRequest") {
2932
2990
  const response = {
2933
2991
  hookSpecificOutput: {
@@ -3528,7 +3586,7 @@ async function loadSingleFile(absPath, opts) {
3528
3586
  const distUrl = distIndex ? pathToFileURL2(distIndex).href : null;
3529
3587
  tmpFiles = await rewriteFileTree(absPath, distUrl, distIndex);
3530
3588
  const entryTmp = absPath + TMP_SUFFIX;
3531
- const fileUrl = pathToFileURL2(entryTmp).href;
3589
+ const fileUrl = `${pathToFileURL2(entryTmp).href}?v=${++loadSequence}`;
3532
3590
  await import(fileUrl);
3533
3591
  } catch (err) {
3534
3592
  const msg = err instanceof Error ? err.message : String(err);
@@ -3573,9 +3631,11 @@ async function loadAllCustomHooks(customPoliciesPath, opts) {
3573
3631
  const conventionSources = [];
3574
3632
  const projectRoot = findProjectConfigDir(opts?.sessionCwd ?? process.cwd());
3575
3633
  const conventionEnabled = opts?.customPoliciesEnabled !== false;
3634
+ const loadedPaths = new Set;
3576
3635
  if (customPoliciesPath) {
3577
3636
  const absPath = isAbsolute(customPoliciesPath) ? customPoliciesPath : resolve4(projectRoot, customPoliciesPath);
3578
3637
  if (existsSync3(absPath)) {
3638
+ loadedPaths.add(absPath);
3579
3639
  await loadSingleFile(absPath);
3580
3640
  } else {
3581
3641
  hookLogWarn(`customPoliciesPath not found: ${absPath}`);
@@ -3585,8 +3645,9 @@ async function loadAllCustomHooks(customPoliciesPath, opts) {
3585
3645
  const projectDir = resolve4(projectRoot, ".failproofai", "policies");
3586
3646
  if (conventionEnabled)
3587
3647
  warnSkippedPolicyFiles(projectDir, "project");
3588
- const projectFiles = conventionEnabled ? discoverPolicyFiles(projectDir) : [];
3648
+ const projectFiles = conventionEnabled ? discoverPolicyFiles(projectDir).filter((f) => !loadedPaths.has(f)) : [];
3589
3649
  for (const file of projectFiles) {
3650
+ loadedPaths.add(file);
3590
3651
  const hooksBefore = getCustomHooks().length;
3591
3652
  await loadSingleFile(file, { conventionScope: "project" });
3592
3653
  const newHooks = getCustomHooks().slice(hooksBefore);
@@ -3599,10 +3660,11 @@ async function loadAllCustomHooks(customPoliciesPath, opts) {
3599
3660
  }
3600
3661
  }
3601
3662
  const userDir = resolve4(homedir4(), ".failproofai", "policies");
3602
- if (conventionEnabled)
3663
+ if (conventionEnabled && userDir !== projectDir)
3603
3664
  warnSkippedPolicyFiles(userDir, "user");
3604
- const userFiles = conventionEnabled ? discoverPolicyFiles(userDir) : [];
3665
+ const userFiles = conventionEnabled && userDir !== projectDir ? discoverPolicyFiles(userDir).filter((f) => !loadedPaths.has(f)) : [];
3605
3666
  for (const file of userFiles) {
3667
+ loadedPaths.add(file);
3606
3668
  const hooksBefore = getCustomHooks().length;
3607
3669
  await loadSingleFile(file, { conventionScope: "user" });
3608
3670
  const newHooks = getCustomHooks().slice(hooksBefore);
@@ -3638,7 +3700,7 @@ async function loadAllCustomHooks(customPoliciesPath, opts) {
3638
3700
  }
3639
3701
  return { hooks: allHooks, conventionSources };
3640
3702
  }
3641
- var LOADING_KEY = "__FAILPROOFAI_LOADING_HOOKS__", CONVENTION_FILE_RE, LOADABLE_EXT_RE;
3703
+ var LOADING_KEY = "__FAILPROOFAI_LOADING_HOOKS__", CONVENTION_FILE_RE, loadSequence = 0, LOADABLE_EXT_RE;
3642
3704
  var init_custom_hooks_loader = __esm(() => {
3643
3705
  init_hook_logger();
3644
3706
  init_custom_hooks_registry();
@@ -4856,6 +4918,65 @@ async function openSqliteReadonly(dbPath) {
4856
4918
  var sqlPromise = null;
4857
4919
  var init_sqlite_reader = () => {};
4858
4920
 
4921
+ // lib/hermes-profiles.ts
4922
+ import { readdirSync as readdirSync3 } from "node:fs";
4923
+ import { homedir as homedir11 } from "node:os";
4924
+ import { basename as basename2, dirname as dirname3, join as join9, resolve as resolve5 } from "node:path";
4925
+ function hermesRoot() {
4926
+ const env = (process.env.HERMES_HOME || "").trim();
4927
+ if (env) {
4928
+ const home = resolve5(env);
4929
+ const parent = dirname3(home);
4930
+ if (basename2(parent) === PROFILES_DIR)
4931
+ return dirname3(parent);
4932
+ return home;
4933
+ }
4934
+ return join9(homedir11(), ".hermes");
4935
+ }
4936
+ function listHermesProfiles() {
4937
+ const root = hermesRoot();
4938
+ const out = [{ name: HERMES_DEFAULT_PROFILE, home: root }];
4939
+ const seen = new Set([HERMES_DEFAULT_PROFILE]);
4940
+ let names;
4941
+ try {
4942
+ names = readdirSync3(join9(root, PROFILES_DIR), { withFileTypes: true }).filter((e) => (e.isDirectory() || e.isSymbolicLink()) && !e.name.startsWith(".")).map((e) => e.name).sort();
4943
+ } catch {
4944
+ return out;
4945
+ }
4946
+ for (const name of names) {
4947
+ if (seen.has(name))
4948
+ continue;
4949
+ seen.add(name);
4950
+ out.push({ name, home: join9(root, PROFILES_DIR, name) });
4951
+ }
4952
+ return out;
4953
+ }
4954
+ function hermesProjectName(profile, source) {
4955
+ return `hermes-${profile}-${source}`;
4956
+ }
4957
+ function hermesProjectPath(profile, source) {
4958
+ return `hermes:${profile}:${source}`;
4959
+ }
4960
+ function hermesProjectNameCandidates(name) {
4961
+ if (!name.startsWith("hermes-"))
4962
+ return [];
4963
+ const rest = name.slice("hermes-".length);
4964
+ if (!rest)
4965
+ return [];
4966
+ const out = [];
4967
+ const profiles = listHermesProfiles().map((p) => p.name).sort((a, b) => b.length - a.length);
4968
+ for (const profile of profiles) {
4969
+ const prefix = `${profile}-`;
4970
+ if (rest.startsWith(prefix) && rest.length > prefix.length) {
4971
+ out.push({ profile, source: rest.slice(prefix.length) });
4972
+ }
4973
+ }
4974
+ out.push({ profile: HERMES_DEFAULT_PROFILE, source: rest });
4975
+ return out;
4976
+ }
4977
+ var PROFILES_DIR = "profiles", HERMES_DEFAULT_PROFILE = "default";
4978
+ var init_hermes_profiles = () => {};
4979
+
4859
4980
  // lib/format-duration.ts
4860
4981
  function formatDuration(ms) {
4861
4982
  if (ms < 1000)
@@ -4877,10 +4998,15 @@ function formatDuration(ms) {
4877
4998
  }
4878
4999
 
4879
5000
  // lib/hermes-sessions.ts
4880
- import { homedir as homedir11 } from "node:os";
4881
- import { join as join9 } from "node:path";
4882
- function hermesDbPath() {
4883
- return process.env.HERMES_DB_PATH || join9(homedir11(), ".hermes", "state.db");
5001
+ import { join as join10 } from "node:path";
5002
+ function hermesDbPaths() {
5003
+ const override = process.env.HERMES_DB_PATH;
5004
+ if (override)
5005
+ return [{ profile: HERMES_DEFAULT_PROFILE, dbPath: override }];
5006
+ return listHermesProfiles().map((p) => ({
5007
+ profile: p.name,
5008
+ dbPath: join10(p.home, "state.db")
5009
+ }));
4884
5010
  }
4885
5011
  function epochToMs(value) {
4886
5012
  if (typeof value === "number" && Number.isFinite(value)) {
@@ -5011,7 +5137,15 @@ function hermesRowsToLogEntries(rows, source = "session") {
5011
5137
  async function getHermesSessionLog(sessionId) {
5012
5138
  if (!sessionId || !/^[A-Za-z0-9_-]+$/.test(sessionId))
5013
5139
  return null;
5014
- const db = await openSqliteReadonly(hermesDbPath());
5140
+ for (const { profile, dbPath } of hermesDbPaths()) {
5141
+ const found = await loadFromDb(dbPath, profile, sessionId);
5142
+ if (found)
5143
+ return found;
5144
+ }
5145
+ return null;
5146
+ }
5147
+ async function loadFromDb(dbPath, profile, sessionId) {
5148
+ const db = await openSqliteReadonly(dbPath);
5015
5149
  if (!db)
5016
5150
  return null;
5017
5151
  try {
@@ -5021,12 +5155,13 @@ async function getHermesSessionLog(sessionId) {
5021
5155
  const { source, cwd: realCwd } = sessionRows[0];
5022
5156
  const msgRows = db.query("SELECT id, role, content, tool_call_id, tool_calls, tool_name, timestamp " + "FROM messages WHERE session_id = ? ORDER BY timestamp ASC", [sessionId]);
5023
5157
  const entries = hermesRowsToLogEntries(msgRows, "session");
5024
- const cwd = realCwd && realCwd.length > 0 ? realCwd : source ? `hermes:${source}` : undefined;
5158
+ const cwd = realCwd && realCwd.length > 0 ? realCwd : source ? hermesProjectPath(profile, source) : undefined;
5025
5159
  return {
5026
5160
  entries,
5027
5161
  rawLines: msgRows,
5028
5162
  cwd,
5029
- filePath: `hermes://${sessionId}`
5163
+ filePath: `hermes://${sessionId}`,
5164
+ profile
5030
5165
  };
5031
5166
  } catch {
5032
5167
  return null;
@@ -5037,6 +5172,7 @@ async function getHermesSessionLog(sessionId) {
5037
5172
  var getCachedHermesSessionLog;
5038
5173
  var init_hermes_sessions = __esm(() => {
5039
5174
  init_sqlite_reader();
5175
+ init_hermes_profiles();
5040
5176
  init_log_entries();
5041
5177
  getCachedHermesSessionLog = runtimeCache((sessionId) => getHermesSessionLog(sessionId), 2, { maxSize: 50 });
5042
5178
  });
@@ -5052,13 +5188,22 @@ __export(exports_hermes_projects, {
5052
5188
  getCachedHermesProjects: () => getCachedHermesProjects
5053
5189
  });
5054
5190
  async function getHermesSessions() {
5055
- const db = await openSqliteReadonly(hermesDbPath());
5191
+ const out = [];
5192
+ for (const { profile, dbPath } of hermesDbPaths()) {
5193
+ out.push(...await readSessionsFromDb(dbPath, profile));
5194
+ }
5195
+ out.sort((a, b) => b.mtimeMs - a.mtimeMs);
5196
+ return out;
5197
+ }
5198
+ async function readSessionsFromDb(dbPath, profile) {
5199
+ const db = await openSqliteReadonly(dbPath);
5056
5200
  if (!db)
5057
5201
  return [];
5058
5202
  try {
5059
5203
  const rows = db.query("SELECT s.id, s.source, s.cwd, s.title, s.user_id, s.chat_id, s.chat_type, " + "s.started_at, s.ended_at, s.message_count, lm.last_activity " + "FROM sessions s " + "LEFT JOIN (SELECT session_id, MAX(timestamp) AS last_activity FROM messages GROUP BY session_id) lm " + "ON lm.session_id = s.id " + "ORDER BY lm.last_activity DESC");
5060
5204
  return rows.map((r) => ({
5061
5205
  sessionId: r.id,
5206
+ profile,
5062
5207
  source: r.source ?? undefined,
5063
5208
  cwd: r.cwd ?? undefined,
5064
5209
  title: r.title ?? undefined,
@@ -5077,36 +5222,58 @@ async function getHermesSessions() {
5077
5222
  }
5078
5223
  async function getHermesProjects() {
5079
5224
  const sessions = await getHermesSessions();
5080
- const latestBySource = new Map;
5225
+ const groups = new Map;
5081
5226
  for (const s of sessions) {
5082
5227
  if (s.messageCount <= 0 && !s.hasMessages)
5083
5228
  continue;
5084
- const src = s.source ?? "unknown";
5085
- latestBySource.set(src, Math.max(latestBySource.get(src) ?? 0, s.mtimeMs));
5229
+ const profile = s.profile || HERMES_DEFAULT_PROFILE;
5230
+ const source = s.source ?? "unknown";
5231
+ const key = JSON.stringify([profile, source]);
5232
+ const prev = groups.get(key);
5233
+ if (prev) {
5234
+ prev.latest = Math.max(prev.latest, s.mtimeMs);
5235
+ prev.count += 1;
5236
+ } else {
5237
+ groups.set(key, { profile, source, latest: s.mtimeMs, count: 1 });
5238
+ }
5086
5239
  }
5087
5240
  const out = [];
5088
- for (const [src, latest] of latestBySource) {
5241
+ for (const { profile, source, latest, count } of groups.values()) {
5089
5242
  const lastModified = new Date(latest);
5090
5243
  out.push({
5091
- name: `hermes-${src}`,
5092
- path: `hermes:${src}`,
5244
+ name: hermesProjectName(profile, source),
5245
+ path: hermesProjectPath(profile, source),
5093
5246
  isDirectory: true,
5094
5247
  lastModified,
5095
5248
  lastModifiedFormatted: formatDate(lastModified),
5096
- cli: ["hermes"]
5249
+ cli: ["hermes"],
5250
+ sessionCount: count
5097
5251
  });
5098
5252
  }
5099
5253
  out.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime());
5100
5254
  return out;
5101
5255
  }
5102
5256
  async function getHermesSessionsByEncodedName(name) {
5103
- if (!name.startsWith("hermes-"))
5257
+ const candidates = hermesProjectNameCandidates(name);
5258
+ if (candidates.length === 0)
5104
5259
  return { cwd: null, sessions: [] };
5105
- const source = name.slice("hermes-".length);
5106
5260
  const sessions = await getHermesSessions();
5107
- const matched = sessions.filter((s) => (s.messageCount > 0 || s.hasMessages) && (s.source ?? "unknown") === source);
5261
+ const matching = (split) => sessions.filter((s) => (s.messageCount > 0 || s.hasMessages) && (s.profile || HERMES_DEFAULT_PROFILE) === split.profile && (s.source ?? "unknown") === split.source);
5262
+ let chosen = candidates[0];
5263
+ let matched = matching(chosen);
5264
+ if (matched.length === 0) {
5265
+ for (const candidate of candidates.slice(1)) {
5266
+ const hits = matching(candidate);
5267
+ if (hits.length > 0) {
5268
+ chosen = candidate;
5269
+ matched = hits;
5270
+ break;
5271
+ }
5272
+ }
5273
+ }
5274
+ const { profile, source } = chosen;
5108
5275
  return {
5109
- cwd: `hermes:${source}`,
5276
+ cwd: hermesProjectPath(profile, source),
5110
5277
  sessions: matched.map((s) => {
5111
5278
  const lastModified = new Date(s.mtimeMs);
5112
5279
  return {
@@ -5127,6 +5294,7 @@ var getCachedHermesSessions, getCachedHermesProjects, getCachedHermesSessionsByE
5127
5294
  var init_hermes_projects = __esm(() => {
5128
5295
  init_sqlite_reader();
5129
5296
  init_hermes_sessions();
5297
+ init_hermes_profiles();
5130
5298
  getCachedHermesSessions = runtimeCache(getHermesSessions, 2);
5131
5299
  getCachedHermesProjects = runtimeCache(getHermesProjects, 2);
5132
5300
  getCachedHermesSessionsByEncodedName = runtimeCache((name) => getHermesSessionsByEncodedName(name), 2, { maxSize: 50 });
@@ -5134,11 +5302,11 @@ var init_hermes_projects = __esm(() => {
5134
5302
 
5135
5303
  // lib/openclaw-sessions.ts
5136
5304
  import { readFile as readFile6 } from "node:fs/promises";
5137
- import { readdirSync as readdirSync3, statSync as statSync4 } from "node:fs";
5305
+ import { readdirSync as readdirSync4, statSync as statSync4 } from "node:fs";
5138
5306
  import { homedir as homedir12 } from "node:os";
5139
- import { join as join10 } from "node:path";
5307
+ import { join as join11 } from "node:path";
5140
5308
  function openclawHome() {
5141
- return process.env.OPENCLAW_HOME || join10(homedir12(), ".openclaw");
5309
+ return process.env.OPENCLAW_HOME || join11(homedir12(), ".openclaw");
5142
5310
  }
5143
5311
  function isPlainObject2(v) {
5144
5312
  return !!v && typeof v === "object" && !Array.isArray(v);
@@ -5251,20 +5419,27 @@ function openclawLinesToLogEntries(lines, source = "session") {
5251
5419
  entries.sort((a, b) => a.timestampMs - b.timestampMs);
5252
5420
  return entries;
5253
5421
  }
5422
+ function listOpenClawAgents() {
5423
+ try {
5424
+ return readdirSync4(join11(openclawHome(), "agents"), { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith(".")).map((d) => d.name).sort();
5425
+ } catch {
5426
+ return [];
5427
+ }
5428
+ }
5254
5429
  function listOpenClawTranscripts() {
5255
- const agentsDir = join10(openclawHome(), "agents");
5430
+ const agentsDir = join11(openclawHome(), "agents");
5256
5431
  const out = [];
5257
5432
  let agentIds;
5258
5433
  try {
5259
- agentIds = readdirSync3(agentsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
5434
+ agentIds = readdirSync4(agentsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
5260
5435
  } catch {
5261
5436
  return out;
5262
5437
  }
5263
5438
  for (const agentId of agentIds) {
5264
- const sessionsDir = join10(agentsDir, agentId, "sessions");
5439
+ const sessionsDir = join11(agentsDir, agentId, "sessions");
5265
5440
  let files;
5266
5441
  try {
5267
- files = readdirSync3(sessionsDir);
5442
+ files = readdirSync4(sessionsDir);
5268
5443
  } catch {
5269
5444
  continue;
5270
5445
  }
@@ -5274,7 +5449,7 @@ function listOpenClawTranscripts() {
5274
5449
  const sessionId = file.slice(0, -".jsonl".length);
5275
5450
  if (!OPENCLAW_SESSION_ID_RE.test(sessionId))
5276
5451
  continue;
5277
- const transcriptPath = join10(sessionsDir, file);
5452
+ const transcriptPath = join11(sessionsDir, file);
5278
5453
  try {
5279
5454
  const st = statSync4(transcriptPath);
5280
5455
  out.push({ agentId, sessionId, transcriptPath, mtimeMs: st.mtimeMs, sizeBytes: st.size });
@@ -5323,6 +5498,10 @@ var init_openclaw_sessions = __esm(() => {
5323
5498
  // lib/openclaw-projects.ts
5324
5499
  var exports_openclaw_projects = {};
5325
5500
  __export(exports_openclaw_projects, {
5501
+ parseOpenClawProjectName: () => parseOpenClawProjectName,
5502
+ openClawProjectPath: () => openClawProjectPath,
5503
+ openClawProjectNameCandidates: () => openClawProjectNameCandidates,
5504
+ openClawProjectName: () => openClawProjectName,
5326
5505
  getOpenClawSessionsByEncodedName: () => getOpenClawSessionsByEncodedName,
5327
5506
  getOpenClawSessions: () => getOpenClawSessions,
5328
5507
  getOpenClawProjects: () => getOpenClawProjects,
@@ -5331,13 +5510,13 @@ __export(exports_openclaw_projects, {
5331
5510
  getCachedOpenClawProjects: () => getCachedOpenClawProjects
5332
5511
  });
5333
5512
  import { readFileSync as readFileSync4 } from "node:fs";
5334
- import { join as join11 } from "node:path";
5513
+ import { join as join12 } from "node:path";
5335
5514
  function str(v) {
5336
5515
  return typeof v === "string" && v.length > 0 ? v : undefined;
5337
5516
  }
5338
5517
  function readSessionsIndex(agentId) {
5339
5518
  const out = new Map;
5340
- const indexPath = join11(openclawHome(), "agents", agentId, "sessions", "sessions.json");
5519
+ const indexPath = join12(openclawHome(), "agents", agentId, "sessions", "sessions.json");
5341
5520
  let raw;
5342
5521
  try {
5343
5522
  raw = JSON.parse(readFileSync4(indexPath, "utf-8"));
@@ -5383,6 +5562,7 @@ async function getOpenClawSessions() {
5383
5562
  label: meta?.label,
5384
5563
  chatType: meta?.chatType,
5385
5564
  chatId: meta?.chatId,
5565
+ transcriptPath: t.transcriptPath,
5386
5566
  mtimeMs: meta?.lastMs ?? t.mtimeMs,
5387
5567
  sizeBytes: t.sizeBytes
5388
5568
  });
@@ -5390,35 +5570,82 @@ async function getOpenClawSessions() {
5390
5570
  refs.sort((a, b) => b.mtimeMs - a.mtimeMs);
5391
5571
  return refs;
5392
5572
  }
5573
+ function openClawProjectName(agentId, channel) {
5574
+ return `openclaw-${agentId}-${channel}`;
5575
+ }
5576
+ function openClawProjectPath(agentId, channel) {
5577
+ return `openclaw:${agentId}:${channel}`;
5578
+ }
5579
+ function openClawProjectNameCandidates(name) {
5580
+ if (!name.startsWith("openclaw-"))
5581
+ return [];
5582
+ const rest = name.slice("openclaw-".length);
5583
+ if (!rest)
5584
+ return [];
5585
+ const out = [];
5586
+ const agents = listOpenClawAgents().sort((a, b) => b.length - a.length);
5587
+ for (const agentId of agents) {
5588
+ const prefix = `${agentId}-`;
5589
+ if (rest.startsWith(prefix) && rest.length > prefix.length) {
5590
+ out.push({ agentId, channel: rest.slice(prefix.length) });
5591
+ }
5592
+ }
5593
+ out.push({ agentId: null, channel: rest });
5594
+ return out;
5595
+ }
5596
+ function parseOpenClawProjectName(name) {
5597
+ return openClawProjectNameCandidates(name)[0] ?? null;
5598
+ }
5393
5599
  async function getOpenClawProjects() {
5394
5600
  const sessions = await getOpenClawSessions();
5395
- const latestByChannel = new Map;
5601
+ const groups = new Map;
5396
5602
  for (const s of sessions) {
5397
- latestByChannel.set(s.channel, Math.max(latestByChannel.get(s.channel) ?? 0, s.mtimeMs));
5603
+ const key = JSON.stringify([s.agentId, s.channel]);
5604
+ const prev = groups.get(key);
5605
+ if (prev) {
5606
+ prev.latest = Math.max(prev.latest, s.mtimeMs);
5607
+ prev.count += 1;
5608
+ } else {
5609
+ groups.set(key, { agentId: s.agentId, channel: s.channel, latest: s.mtimeMs, count: 1 });
5610
+ }
5398
5611
  }
5399
5612
  const out = [];
5400
- for (const [channel, latest] of latestByChannel) {
5613
+ for (const { agentId, channel, latest, count } of groups.values()) {
5401
5614
  const lastModified = new Date(latest);
5402
5615
  out.push({
5403
- name: `openclaw-${channel}`,
5404
- path: `openclaw:${channel}`,
5616
+ name: openClawProjectName(agentId, channel),
5617
+ path: openClawProjectPath(agentId, channel),
5405
5618
  isDirectory: true,
5406
5619
  lastModified,
5407
5620
  lastModifiedFormatted: formatDate(lastModified),
5408
- cli: ["openclaw"]
5621
+ cli: ["openclaw"],
5622
+ sessionCount: count
5409
5623
  });
5410
5624
  }
5411
5625
  out.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime());
5412
5626
  return out;
5413
5627
  }
5414
5628
  async function getOpenClawSessionsByEncodedName(name) {
5415
- if (!name.startsWith("openclaw-"))
5629
+ const candidates = openClawProjectNameCandidates(name);
5630
+ if (candidates.length === 0)
5416
5631
  return { cwd: null, sessions: [] };
5417
- const channel = name.slice("openclaw-".length);
5418
5632
  const sessions = await getOpenClawSessions();
5419
- const matched = sessions.filter((s) => s.channel === channel);
5633
+ const matching = (split) => sessions.filter((s) => s.channel === split.channel && (split.agentId === null || s.agentId === split.agentId));
5634
+ let chosen = candidates[0];
5635
+ let matched = matching(chosen);
5636
+ if (matched.length === 0) {
5637
+ for (const candidate of candidates.slice(1)) {
5638
+ const hits = matching(candidate);
5639
+ if (hits.length > 0) {
5640
+ chosen = candidate;
5641
+ matched = hits;
5642
+ break;
5643
+ }
5644
+ }
5645
+ }
5646
+ const { agentId, channel } = chosen;
5420
5647
  return {
5421
- cwd: `openclaw:${channel}`,
5648
+ cwd: agentId === null ? `openclaw:${channel}` : openClawProjectPath(agentId, channel),
5422
5649
  sessions: matched.map((s) => {
5423
5650
  const lastModified = new Date(s.mtimeMs);
5424
5651
  return {
@@ -5444,14 +5671,14 @@ var init_openclaw_projects = __esm(() => {
5444
5671
 
5445
5672
  // lib/factory-sessions.ts
5446
5673
  import { readFile as readFile7 } from "node:fs/promises";
5447
- import { readdirSync as readdirSync4, statSync as statSync5 } from "node:fs";
5674
+ import { readdirSync as readdirSync5, statSync as statSync5 } from "node:fs";
5448
5675
  import { homedir as homedir13 } from "node:os";
5449
- import { join as join12 } from "node:path";
5676
+ import { join as join13 } from "node:path";
5450
5677
  function factoryHome() {
5451
- return process.env.FACTORY_HOME || join12(homedir13(), ".factory");
5678
+ return process.env.FACTORY_HOME || join13(homedir13(), ".factory");
5452
5679
  }
5453
5680
  function factorySessionsRoot() {
5454
- return join12(factoryHome(), "sessions");
5681
+ return join13(factoryHome(), "sessions");
5455
5682
  }
5456
5683
  function isPlainObject3(v) {
5457
5684
  return !!v && typeof v === "object" && !Array.isArray(v);
@@ -5590,17 +5817,17 @@ function listFactoryTranscripts() {
5590
5817
  const out = [];
5591
5818
  let projectDirs;
5592
5819
  try {
5593
- projectDirs = readdirSync4(root, { withFileTypes: true }).filter((d) => d.isDirectory());
5820
+ projectDirs = readdirSync5(root, { withFileTypes: true }).filter((d) => d.isDirectory());
5594
5821
  } catch {
5595
5822
  return out;
5596
5823
  }
5597
5824
  for (const dir of projectDirs) {
5598
5825
  const projectName = dir.name;
5599
5826
  const cwd = decodeFolderName(projectName);
5600
- const projectPath = join12(root, projectName);
5827
+ const projectPath = join13(root, projectName);
5601
5828
  let files;
5602
5829
  try {
5603
- files = readdirSync4(projectPath);
5830
+ files = readdirSync5(projectPath);
5604
5831
  } catch {
5605
5832
  continue;
5606
5833
  }
@@ -5610,7 +5837,7 @@ function listFactoryTranscripts() {
5610
5837
  const sessionId = file.slice(0, -".jsonl".length);
5611
5838
  if (!FACTORY_SESSION_ID_RE.test(sessionId))
5612
5839
  continue;
5613
- const transcriptPath = join12(projectPath, file);
5840
+ const transcriptPath = join13(projectPath, file);
5614
5841
  try {
5615
5842
  const st = statSync5(transcriptPath);
5616
5843
  out.push({ projectName, cwd, sessionId, transcriptPath, mtimeMs: st.mtimeMs, sizeBytes: st.size });
@@ -5737,12 +5964,12 @@ var init_factory_projects = __esm(() => {
5737
5964
 
5738
5965
  // lib/devin-sessions.ts
5739
5966
  import { homedir as homedir14 } from "node:os";
5740
- import { join as join13 } from "node:path";
5967
+ import { join as join14 } from "node:path";
5741
5968
  function devinHome() {
5742
- return process.env.DEVIN_HOME || join13(homedir14(), ".local", "share", "devin");
5969
+ return process.env.DEVIN_HOME || join14(homedir14(), ".local", "share", "devin");
5743
5970
  }
5744
5971
  function devinDbPath() {
5745
- return process.env.DEVIN_DB_PATH || join13(devinHome(), "cli", "sessions.db");
5972
+ return process.env.DEVIN_DB_PATH || join14(devinHome(), "cli", "sessions.db");
5746
5973
  }
5747
5974
  function devinEpochToMs(value) {
5748
5975
  if (typeof value === "number" && Number.isFinite(value)) {
@@ -6039,17 +6266,17 @@ var init_devin_projects = __esm(() => {
6039
6266
 
6040
6267
  // lib/antigravity-sessions.ts
6041
6268
  import { readFile as readFile8 } from "node:fs/promises";
6042
- import { readdirSync as readdirSync5, statSync as statSync6 } from "node:fs";
6269
+ import { readdirSync as readdirSync6, statSync as statSync6 } from "node:fs";
6043
6270
  import { homedir as homedir15 } from "node:os";
6044
- import { join as join14 } from "node:path";
6271
+ import { join as join15 } from "node:path";
6045
6272
  function antigravityHome() {
6046
- return process.env.ANTIGRAVITY_HOME || join14(homedir15(), ".gemini", "antigravity-cli");
6273
+ return process.env.ANTIGRAVITY_HOME || join15(homedir15(), ".gemini", "antigravity-cli");
6047
6274
  }
6048
6275
  function antigravityBrainRoot() {
6049
- return join14(antigravityHome(), "brain");
6276
+ return join15(antigravityHome(), "brain");
6050
6277
  }
6051
6278
  function antigravityTranscriptRelPath() {
6052
- return join14(".system_generated", "logs", "transcript_full.jsonl");
6279
+ return join15(".system_generated", "logs", "transcript_full.jsonl");
6053
6280
  }
6054
6281
  function isPlainObject5(v) {
6055
6282
  return !!v && typeof v === "object" && !Array.isArray(v);
@@ -6164,7 +6391,7 @@ function listAntigravityTranscripts() {
6164
6391
  const out = [];
6165
6392
  let convoDirs;
6166
6393
  try {
6167
- convoDirs = readdirSync5(root, { withFileTypes: true }).filter((d) => d.isDirectory());
6394
+ convoDirs = readdirSync6(root, { withFileTypes: true }).filter((d) => d.isDirectory());
6168
6395
  } catch {
6169
6396
  return out;
6170
6397
  }
@@ -6172,7 +6399,7 @@ function listAntigravityTranscripts() {
6172
6399
  const conversationId = dir.name;
6173
6400
  if (!ANTIGRAVITY_CONVERSATION_ID_RE.test(conversationId))
6174
6401
  continue;
6175
- const transcriptPath = join14(root, conversationId, rel);
6402
+ const transcriptPath = join15(root, conversationId, rel);
6176
6403
  try {
6177
6404
  const st = statSync6(transcriptPath);
6178
6405
  if (!st.isFile())
@@ -6185,7 +6412,7 @@ function listAntigravityTranscripts() {
6185
6412
  function findAntigravityTranscript(conversationId) {
6186
6413
  if (!ANTIGRAVITY_CONVERSATION_ID_RE.test(conversationId))
6187
6414
  return null;
6188
- const transcriptPath = join14(antigravityBrainRoot(), conversationId, antigravityTranscriptRelPath());
6415
+ const transcriptPath = join15(antigravityBrainRoot(), conversationId, antigravityTranscriptRelPath());
6189
6416
  try {
6190
6417
  if (statSync6(transcriptPath).isFile())
6191
6418
  return transcriptPath;
@@ -6225,9 +6452,9 @@ __export(exports_antigravity_projects, {
6225
6452
  getAntigravityIndex: () => getAntigravityIndex,
6226
6453
  antigravitySummariesDbPath: () => antigravitySummariesDbPath
6227
6454
  });
6228
- import { join as join15 } from "node:path";
6455
+ import { join as join16 } from "node:path";
6229
6456
  function antigravitySummariesDbPath() {
6230
- return join15(antigravityHome(), "conversation_summaries.db");
6457
+ return join16(antigravityHome(), "conversation_summaries.db");
6231
6458
  }
6232
6459
  function parseWorkspaceCwd(raw) {
6233
6460
  if (!raw)
@@ -6371,15 +6598,15 @@ var init_antigravity_projects = __esm(() => {
6371
6598
 
6372
6599
  // lib/goose-sessions.ts
6373
6600
  import { homedir as homedir16 } from "node:os";
6374
- import { join as join16 } from "node:path";
6601
+ import { join as join17 } from "node:path";
6375
6602
  function gooseHome() {
6376
6603
  if (process.env.GOOSE_HOME)
6377
6604
  return process.env.GOOSE_HOME;
6378
6605
  const xdg = process.env.XDG_DATA_HOME;
6379
- return join16(xdg && xdg.length > 0 ? xdg : join16(homedir16(), ".local", "share"), "goose");
6606
+ return join17(xdg && xdg.length > 0 ? xdg : join17(homedir16(), ".local", "share"), "goose");
6380
6607
  }
6381
6608
  function gooseDbPath() {
6382
- return process.env.GOOSE_DB_PATH || join16(gooseHome(), "sessions", "sessions.db");
6609
+ return process.env.GOOSE_DB_PATH || join17(gooseHome(), "sessions", "sessions.db");
6383
6610
  }
6384
6611
  function gooseTimestampToMs(value) {
6385
6612
  if (typeof value === "number" && Number.isFinite(value)) {
@@ -6647,7 +6874,7 @@ var init_goose_projects = __esm(() => {
6647
6874
 
6648
6875
  // lib/projects.ts
6649
6876
  import { readdir as readdir5, stat as stat5 } from "node:fs/promises";
6650
- import { join as join17, resolve as resolve5, sep } from "node:path";
6877
+ import { join as join18, resolve as resolve6, sep } from "node:path";
6651
6878
  async function getMtime(path3, label) {
6652
6879
  try {
6653
6880
  return (await stat5(path3)).mtime;
@@ -6673,7 +6900,7 @@ async function getClaudeProjectFolders() {
6673
6900
  if (!entries)
6674
6901
  return [];
6675
6902
  const settled = await batchAll(entries.filter((entry) => entry.isDirectory()).map((entry) => async () => {
6676
- const folderPath = join17(projectsPath, entry.name);
6903
+ const folderPath = join18(projectsPath, entry.name);
6677
6904
  const mtime = await getMtime(folderPath, entry.name);
6678
6905
  return {
6679
6906
  name: entry.name,
@@ -6710,7 +6937,8 @@ function mergeProjectFolders(...sources) {
6710
6937
  ...existing,
6711
6938
  cli: mergedCli,
6712
6939
  lastModified: newer.lastModified,
6713
- lastModifiedFormatted: newer.lastModifiedFormatted
6940
+ lastModifiedFormatted: newer.lastModifiedFormatted,
6941
+ sessionCount: existing.sessionCount === undefined && f.sessionCount === undefined ? undefined : (existing.sessionCount ?? 0) + (f.sessionCount ?? 0)
6714
6942
  });
6715
6943
  }
6716
6944
  }
@@ -6798,8 +7026,8 @@ function resolveProjectPath(projectName) {
6798
7026
  throw new RangeError("Empty project name");
6799
7027
  if (/^[/\\]/.test(projectName))
6800
7028
  throw new RangeError("Absolute project name");
6801
- const projectsPath = resolve5(getClaudeProjectsPath());
6802
- const candidate = resolve5(join17(projectsPath, projectName));
7029
+ const projectsPath = resolve6(getClaudeProjectsPath());
7030
+ const candidate = resolve6(join18(projectsPath, projectName));
6803
7031
  if (!candidate.startsWith(projectsPath + sep)) {
6804
7032
  throw new RangeError("Project path escapes root");
6805
7033
  }
@@ -6817,7 +7045,7 @@ async function getSessionFiles(projectPath) {
6817
7045
  return [];
6818
7046
  const jsonlEntries = entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl") && extractSessionId2(entry.name));
6819
7047
  const settled = await batchAll(jsonlEntries.map((entry) => async () => {
6820
- const filePath = join17(projectPath, entry.name);
7048
+ const filePath = join18(projectPath, entry.name);
6821
7049
  const mtime = await getMtime(filePath, entry.name);
6822
7050
  return {
6823
7051
  name: entry.name,
@@ -6846,13 +7074,13 @@ var init_projects = __esm(() => {
6846
7074
 
6847
7075
  // lib/resolve-subagent-path.ts
6848
7076
  import { access as access2 } from "fs/promises";
6849
- import { join as join18, relative as relative2 } from "path";
7077
+ import { join as join19, relative as relative2 } from "path";
6850
7078
  async function resolveSubagentPath(projectsPath, projectName, sessionId, agentId) {
6851
7079
  const fileName = `agent-${agentId}.jsonl`;
6852
7080
  const candidatePaths = [
6853
- join18(projectsPath, projectName, fileName),
6854
- join18(projectsPath, projectName, sessionId, fileName),
6855
- join18(projectsPath, projectName, sessionId, "subagents", fileName)
7081
+ join19(projectsPath, projectName, fileName),
7082
+ join19(projectsPath, projectName, sessionId, fileName),
7083
+ join19(projectsPath, projectName, sessionId, "subagents", fileName)
6856
7084
  ];
6857
7085
  for (const candidatePath of candidatePaths) {
6858
7086
  if (relative2(projectsPath, candidatePath).startsWith("..")) {
@@ -6874,7 +7102,7 @@ var init_resolve_subagent_path = () => {};
6874
7102
 
6875
7103
  // lib/log-entries.ts
6876
7104
  import { readFile as readFile9 } from "fs/promises";
6877
- import { join as join19 } from "path";
7105
+ import { join as join20 } from "path";
6878
7106
  function formatTimestamp(date) {
6879
7107
  const base = formatDate(date);
6880
7108
  const ms = date.getMilliseconds().toString().padStart(3, "0");
@@ -7072,7 +7300,7 @@ async function parseLogContent(fileContent, source = "session") {
7072
7300
  async function parseSessionLog(projectName, sessionId) {
7073
7301
  const projectDir = resolveProjectPath(projectName);
7074
7302
  const projectsPath = getClaudeProjectsPath();
7075
- const filePath = join19(projectDir, `${sessionId}.jsonl`);
7303
+ const filePath = join20(projectDir, `${sessionId}.jsonl`);
7076
7304
  const fileContent = await readFile9(filePath, "utf-8");
7077
7305
  const { entries: sessionEntries, rawLines: sessionRawLines, subagentIds } = await parseFileContent(fileContent, "session");
7078
7306
  if (subagentIds.length === 0) {
@@ -7109,9 +7337,9 @@ var init_log_entries = __esm(() => {
7109
7337
  });
7110
7338
 
7111
7339
  // lib/codex-sessions.ts
7112
- import { readFileSync as readFileSync5, readdirSync as readdirSync6, existsSync as existsSync6, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, statSync as statSync7 } from "node:fs";
7340
+ import { readFileSync as readFileSync5, readdirSync as readdirSync7, existsSync as existsSync6, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, statSync as statSync7 } from "node:fs";
7113
7341
  import { readFile as readFile10 } from "node:fs/promises";
7114
- import { dirname as dirname3, join as join20 } from "node:path";
7342
+ import { dirname as dirname4, join as join21 } from "node:path";
7115
7343
  import { homedir as homedir17 } from "node:os";
7116
7344
  function readCache() {
7117
7345
  try {
@@ -7124,7 +7352,7 @@ function readCache() {
7124
7352
  }
7125
7353
  function writeCacheEntry(sessionId, path3) {
7126
7354
  try {
7127
- mkdirSync4(dirname3(CACHE_PATH), { recursive: true });
7355
+ mkdirSync4(dirname4(CACHE_PATH), { recursive: true });
7128
7356
  const cache = readCache();
7129
7357
  cache[sessionId] = path3;
7130
7358
  writeFileSync3(CACHE_PATH, JSON.stringify(cache), "utf-8");
@@ -7132,9 +7360,9 @@ function writeCacheEntry(sessionId, path3) {
7132
7360
  }
7133
7361
  function dirSearch(dir, sessionId) {
7134
7362
  try {
7135
- for (const f of readdirSync6(dir, { withFileTypes: true })) {
7363
+ for (const f of readdirSync7(dir, { withFileTypes: true })) {
7136
7364
  if (f.isFile() && f.name.includes(sessionId) && f.name.endsWith(".jsonl")) {
7137
- return join20(dir, f.name);
7365
+ return join21(dir, f.name);
7138
7366
  }
7139
7367
  }
7140
7368
  } catch {}
@@ -7145,14 +7373,14 @@ function findCodexTranscript(sessionId) {
7145
7373
  const cached = cache[sessionId];
7146
7374
  if (cached && existsSync6(cached))
7147
7375
  return cached;
7148
- const root = join20(homedir17(), ".codex", "sessions");
7376
+ const root = join21(homedir17(), ".codex", "sessions");
7149
7377
  const today = new Date;
7150
7378
  const yesterday = new Date(today.getTime() - 24 * 60 * 60 * 1000);
7151
7379
  const datedDirs = [today, yesterday].map((d) => {
7152
7380
  const y = String(d.getUTCFullYear());
7153
7381
  const m = String(d.getUTCMonth() + 1).padStart(2, "0");
7154
7382
  const day = String(d.getUTCDate()).padStart(2, "0");
7155
- return join20(root, y, m, day);
7383
+ return join21(root, y, m, day);
7156
7384
  });
7157
7385
  for (const dir of datedDirs) {
7158
7386
  const hit = dirSearch(dir, sessionId);
@@ -7162,16 +7390,16 @@ function findCodexTranscript(sessionId) {
7162
7390
  }
7163
7391
  }
7164
7392
  try {
7165
- for (const y of readdirSync6(root, { withFileTypes: true })) {
7393
+ for (const y of readdirSync7(root, { withFileTypes: true })) {
7166
7394
  if (!y.isDirectory())
7167
7395
  continue;
7168
- for (const m of readdirSync6(join20(root, y.name), { withFileTypes: true })) {
7396
+ for (const m of readdirSync7(join21(root, y.name), { withFileTypes: true })) {
7169
7397
  if (!m.isDirectory())
7170
7398
  continue;
7171
- for (const d of readdirSync6(join20(root, y.name, m.name), { withFileTypes: true })) {
7399
+ for (const d of readdirSync7(join21(root, y.name, m.name), { withFileTypes: true })) {
7172
7400
  if (!d.isDirectory())
7173
7401
  continue;
7174
- const hit = dirSearch(join20(root, y.name, m.name, d.name), sessionId);
7402
+ const hit = dirSearch(join21(root, y.name, m.name, d.name), sessionId);
7175
7403
  if (hit) {
7176
7404
  writeCacheEntry(sessionId, hit);
7177
7405
  return hit;
@@ -7391,7 +7619,7 @@ async function getCodexSessionLog(sessionId) {
7391
7619
  var CACHE_PATH, getCachedCodexSessionLog;
7392
7620
  var init_codex_sessions = __esm(() => {
7393
7621
  init_log_entries();
7394
- CACHE_PATH = join20(homedir17(), ".failproofai", "cache", "codex-session-paths.json");
7622
+ CACHE_PATH = join21(homedir17(), ".failproofai", "cache", "codex-session-paths.json");
7395
7623
  getCachedCodexSessionLog = runtimeCache((sessionId) => getCodexSessionLog(sessionId), 60, { maxSize: 50 });
7396
7624
  });
7397
7625
 
@@ -7436,21 +7664,21 @@ var init_resolve_permission_mode = __esm(() => {
7436
7664
  });
7437
7665
 
7438
7666
  // lib/copilot-sessions.ts
7439
- import { readFileSync as readFileSync7, readdirSync as readdirSync7, existsSync as existsSync7, statSync as statSync8 } from "node:fs";
7667
+ import { readFileSync as readFileSync7, readdirSync as readdirSync8, existsSync as existsSync7, statSync as statSync8 } from "node:fs";
7440
7668
  import { readFile as readFile11 } from "node:fs/promises";
7441
- import { join as join21, resolve as resolve6, sep as sep2 } from "node:path";
7669
+ import { join as join22, resolve as resolve7, sep as sep2 } from "node:path";
7442
7670
  import { homedir as homedir18 } from "node:os";
7443
7671
  function getCopilotHome() {
7444
- return process.env.COPILOT_HOME || join21(homedir18(), ".copilot");
7672
+ return process.env.COPILOT_HOME || join22(homedir18(), ".copilot");
7445
7673
  }
7446
7674
  function getCopilotSessionStateRoot2() {
7447
- return join21(getCopilotHome(), "session-state");
7675
+ return join22(getCopilotHome(), "session-state");
7448
7676
  }
7449
7677
  function getCopilotSessionDir(sessionId) {
7450
7678
  if (!sessionId)
7451
7679
  return null;
7452
- const root = resolve6(getCopilotSessionStateRoot2());
7453
- const candidate = resolve6(root, sessionId);
7680
+ const root = resolve7(getCopilotSessionStateRoot2());
7681
+ const candidate = resolve7(root, sessionId);
7454
7682
  if (candidate === root || !candidate.startsWith(`${root}${sep2}`))
7455
7683
  return null;
7456
7684
  return candidate;
@@ -7459,7 +7687,7 @@ function resolveSessionFile(sessionId, filename) {
7459
7687
  const dir = getCopilotSessionDir(sessionId);
7460
7688
  if (!dir)
7461
7689
  return null;
7462
- return join21(dir, filename);
7690
+ return join22(dir, filename);
7463
7691
  }
7464
7692
  function findCopilotTranscript(sessionId) {
7465
7693
  const candidate = resolveSessionFile(sessionId, "events.jsonl");
@@ -7653,35 +7881,35 @@ var init_copilot_sessions = __esm(() => {
7653
7881
  });
7654
7882
 
7655
7883
  // lib/cursor-sessions.ts
7656
- import { readFileSync as readFileSync8, readdirSync as readdirSync8, existsSync as existsSync8, statSync as statSync9 } from "node:fs";
7884
+ import { readFileSync as readFileSync8, readdirSync as readdirSync9, existsSync as existsSync8, statSync as statSync9 } from "node:fs";
7657
7885
  import { readFile as readFile12 } from "node:fs/promises";
7658
- import { basename as basename2, join as join22, resolve as resolve7, sep as sep3 } from "node:path";
7886
+ import { basename as basename3, join as join23, resolve as resolve8, sep as sep3 } from "node:path";
7659
7887
  import { homedir as homedir19 } from "node:os";
7660
7888
  function getCursorHome2() {
7661
- return process.env.CURSOR_HOME || join22(homedir19(), ".cursor");
7889
+ return process.env.CURSOR_HOME || join23(homedir19(), ".cursor");
7662
7890
  }
7663
7891
  function getCursorSessionDir(sessionId) {
7664
7892
  if (!sessionId)
7665
7893
  return null;
7666
- const home = resolve7(getCursorHome2());
7667
- const projectsRoot = resolve7(home, NEW_PROJECTS_DIR2);
7894
+ const home = resolve8(getCursorHome2());
7895
+ const projectsRoot = resolve8(home, NEW_PROJECTS_DIR2);
7668
7896
  let projectEntries = [];
7669
7897
  try {
7670
- projectEntries = readdirSync8(projectsRoot, { withFileTypes: true });
7898
+ projectEntries = readdirSync9(projectsRoot, { withFileTypes: true });
7671
7899
  } catch {}
7672
7900
  for (const entry of projectEntries) {
7673
7901
  if (!entry.isDirectory())
7674
7902
  continue;
7675
- const candidate = resolve7(projectsRoot, entry.name, NEW_AGENT_TRANSCRIPTS_DIR2, sessionId);
7676
- const transcriptRoot = resolve7(projectsRoot, entry.name, NEW_AGENT_TRANSCRIPTS_DIR2);
7903
+ const candidate = resolve8(projectsRoot, entry.name, NEW_AGENT_TRANSCRIPTS_DIR2, sessionId);
7904
+ const transcriptRoot = resolve8(projectsRoot, entry.name, NEW_AGENT_TRANSCRIPTS_DIR2);
7677
7905
  if (candidate === transcriptRoot || !candidate.startsWith(`${transcriptRoot}${sep3}`))
7678
7906
  continue;
7679
7907
  if (existsSync8(candidate))
7680
7908
  return candidate;
7681
7909
  }
7682
7910
  for (const sub of LEGACY_SESSION_ROOT_CANDIDATES2) {
7683
- const root = resolve7(home, sub);
7684
- const candidate = resolve7(root, sessionId);
7911
+ const root = resolve8(home, sub);
7912
+ const candidate = resolve8(root, sessionId);
7685
7913
  if (candidate === root || !candidate.startsWith(`${root}${sep3}`))
7686
7914
  continue;
7687
7915
  if (existsSync8(candidate))
@@ -7693,11 +7921,11 @@ function findCursorTranscript(sessionId) {
7693
7921
  const dir = getCursorSessionDir(sessionId);
7694
7922
  if (!dir)
7695
7923
  return null;
7696
- const newCandidate = join22(dir, `${basename2(dir)}.jsonl`);
7924
+ const newCandidate = join23(dir, `${basename3(dir)}.jsonl`);
7697
7925
  if (existsSync8(newCandidate))
7698
7926
  return newCandidate;
7699
7927
  for (const name of LEGACY_TRANSCRIPT_FILE_CANDIDATES2) {
7700
- const candidate = join22(dir, name);
7928
+ const candidate = join23(dir, name);
7701
7929
  if (existsSync8(candidate))
7702
7930
  return candidate;
7703
7931
  }
@@ -7909,12 +8137,12 @@ var init_cursor_sessions = __esm(() => {
7909
8137
  });
7910
8138
 
7911
8139
  // lib/pi-sessions.ts
7912
- import { readFileSync as readFileSync9, readdirSync as readdirSync9, existsSync as existsSync9, statSync as statSync10 } from "node:fs";
8140
+ import { readFileSync as readFileSync9, readdirSync as readdirSync10, existsSync as existsSync9, statSync as statSync10 } from "node:fs";
7913
8141
  import { readFile as readFile13 } from "node:fs/promises";
7914
- import { join as join23, resolve as resolve8, sep as sep4 } from "node:path";
8142
+ import { join as join24, resolve as resolve9, sep as sep4 } from "node:path";
7915
8143
  import { homedir as homedir20 } from "node:os";
7916
8144
  function getPiSessionStateRoot() {
7917
- return process.env.PI_SESSIONS_DIR || join23(homedir20(), ".pi", "agent", "sessions");
8145
+ return process.env.PI_SESSIONS_DIR || join24(homedir20(), ".pi", "agent", "sessions");
7918
8146
  }
7919
8147
  function isSafeSessionId(sessionId) {
7920
8148
  return UUID_RE.test(sessionId);
@@ -7922,20 +8150,20 @@ function isSafeSessionId(sessionId) {
7922
8150
  function findPiTranscript(sessionId) {
7923
8151
  if (!isSafeSessionId(sessionId))
7924
8152
  return null;
7925
- const root = resolve8(getPiSessionStateRoot());
8153
+ const root = resolve9(getPiSessionStateRoot());
7926
8154
  let cwdDirs;
7927
8155
  try {
7928
- cwdDirs = readdirSync9(root);
8156
+ cwdDirs = readdirSync10(root);
7929
8157
  } catch {
7930
8158
  return null;
7931
8159
  }
7932
8160
  for (const cwdDir of cwdDirs) {
7933
- const cwdPath = resolve8(root, cwdDir);
8161
+ const cwdPath = resolve9(root, cwdDir);
7934
8162
  if (!cwdPath.startsWith(`${root}${sep4}`))
7935
8163
  continue;
7936
8164
  let files;
7937
8165
  try {
7938
- files = readdirSync9(cwdPath);
8166
+ files = readdirSync10(cwdPath);
7939
8167
  } catch {
7940
8168
  continue;
7941
8169
  }
@@ -7943,7 +8171,7 @@ function findPiTranscript(sessionId) {
7943
8171
  const m = SESSION_FILE_RE2.exec(f);
7944
8172
  if (!m || m[1].toLowerCase() !== sessionId.toLowerCase())
7945
8173
  continue;
7946
- const candidate = resolve8(cwdPath, f);
8174
+ const candidate = resolve9(cwdPath, f);
7947
8175
  if (!candidate.startsWith(`${cwdPath}${sep4}`))
7948
8176
  continue;
7949
8177
  if (existsSync9(candidate))
@@ -8187,7 +8415,7 @@ async function handleHookEvent(eventType, cli = "claude") {
8187
8415
  let payload = "";
8188
8416
  let stdinOversized = false;
8189
8417
  try {
8190
- payload = await new Promise((resolve9, reject) => {
8418
+ payload = await new Promise((resolve10, reject) => {
8191
8419
  const chunks = [];
8192
8420
  let totalBytes = 0;
8193
8421
  process.stdin.setEncoding("utf8");
@@ -8197,15 +8425,15 @@ async function handleHookEvent(eventType, cli = "claude") {
8197
8425
  hookLogWarn(`stdin payload exceeds 1 MB for ${eventType}, discarding`);
8198
8426
  stdinOversized = true;
8199
8427
  process.stdin.destroy();
8200
- resolve9("");
8428
+ resolve10("");
8201
8429
  return;
8202
8430
  }
8203
8431
  chunks.push(chunk);
8204
8432
  });
8205
- process.stdin.on("end", () => resolve9(chunks.join("")));
8433
+ process.stdin.on("end", () => resolve10(chunks.join("")));
8206
8434
  process.stdin.on("error", reject);
8207
8435
  if (process.stdin.readableEnded)
8208
- resolve9("");
8436
+ resolve10("");
8209
8437
  });
8210
8438
  } catch (err) {
8211
8439
  hookLogWarn(`stdin read failed for ${eventType}`);
@@ -8356,6 +8584,7 @@ async function handleHookEvent(eventType, cli = "claude") {
8356
8584
  if (result.stderr) {
8357
8585
  process.stderr.write(result.stderr);
8358
8586
  }
8587
+ const matchedPolicies = getPoliciesForEvent(canonicalEventType, parsed.tool_name).map((p) => p.name);
8359
8588
  const activityEntry = {
8360
8589
  timestamp: Date.now(),
8361
8590
  eventType: canonicalEventType,
@@ -8363,6 +8592,7 @@ async function handleHookEvent(eventType, cli = "claude") {
8363
8592
  toolName: parsed.tool_name ?? null,
8364
8593
  policyName: result.policyName,
8365
8594
  policyNames: result.policyNames,
8595
+ matchedPolicies,
8366
8596
  decision: result.decision,
8367
8597
  reason: result.reason,
8368
8598
  durationMs,
@@ -8424,13 +8654,13 @@ import { createHmac, randomUUID } from "node:crypto";
8424
8654
  import { execSync as execSync4 } from "node:child_process";
8425
8655
  import { readFileSync as readFileSync10, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5 } from "node:fs";
8426
8656
  import { homedir as homedir21, platform, arch, hostname, cpus } from "node:os";
8427
- import { join as join24 } from "node:path";
8657
+ import { join as join25 } from "node:path";
8428
8658
  function hashToId3(raw) {
8429
8659
  return createHmac("sha256", NAMESPACE3).update(raw).digest("hex");
8430
8660
  }
8431
8661
  function getInstanceId3() {
8432
- const idDir = join24(homedir21(), ".failproofai");
8433
- const idFile = join24(idDir, "instance-id");
8662
+ const idDir = join25(homedir21(), ".failproofai");
8663
+ const idFile = join25(idDir, "instance-id");
8434
8664
  try {
8435
8665
  const existing = readFileSync10(idFile, "utf-8").trim();
8436
8666
  if (existing)
@@ -8511,14 +8741,14 @@ __export(exports_install_check, {
8511
8741
  checkHooks: () => checkHooks
8512
8742
  });
8513
8743
  import { existsSync as existsSync10, readFileSync as readFileSync11, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6 } from "node:fs";
8514
- import { resolve as resolve9 } from "node:path";
8744
+ import { resolve as resolve10 } from "node:path";
8515
8745
  import { platform as platform2, arch as arch2, release, homedir as homedir22, hostname as hostname2 } from "node:os";
8516
8746
  import { createHmac as createHmac2 } from "node:crypto";
8517
8747
  function hashToId4(raw) {
8518
8748
  return createHmac2("sha256", NAMESPACE4).update(raw).digest("hex");
8519
8749
  }
8520
8750
  function lastVersionPath() {
8521
- return resolve9(homedir22(), ".failproofai", "last-version");
8751
+ return resolve10(homedir22(), ".failproofai", "last-version");
8522
8752
  }
8523
8753
  function compareSemver(a, b) {
8524
8754
  const parse = (v) => {
@@ -8565,7 +8795,7 @@ function compareSemver(a, b) {
8565
8795
  return 0;
8566
8796
  }
8567
8797
  function checkHooks() {
8568
- const hooksConfigPath = resolve9(homedir22(), ".failproofai", "policies-config.json");
8798
+ const hooksConfigPath = resolve10(homedir22(), ".failproofai", "policies-config.json");
8569
8799
  if (!existsSync10(hooksConfigPath)) {
8570
8800
  return { configured: false, registered: false, policyCount: 0 };
8571
8801
  }
@@ -8579,7 +8809,7 @@ function checkHooks() {
8579
8809
  return { configured: false, registered: false, policyCount: 0 };
8580
8810
  }
8581
8811
  const policyCount = config.enabledPolicies.length;
8582
- const settingsPath = resolve9(homedir22(), ".claude", "settings.json");
8812
+ const settingsPath = resolve10(homedir22(), ".claude", "settings.json");
8583
8813
  if (!existsSync10(settingsPath))
8584
8814
  return { configured: true, registered: false, policyCount };
8585
8815
  let settings;
@@ -8644,7 +8874,7 @@ async function maybeReportInstall(version3) {
8644
8874
  enabled_policy_count: hooks.policyCount
8645
8875
  }, { version: version3, timeoutMs: REPORT_TIMEOUT_MS }));
8646
8876
  try {
8647
- mkdirSync6(resolve9(homedir22(), ".failproofai"), { recursive: true });
8877
+ mkdirSync6(resolve10(homedir22(), ".failproofai"), { recursive: true });
8648
8878
  writeFileSync5(versionFile, version3, "utf8");
8649
8879
  } catch {}
8650
8880
  await Promise.all(events.map((p) => p.catch(() => {})));
@@ -15648,7 +15878,7 @@ var init_dist = __esm(() => {
15648
15878
  // src/hooks/integrations.ts
15649
15879
  import { execSync as execSync5 } from "node:child_process";
15650
15880
  import { readFileSync as readFileSync12, writeFileSync as writeFileSync6, existsSync as existsSync11, mkdirSync as mkdirSync7, unlinkSync as unlinkSync2 } from "node:fs";
15651
- import { resolve as resolve10, dirname as dirname4 } from "node:path";
15881
+ import { resolve as resolve11, dirname as dirname5 } from "node:path";
15652
15882
  import { fileURLToPath } from "node:url";
15653
15883
  import { homedir as homedir23 } from "node:os";
15654
15884
  function readJsonFile(path3) {
@@ -15658,7 +15888,7 @@ function readJsonFile(path3) {
15658
15888
  return JSON.parse(raw);
15659
15889
  }
15660
15890
  function writeJsonFile(path3, data) {
15661
- mkdirSync7(dirname4(path3), { recursive: true });
15891
+ mkdirSync7(dirname5(path3), { recursive: true });
15662
15892
  writeFileSync6(path3, JSON.stringify(data, null, 2) + `
15663
15893
  `, "utf8");
15664
15894
  }
@@ -15670,7 +15900,7 @@ function readYamlDoc(path3) {
15670
15900
  }
15671
15901
  }
15672
15902
  function writeYamlDoc(path3, doc) {
15673
- mkdirSync7(dirname4(path3), { recursive: true });
15903
+ mkdirSync7(dirname5(path3), { recursive: true });
15674
15904
  writeFileSync6(path3, doc.toString(), "utf8");
15675
15905
  }
15676
15906
  function isMarkedHook(hook) {
@@ -15698,6 +15928,10 @@ function binaryExists(name) {
15698
15928
  return false;
15699
15929
  }
15700
15930
  }
15931
+ function settingsPathsFor(integration, scope, cwd) {
15932
+ const paths = integration.getSettingsPaths?.(scope, cwd);
15933
+ return paths && paths.length > 0 ? paths : [integration.getSettingsPath(scope, cwd)];
15934
+ }
15701
15935
  function isMarkedCopilotHook(hook) {
15702
15936
  if (hook[FAILPROOFAI_HOOK_MARKER] === true)
15703
15937
  return true;
@@ -15710,7 +15944,7 @@ function isMarkedCopilotHook(hook) {
15710
15944
  return false;
15711
15945
  }
15712
15946
  function opencodePluginFilePath(settingsPath) {
15713
- return resolve10(dirname4(settingsPath), "plugins", "failproofai.mjs");
15947
+ return resolve11(dirname5(settingsPath), "plugins", "failproofai.mjs");
15714
15948
  }
15715
15949
  function buildOpenCodePluginShim(binaryPath, scope) {
15716
15950
  const useNpx = scope === "project";
@@ -15925,8 +16159,8 @@ export default async function failproofaiPlugin({ client, directory }) {
15925
16159
  function getPiExtensionPath() {
15926
16160
  const fromEnv = process.env.FAILPROOFAI_PACKAGE_ROOT;
15927
16161
  if (fromEnv)
15928
- return resolve10(fromEnv, "pi-extension");
15929
- return resolve10(fileURLToPath(import.meta.url), "..", "..", "..", "pi-extension");
16162
+ return resolve11(fromEnv, "pi-extension");
16163
+ return resolve11(fileURLToPath(import.meta.url), "..", "..", "..", "pi-extension");
15930
16164
  }
15931
16165
  function isFailproofaiPiEntry(source) {
15932
16166
  if (typeof source !== "string")
@@ -15937,19 +16171,38 @@ function isFailproofaiPiEntry(source) {
15937
16171
  }
15938
16172
  function makePiProjectRelativeEntry(extPath) {
15939
16173
  const cwd = process.cwd();
15940
- const cwdResolved = resolve10(cwd);
15941
- const extResolved = resolve10(extPath);
16174
+ const cwdResolved = resolve11(cwd);
16175
+ const extResolved = resolve11(extPath);
15942
16176
  if (extResolved.startsWith(cwdResolved + "/") || extResolved === cwdResolved) {
15943
16177
  const fromSettingsDir = "../" + extResolved.slice(cwdResolved.length + 1);
15944
16178
  return fromSettingsDir;
15945
16179
  }
15946
16180
  return extResolved;
15947
16181
  }
16182
+ function hermesConfigHasHooks(settingsPath) {
16183
+ if (!existsSync11(settingsPath))
16184
+ return false;
16185
+ try {
16186
+ const doc = readYamlDoc(settingsPath);
16187
+ const js = doc.toJS() ?? {};
16188
+ const hooks = js.hooks;
16189
+ if (!hooks || typeof hooks !== "object")
16190
+ return false;
16191
+ for (const entries of Object.values(hooks)) {
16192
+ if (Array.isArray(entries) && entries.some((h) => isMarkedHook(h)))
16193
+ return true;
16194
+ }
16195
+ } catch {}
16196
+ return false;
16197
+ }
16198
+ function unhookedHermesProfiles() {
16199
+ return listHermesProfiles().filter((p) => existsSync11(p.home)).filter((p) => !hermesConfigHasHooks(resolve11(p.home, "config.yaml"))).map((p) => p.name);
16200
+ }
15948
16201
  function getOpenClawPluginPath() {
15949
16202
  const fromEnv = process.env.FAILPROOFAI_PACKAGE_ROOT;
15950
16203
  if (fromEnv)
15951
- return resolve10(fromEnv, "openclaw-plugin");
15952
- return resolve10(fileURLToPath(import.meta.url), "..", "..", "..", "openclaw-plugin");
16204
+ return resolve11(fromEnv, "openclaw-plugin");
16205
+ return resolve11(fileURLToPath(import.meta.url), "..", "..", "..", "openclaw-plugin");
15953
16206
  }
15954
16207
  function isFailproofaiOpenClawPath(p) {
15955
16208
  if (typeof p !== "string")
@@ -15978,21 +16231,22 @@ function detectInstalledClis() {
15978
16231
  var claudeCode, codex, copilot, cursor, OPENCODE_PLUGIN_REL_PATH = "./plugins/failproofai.mjs", opencode, pi, hermes, OPENCLAW_PLUGIN_ID = "failproofai", openclaw, factory, devin, ANTIGRAVITY_HOOK_NAME = "failproofai", ANTIGRAVITY_TOOL_EVENTS, antigravity, goose, INTEGRATIONS;
15979
16232
  var init_integrations = __esm(() => {
15980
16233
  init_dist();
16234
+ init_hermes_profiles();
15981
16235
  init_types();
15982
16236
  claudeCode = {
15983
16237
  id: "claude",
15984
16238
  displayName: "Claude Code",
15985
16239
  scopes: HOOK_SCOPES,
15986
- eventTypes: HOOK_EVENT_TYPES,
16240
+ eventTypes: CLAUDE_INSTALL_EVENT_TYPES,
15987
16241
  getSettingsPath(scope, cwd) {
15988
- const base = cwd ? resolve10(cwd) : process.cwd();
16242
+ const base = cwd ? resolve11(cwd) : process.cwd();
15989
16243
  switch (scope) {
15990
16244
  case "user":
15991
- return resolve10(homedir23(), ".claude", "settings.json");
16245
+ return resolve11(homedir23(), ".claude", "settings.json");
15992
16246
  case "project":
15993
- return resolve10(base, ".claude", "settings.json");
16247
+ return resolve11(base, ".claude", "settings.json");
15994
16248
  case "local":
15995
- return resolve10(base, ".claude", "settings.local.json");
16249
+ return resolve11(base, ".claude", "settings.local.json");
15996
16250
  }
15997
16251
  },
15998
16252
  readSettings(settingsPath) {
@@ -16015,7 +16269,31 @@ var init_integrations = __esm(() => {
16015
16269
  const s = settings;
16016
16270
  if (!s.hooks)
16017
16271
  s.hooks = {};
16018
- for (const eventType of HOOK_EVENT_TYPES) {
16272
+ const installed = new Set(CLAUDE_INSTALL_EVENT_TYPES);
16273
+ for (const eventType of Object.keys(s.hooks)) {
16274
+ if (installed.has(eventType))
16275
+ continue;
16276
+ const matchers = s.hooks[eventType];
16277
+ if (!Array.isArray(matchers))
16278
+ continue;
16279
+ const kept = [];
16280
+ for (const matcher of matchers) {
16281
+ if (!matcher || !Array.isArray(matcher.hooks)) {
16282
+ if (matcher)
16283
+ kept.push(matcher);
16284
+ continue;
16285
+ }
16286
+ const before = matcher.hooks.length;
16287
+ matcher.hooks = matcher.hooks.filter((h) => !isMarkedHook(h));
16288
+ const weEmptiedIt = matcher.hooks.length === 0 && before > 0;
16289
+ if (!weEmptiedIt)
16290
+ kept.push(matcher);
16291
+ }
16292
+ s.hooks[eventType] = kept;
16293
+ if (kept.length === 0)
16294
+ delete s.hooks[eventType];
16295
+ }
16296
+ for (const eventType of CLAUDE_INSTALL_EVENT_TYPES) {
16019
16297
  const hookEntry = this.buildHookEntry(binaryPath, eventType, scope);
16020
16298
  if (!s.hooks[eventType])
16021
16299
  s.hooks[eventType] = [];
@@ -16093,14 +16371,14 @@ var init_integrations = __esm(() => {
16093
16371
  scopes: CODEX_HOOK_SCOPES,
16094
16372
  eventTypes: CODEX_HOOK_EVENT_TYPES,
16095
16373
  getSettingsPath(scope, cwd) {
16096
- const base = cwd ? resolve10(cwd) : process.cwd();
16374
+ const base = cwd ? resolve11(cwd) : process.cwd();
16097
16375
  switch (scope) {
16098
16376
  case "user":
16099
- return resolve10(homedir23(), ".codex", "hooks.json");
16377
+ return resolve11(homedir23(), ".codex", "hooks.json");
16100
16378
  case "project":
16101
- return resolve10(base, ".codex", "hooks.json");
16379
+ return resolve11(base, ".codex", "hooks.json");
16102
16380
  case "local":
16103
- return resolve10(base, ".codex", "hooks.json");
16381
+ return resolve11(base, ".codex", "hooks.json");
16104
16382
  }
16105
16383
  },
16106
16384
  readSettings(settingsPath) {
@@ -16209,14 +16487,14 @@ var init_integrations = __esm(() => {
16209
16487
  scopes: COPILOT_HOOK_SCOPES,
16210
16488
  eventTypes: COPILOT_HOOK_EVENT_TYPES,
16211
16489
  getSettingsPath(scope, cwd) {
16212
- const base = cwd ? resolve10(cwd) : process.cwd();
16490
+ const base = cwd ? resolve11(cwd) : process.cwd();
16213
16491
  switch (scope) {
16214
16492
  case "user":
16215
- return resolve10(homedir23(), ".copilot", "hooks", "failproofai.json");
16493
+ return resolve11(homedir23(), ".copilot", "hooks", "failproofai.json");
16216
16494
  case "project":
16217
- return resolve10(base, ".github", "hooks", "failproofai.json");
16495
+ return resolve11(base, ".github", "hooks", "failproofai.json");
16218
16496
  case "local":
16219
- return resolve10(base, ".github", "hooks", "failproofai.json");
16497
+ return resolve11(base, ".github", "hooks", "failproofai.json");
16220
16498
  }
16221
16499
  },
16222
16500
  readSettings(settingsPath) {
@@ -16323,14 +16601,14 @@ var init_integrations = __esm(() => {
16323
16601
  scopes: CURSOR_HOOK_SCOPES,
16324
16602
  eventTypes: CURSOR_HOOK_EVENT_TYPES,
16325
16603
  getSettingsPath(scope, cwd) {
16326
- const base = cwd ? resolve10(cwd) : process.cwd();
16604
+ const base = cwd ? resolve11(cwd) : process.cwd();
16327
16605
  switch (scope) {
16328
16606
  case "user":
16329
- return resolve10(homedir23(), ".cursor", "hooks.json");
16607
+ return resolve11(homedir23(), ".cursor", "hooks.json");
16330
16608
  case "project":
16331
- return resolve10(base, ".cursor", "hooks.json");
16609
+ return resolve11(base, ".cursor", "hooks.json");
16332
16610
  case "local":
16333
- return resolve10(base, ".cursor", "hooks.json");
16611
+ return resolve11(base, ".cursor", "hooks.json");
16334
16612
  }
16335
16613
  },
16336
16614
  readSettings(settingsPath) {
@@ -16422,14 +16700,14 @@ var init_integrations = __esm(() => {
16422
16700
  scopes: OPENCODE_HOOK_SCOPES,
16423
16701
  eventTypes: OPENCODE_HOOK_EVENT_TYPES,
16424
16702
  getSettingsPath(scope, cwd) {
16425
- const base = cwd ? resolve10(cwd) : process.cwd();
16703
+ const base = cwd ? resolve11(cwd) : process.cwd();
16426
16704
  switch (scope) {
16427
16705
  case "user":
16428
- return resolve10(homedir23(), ".config", "opencode", "opencode.json");
16706
+ return resolve11(homedir23(), ".config", "opencode", "opencode.json");
16429
16707
  case "project":
16430
- return resolve10(base, ".opencode", "opencode.json");
16708
+ return resolve11(base, ".opencode", "opencode.json");
16431
16709
  case "local":
16432
- return resolve10(base, ".opencode", "opencode.json");
16710
+ return resolve11(base, ".opencode", "opencode.json");
16433
16711
  }
16434
16712
  },
16435
16713
  readSettings(settingsPath) {
@@ -16440,7 +16718,7 @@ var init_integrations = __esm(() => {
16440
16718
  },
16441
16719
  buildHookEntry(_binaryPath, _eventType, scope) {
16442
16720
  if (scope === "user") {
16443
- const abs = resolve10(homedir23(), ".config", "opencode", "plugins", "failproofai.mjs");
16721
+ const abs = resolve11(homedir23(), ".config", "opencode", "plugins", "failproofai.mjs");
16444
16722
  return { spec: `file://${abs}`, [FAILPROOFAI_HOOK_MARKER]: true };
16445
16723
  }
16446
16724
  return { spec: OPENCODE_PLUGIN_REL_PATH, [FAILPROOFAI_HOOK_MARKER]: true };
@@ -16455,9 +16733,9 @@ var init_integrations = __esm(() => {
16455
16733
  writeHookEntries(settings, binaryPath, scope) {
16456
16734
  const s = settings;
16457
16735
  const effectiveScope = scope ?? "project";
16458
- const settingsPath = effectiveScope === "user" ? resolve10(homedir23(), ".config", "opencode", "opencode.json") : resolve10(process.cwd(), ".opencode", "opencode.json");
16736
+ const settingsPath = effectiveScope === "user" ? resolve11(homedir23(), ".config", "opencode", "opencode.json") : resolve11(process.cwd(), ".opencode", "opencode.json");
16459
16737
  const pluginPath = opencodePluginFilePath(settingsPath);
16460
- mkdirSync7(dirname4(pluginPath), { recursive: true });
16738
+ mkdirSync7(dirname5(pluginPath), { recursive: true });
16461
16739
  writeFileSync6(pluginPath, buildOpenCodePluginShim(binaryPath, effectiveScope), "utf8");
16462
16740
  if (!Array.isArray(s.plugin))
16463
16741
  s.plugin = [];
@@ -16523,14 +16801,14 @@ var init_integrations = __esm(() => {
16523
16801
  scopes: PI_HOOK_SCOPES,
16524
16802
  eventTypes: PI_HOOK_EVENT_TYPES,
16525
16803
  getSettingsPath(scope, cwd) {
16526
- const base = cwd ? resolve10(cwd) : process.cwd();
16804
+ const base = cwd ? resolve11(cwd) : process.cwd();
16527
16805
  switch (scope) {
16528
16806
  case "user":
16529
- return resolve10(homedir23(), ".pi", "agent", "settings.json");
16807
+ return resolve11(homedir23(), ".pi", "agent", "settings.json");
16530
16808
  case "project":
16531
- return resolve10(base, ".pi", "settings.json");
16809
+ return resolve11(base, ".pi", "settings.json");
16532
16810
  case "local":
16533
- return resolve10(base, ".pi", "settings.json");
16811
+ return resolve11(base, ".pi", "settings.json");
16534
16812
  }
16535
16813
  },
16536
16814
  readSettings(settingsPath) {
@@ -16608,7 +16886,10 @@ var init_integrations = __esm(() => {
16608
16886
  scopes: HERMES_HOOK_SCOPES,
16609
16887
  eventTypes: HERMES_HOOK_EVENT_TYPES,
16610
16888
  getSettingsPath() {
16611
- return resolve10(homedir23(), ".hermes", "config.yaml");
16889
+ return resolve11(hermesRoot(), "config.yaml");
16890
+ },
16891
+ getSettingsPaths() {
16892
+ return listHermesProfiles().map((p) => resolve11(p.home, "config.yaml"));
16612
16893
  },
16613
16894
  readSettings(settingsPath) {
16614
16895
  return readYamlDoc(settingsPath);
@@ -16675,21 +16956,8 @@ var init_integrations = __esm(() => {
16675
16956
  return removed;
16676
16957
  },
16677
16958
  hooksInstalledInSettings(scope, cwd) {
16678
- const settingsPath = this.getSettingsPath(scope, cwd);
16679
- if (!existsSync11(settingsPath))
16680
- return false;
16681
- try {
16682
- const doc = readYamlDoc(settingsPath);
16683
- const js = doc.toJS() ?? {};
16684
- const hooks = js.hooks;
16685
- if (!hooks || typeof hooks !== "object")
16686
- return false;
16687
- for (const entries of Object.values(hooks)) {
16688
- if (Array.isArray(entries) && entries.some((h) => isMarkedHook(h)))
16689
- return true;
16690
- }
16691
- } catch {}
16692
- return false;
16959
+ const paths = settingsPathsFor(this, scope, cwd);
16960
+ return paths.length > 0 && paths.every((p) => hermesConfigHasHooks(p));
16693
16961
  },
16694
16962
  detectInstalled() {
16695
16963
  return binaryExists("hermes");
@@ -16701,7 +16969,7 @@ var init_integrations = __esm(() => {
16701
16969
  scopes: OPENCLAW_HOOK_SCOPES,
16702
16970
  eventTypes: OPENCLAW_HOOK_EVENT_TYPES,
16703
16971
  getSettingsPath() {
16704
- return resolve10(homedir23(), ".openclaw", "openclaw.json");
16972
+ return resolve11(homedir23(), ".openclaw", "openclaw.json");
16705
16973
  },
16706
16974
  readSettings(settingsPath) {
16707
16975
  return readJsonFile(settingsPath);
@@ -16797,14 +17065,14 @@ var init_integrations = __esm(() => {
16797
17065
  scopes: FACTORY_HOOK_SCOPES,
16798
17066
  eventTypes: FACTORY_HOOK_EVENT_TYPES,
16799
17067
  getSettingsPath(scope, cwd) {
16800
- const base = cwd ? resolve10(cwd) : process.cwd();
17068
+ const base = cwd ? resolve11(cwd) : process.cwd();
16801
17069
  switch (scope) {
16802
17070
  case "user":
16803
- return resolve10(homedir23(), ".factory", "hooks.json");
17071
+ return resolve11(homedir23(), ".factory", "hooks.json");
16804
17072
  case "project":
16805
- return resolve10(base, ".factory", "hooks.json");
17073
+ return resolve11(base, ".factory", "hooks.json");
16806
17074
  case "local":
16807
- return resolve10(base, ".factory", "hooks.json");
17075
+ return resolve11(base, ".factory", "hooks.json");
16808
17076
  }
16809
17077
  },
16810
17078
  readSettings(settingsPath) {
@@ -16899,14 +17167,14 @@ var init_integrations = __esm(() => {
16899
17167
  scopes: DEVIN_HOOK_SCOPES,
16900
17168
  eventTypes: DEVIN_HOOK_EVENT_TYPES,
16901
17169
  getSettingsPath(scope, cwd) {
16902
- const base = cwd ? resolve10(cwd) : process.cwd();
17170
+ const base = cwd ? resolve11(cwd) : process.cwd();
16903
17171
  switch (scope) {
16904
17172
  case "user":
16905
- return resolve10(homedir23(), ".config", "devin", "config.json");
17173
+ return resolve11(homedir23(), ".config", "devin", "config.json");
16906
17174
  case "project":
16907
- return resolve10(base, ".devin", "config.json");
17175
+ return resolve11(base, ".devin", "config.json");
16908
17176
  case "local":
16909
- return resolve10(base, ".devin", "config.json");
17177
+ return resolve11(base, ".devin", "config.json");
16910
17178
  }
16911
17179
  },
16912
17180
  readSettings(settingsPath) {
@@ -17008,14 +17276,14 @@ var init_integrations = __esm(() => {
17008
17276
  scopes: ANTIGRAVITY_HOOK_SCOPES,
17009
17277
  eventTypes: ANTIGRAVITY_HOOK_EVENT_TYPES,
17010
17278
  getSettingsPath(scope, cwd) {
17011
- const base = cwd ? resolve10(cwd) : process.cwd();
17279
+ const base = cwd ? resolve11(cwd) : process.cwd();
17012
17280
  switch (scope) {
17013
17281
  case "user":
17014
- return resolve10(homedir23(), ".gemini", "config", "hooks.json");
17282
+ return resolve11(homedir23(), ".gemini", "config", "hooks.json");
17015
17283
  case "project":
17016
- return resolve10(base, ".agents", "hooks.json");
17284
+ return resolve11(base, ".agents", "hooks.json");
17017
17285
  case "local":
17018
- return resolve10(base, ".agents", "hooks.json");
17286
+ return resolve11(base, ".agents", "hooks.json");
17019
17287
  }
17020
17288
  },
17021
17289
  readSettings(settingsPath) {
@@ -17149,14 +17417,14 @@ var init_integrations = __esm(() => {
17149
17417
  scopes: GOOSE_HOOK_SCOPES,
17150
17418
  eventTypes: GOOSE_HOOK_EVENT_TYPES,
17151
17419
  getSettingsPath(scope, cwd) {
17152
- const base = cwd ? resolve10(cwd) : process.cwd();
17420
+ const base = cwd ? resolve11(cwd) : process.cwd();
17153
17421
  switch (scope) {
17154
17422
  case "user":
17155
- return resolve10(homedir23(), ".agents", "plugins", "failproofai", "hooks", "hooks.json");
17423
+ return resolve11(homedir23(), ".agents", "plugins", "failproofai", "hooks", "hooks.json");
17156
17424
  case "project":
17157
- return resolve10(base, ".agents", "plugins", "failproofai", "hooks", "hooks.json");
17425
+ return resolve11(base, ".agents", "plugins", "failproofai", "hooks", "hooks.json");
17158
17426
  case "local":
17159
- return resolve10(base, ".agents", "plugins", "failproofai", "hooks", "hooks.json");
17427
+ return resolve11(base, ".agents", "plugins", "failproofai", "hooks", "hooks.json");
17160
17428
  }
17161
17429
  },
17162
17430
  readSettings(settingsPath) {
@@ -17491,7 +17759,7 @@ function runPrompt(p) {
17491
17759
  `${c.dim(BAR)} ${c.dim(p.summaryFor(result))}`
17492
17760
  ]);
17493
17761
  };
17494
- return new Promise((resolve11) => {
17762
+ return new Promise((resolve12) => {
17495
17763
  hideCursor(stdout);
17496
17764
  repaint(stdout, region, build());
17497
17765
  readline.emitKeypressEvents(stdin);
@@ -17507,7 +17775,7 @@ function runPrompt(p) {
17507
17775
  const finish = (result) => {
17508
17776
  cleanup();
17509
17777
  collapse(result);
17510
- resolve11(result);
17778
+ resolve12(result);
17511
17779
  };
17512
17780
  function onKey(_s, key) {
17513
17781
  if (!key)
@@ -17808,7 +18076,7 @@ async function promptPolicySelection(preSelected, options = {}) {
17808
18076
  `);
17809
18077
  lastLineCount = lines.length;
17810
18078
  }
17811
- return new Promise((resolve11) => {
18079
+ return new Promise((resolve12) => {
17812
18080
  render();
17813
18081
  process.stdin.setRawMode(true);
17814
18082
  process.stdin.resume();
@@ -17845,7 +18113,7 @@ async function promptPolicySelection(preSelected, options = {}) {
17845
18113
  ${dim(STEP_DONE)} Policies
17846
18114
  ${dim(BAR)} ${dim(`${selected.length} selected`)}
17847
18115
  `);
17848
- resolve11(selected);
18116
+ resolve12(selected);
17849
18117
  } else if (key.name === "escape") {
17850
18118
  search = "";
17851
18119
  cursor2 = 0;
@@ -17908,7 +18176,7 @@ __export(exports_manager, {
17908
18176
  });
17909
18177
  import { execSync as execSync6 } from "node:child_process";
17910
18178
  import { existsSync as existsSync12 } from "node:fs";
17911
- import { resolve as resolve11, basename as basename3 } from "node:path";
18179
+ import { resolve as resolve12, basename as basename4 } from "node:path";
17912
18180
  import { homedir as homedir24, platform as platform3, arch as arch3, release as release2, hostname as hostname3 } from "node:os";
17913
18181
  function getSettingsPath(scope, cwd) {
17914
18182
  return claudeCode.getSettingsPath(scope, cwd);
@@ -18015,7 +18283,7 @@ async function installHooksImpl(policyNames, scope = "user", cwd, includeBeta =
18015
18283
  if (removeCustomHooks) {
18016
18284
  delete configToWrite.customPoliciesPath;
18017
18285
  } else if (customPoliciesPath) {
18018
- configToWrite.customPoliciesPath = resolve11(customPoliciesPath);
18286
+ configToWrite.customPoliciesPath = resolve12(customPoliciesPath);
18019
18287
  let validatedHooks = [];
18020
18288
  try {
18021
18289
  validatedHooks = await loadCustomHooks(configToWrite.customPoliciesPath, { strict: true });
@@ -18055,12 +18323,14 @@ Enabled ${selectedPolicies.length} policy(ies): ${selectedPolicies.join(", ")}
18055
18323
  const writtenSettingsPaths = [];
18056
18324
  for (const cliId of selectedClis) {
18057
18325
  const integration = getIntegration(cliId);
18058
- const settingsPath = integration.getSettingsPath(scope, cwd);
18326
+ const settingsPaths = settingsPathsFor(integration, scope, cwd);
18059
18327
  try {
18060
- const settings = integration.readSettings(settingsPath);
18061
- integration.writeHookEntries(settings, binaryPath, scope);
18062
- integration.writeSettings(settingsPath, settings);
18063
- writtenSettingsPaths.push({ cli: cliId, path: settingsPath });
18328
+ for (const settingsPath of settingsPaths) {
18329
+ const settings = integration.readSettings(settingsPath);
18330
+ integration.writeHookEntries(settings, binaryPath, scope);
18331
+ integration.writeSettings(settingsPath, settings);
18332
+ writtenSettingsPaths.push({ cli: cliId, path: settingsPath });
18333
+ }
18064
18334
  } catch (err) {
18065
18335
  const errorType = err instanceof Error && /EACCES|EPERM/.test(err.message) ? "permission_denied" : err instanceof Error && /ENOENT|ENOTDIR/.test(err.message) ? "path_not_found" : "write_error";
18066
18336
  try {
@@ -18194,25 +18464,30 @@ async function removeHooks(policyNames, scope = "user", cwd, opts) {
18194
18464
  const integration = getIntegration(cliId);
18195
18465
  const scopesToRemove = scope === "all" ? [...integration.scopes] : integration.scopes.includes(scope) ? [scope] : [];
18196
18466
  for (const s of scopesToRemove) {
18197
- const settingsPath = integration.getSettingsPath(s, cwd);
18198
- if (!existsSync12(settingsPath)) {
18467
+ const settingsPaths = settingsPathsFor(integration, s, cwd);
18468
+ const existing = settingsPaths.filter((p) => existsSync12(p));
18469
+ if (existing.length === 0) {
18199
18470
  if (scope !== "all" && selectedClis.length === 1) {
18200
18471
  console.log("No settings file found. Nothing to remove.");
18201
18472
  nothingToReport = true;
18202
18473
  }
18203
18474
  continue;
18204
18475
  }
18205
- const removed = integration.removeHooksFromFile(settingsPath);
18206
- if (removed === 0 && scope !== "all" && selectedClis.length === 1) {
18476
+ let removedHere = 0;
18477
+ for (const settingsPath of existing) {
18478
+ const removed = integration.removeHooksFromFile(settingsPath);
18479
+ removedHere += removed;
18480
+ if (removed > 0 && scope !== "all") {
18481
+ console.log(`Removed ${removed} failproofai hook(s) from ${integration.displayName} settings.`);
18482
+ console.log(`Settings: ${settingsPath}`);
18483
+ }
18484
+ }
18485
+ if (removedHere === 0 && scope !== "all" && selectedClis.length === 1) {
18207
18486
  console.log("No hooks found in settings. Nothing to remove.");
18208
18487
  nothingToReport = true;
18209
18488
  continue;
18210
18489
  }
18211
- totalRemoved += removed;
18212
- if (scope !== "all") {
18213
- console.log(`Removed ${removed} failproofai hook(s) from ${integration.displayName} settings.`);
18214
- console.log(`Settings: ${settingsPath}`);
18215
- }
18490
+ totalRemoved += removedHere;
18216
18491
  }
18217
18492
  }
18218
18493
  if (nothingToReport && totalRemoved === 0)
@@ -18222,7 +18497,9 @@ async function removeHooks(policyNames, scope = "user", cwd, opts) {
18222
18497
  for (const cliId of selectedClis) {
18223
18498
  const integration = getIntegration(cliId);
18224
18499
  for (const s of integration.scopes) {
18225
- console.log(` ${integration.displayName} / ${s}: ${integration.getSettingsPath(s, cwd)}`);
18500
+ for (const p of settingsPathsFor(integration, s, cwd)) {
18501
+ console.log(` ${integration.displayName} / ${s}: ${p}`);
18502
+ }
18226
18503
  }
18227
18504
  }
18228
18505
  }
@@ -18399,35 +18676,54 @@ Failproof AI Hook Policies
18399
18676
  }
18400
18677
  console.log();
18401
18678
  }
18402
- const base = cwd ? resolve11(cwd) : process.cwd();
18679
+ const base = findProjectConfigDir(cwd ?? process.cwd());
18680
+ const projectDir = resolve12(base, ".failproofai", "policies");
18681
+ const userDir = resolve12(homedir24(), ".failproofai", "policies");
18682
+ const sameDir = userDir === projectDir;
18403
18683
  const conventionDirs = [
18404
- { label: "Project", dir: resolve11(base, ".failproofai", "policies") },
18405
- { label: "User", dir: resolve11(homedir24(), ".failproofai", "policies") }
18684
+ { label: sameDir ? "Project + User" : "Project", dir: projectDir },
18685
+ ...sameDir ? [] : [{ label: "User", dir: userDir }]
18406
18686
  ];
18687
+ const discovered = {
18688
+ project: [],
18689
+ user: []
18690
+ };
18407
18691
  for (const { label, dir } of conventionDirs) {
18408
18692
  const files = discoverPolicyFiles(dir);
18409
18693
  if (files.length === 0)
18410
18694
  continue;
18695
+ const targets = dir === projectDir && dir === userDir ? ["project", "user"] : dir === projectDir ? ["project"] : ["user"];
18696
+ const record = (file, hooks) => {
18697
+ for (const t of targets)
18698
+ discovered[t].push({ file, hooks });
18699
+ };
18411
18700
  console.log(`
18412
18701
  ── Convention Policies — ${label} (${dir}) ──────────`);
18702
+ const colWidth = Math.max(nameColWidth, ...files.map((f) => basename4(f).length + 2));
18413
18703
  for (const file of files) {
18414
18704
  try {
18415
18705
  const hooks = await loadCustomHooks(file);
18706
+ const filename = basename4(file);
18707
+ record(filename, hooks.map((h) => h.name));
18416
18708
  if (hooks.length === 0) {
18417
- const filename = basename3(file);
18418
- console.log(` \x1B[31m✗\x1B[0m ${filename.padEnd(nameColWidth)}\x1B[31mfailed to load\x1B[0m`);
18709
+ console.log(` \x1B[31m✗\x1B[0m ${filename.padEnd(colWidth)}\x1B[31mfailed to load\x1B[0m`);
18419
18710
  } else {
18420
- const filename = basename3(file);
18421
18711
  const hookSummary = hooks.map((h) => h.name).join(", ");
18422
- console.log(` \x1B[32m✓\x1B[0m ${filename.padEnd(nameColWidth)}${hooks.length} hook(s): ${hookSummary}`);
18712
+ console.log(` \x1B[32m✓\x1B[0m ${filename.padEnd(colWidth)}${hooks.length} hook(s): ${hookSummary}`);
18423
18713
  }
18424
18714
  } catch {
18425
- const filename = basename3(file);
18426
- console.log(` \x1B[31m✗\x1B[0m ${filename.padEnd(nameColWidth)}\x1B[31merror\x1B[0m`);
18715
+ const filename = basename4(file);
18716
+ record(filename, []);
18717
+ console.log(` \x1B[31m✗\x1B[0m ${filename.padEnd(colWidth)}\x1B[31merror\x1B[0m`);
18427
18718
  }
18428
18719
  }
18429
18720
  console.log();
18430
18721
  }
18722
+ try {
18723
+ syncConventionPolicies(discovered.user, "user");
18724
+ } catch (err) {
18725
+ hookLogWarn(`could not record convention policies in config: ${err instanceof Error ? err.message : String(err)}`);
18726
+ }
18431
18727
  }
18432
18728
  var VALID_POLICY_NAMES;
18433
18729
  var init_manager = __esm(() => {
@@ -18440,6 +18736,7 @@ var init_manager = __esm(() => {
18440
18736
  init_hook_telemetry2();
18441
18737
  init_telemetry_id2();
18442
18738
  init_cli_error();
18739
+ init_hook_logger();
18443
18740
  VALID_POLICY_NAMES = new Set(BUILTIN_POLICIES.map((p) => p.name));
18444
18741
  });
18445
18742
 
@@ -18604,7 +18901,7 @@ async function promptCliTargetSelection(detected, action = "install") {
18604
18901
  lastLineCount = lines.length;
18605
18902
  }
18606
18903
  const itemCount = options.length;
18607
- return new Promise((resolve12) => {
18904
+ return new Promise((resolve13) => {
18608
18905
  render();
18609
18906
  readline3.emitKeypressEvents(process.stdin);
18610
18907
  const wasRaw = process.stdin.isRaw;
@@ -18637,7 +18934,7 @@ async function promptCliTargetSelection(detected, action = "install") {
18637
18934
  cleanup();
18638
18935
  process.stdout.write(`
18639
18936
  `);
18640
- resolve12(options[cursor2].value);
18937
+ resolve13(options[cursor2].value);
18641
18938
  }
18642
18939
  }
18643
18940
  process.stdin.on("keypress", onKey);
@@ -18790,7 +19087,7 @@ async function promptPolicySelection2(preSelected, options = {}) {
18790
19087
  `);
18791
19088
  lastLineCount = lines.length;
18792
19089
  }
18793
- return new Promise((resolve12) => {
19090
+ return new Promise((resolve13) => {
18794
19091
  render();
18795
19092
  process.stdin.setRawMode(true);
18796
19093
  process.stdin.resume();
@@ -18827,7 +19124,7 @@ async function promptPolicySelection2(preSelected, options = {}) {
18827
19124
  ${dim(STEP_DONE)} Policies
18828
19125
  ${dim(BAR)} ${dim(`${selected.length} selected`)}
18829
19126
  `);
18830
- resolve12(selected);
19127
+ resolve13(selected);
18831
19128
  } else if (key.name === "escape") {
18832
19129
  search = "";
18833
19130
  cursor2 = 0;
@@ -19014,12 +19311,12 @@ import {
19014
19311
  statSync as statSync11,
19015
19312
  writeFileSync as writeFileSync7
19016
19313
  } from "node:fs";
19017
- import { dirname as dirname5 } from "node:path";
19314
+ import { dirname as dirname6 } from "node:path";
19018
19315
  import { randomBytes } from "node:crypto";
19019
19316
  function writeJsonAtomically(filePath, value, opts = {}) {
19020
19317
  const mode = opts.mode ?? 384;
19021
19318
  const dirMode = opts.dirMode ?? 448;
19022
- const dir = dirname5(filePath);
19319
+ const dir = dirname6(filePath);
19023
19320
  if (!existsSync13(dir))
19024
19321
  mkdirSync8(dir, { recursive: true, mode: dirMode });
19025
19322
  const tmp = `${filePath}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
@@ -19046,15 +19343,15 @@ var init_atomic_write = () => {};
19046
19343
  // lib/auth/auth-store.ts
19047
19344
  import { existsSync as existsSync14, readFileSync as readFileSync13, rmSync as rmSync2 } from "node:fs";
19048
19345
  import { homedir as homedir25 } from "node:os";
19049
- import { join as join25 } from "node:path";
19346
+ import { join as join26 } from "node:path";
19050
19347
  function getAuthDir() {
19051
19348
  const override = process.env.FAILPROOFAI_AUTH_DIR;
19052
19349
  if (override)
19053
19350
  return override;
19054
- return join25(homedir25(), ".failproofai");
19351
+ return join26(homedir25(), ".failproofai");
19055
19352
  }
19056
19353
  function getAuthFilePath() {
19057
- return join25(getAuthDir(), "auth.json");
19354
+ return join26(getAuthDir(), "auth.json");
19058
19355
  }
19059
19356
  function readAuth() {
19060
19357
  const p = getAuthFilePath();
@@ -19162,13 +19459,13 @@ function prompt(question, opts = {}) {
19162
19459
  orig(s);
19163
19460
  };
19164
19461
  }
19165
- return new Promise((resolve12) => {
19462
+ return new Promise((resolve13) => {
19166
19463
  rl.question(question, (answer) => {
19167
19464
  rl.close();
19168
19465
  if (opts.hidden && process.stdin.isTTY)
19169
19466
  process.stdout.write(`
19170
19467
  `);
19171
- resolve12(answer.trim());
19468
+ resolve13(answer.trim());
19172
19469
  });
19173
19470
  });
19174
19471
  }
@@ -19417,8 +19714,8 @@ EXAMPLES
19417
19714
  });
19418
19715
 
19419
19716
  // lib/claude-sessions.ts
19420
- import { readdirSync as readdirSync10, statSync as statSync12, existsSync as existsSync15 } from "node:fs";
19421
- import { join as join26, basename as basename4 } from "node:path";
19717
+ import { readdirSync as readdirSync11, statSync as statSync12, existsSync as existsSync15 } from "node:fs";
19718
+ import { join as join27, basename as basename5 } from "node:path";
19422
19719
  function getClaudeProjectsRoot() {
19423
19720
  return getClaudeProjectsPath();
19424
19721
  }
@@ -19426,21 +19723,21 @@ function listClaudeProjects() {
19426
19723
  const root = getClaudeProjectsRoot();
19427
19724
  let entries;
19428
19725
  try {
19429
- entries = readdirSync10(root, { withFileTypes: true });
19726
+ entries = readdirSync11(root, { withFileTypes: true });
19430
19727
  } catch {
19431
19728
  return [];
19432
19729
  }
19433
19730
  return entries.filter((e) => e.isDirectory()).map((e) => ({
19434
19731
  name: e.name,
19435
19732
  cwd: decodeFolderName(e.name),
19436
- path: join26(root, e.name)
19733
+ path: join27(root, e.name)
19437
19734
  }));
19438
19735
  }
19439
19736
  function listClaudeTranscripts(project) {
19440
19737
  const out = [];
19441
19738
  let entries;
19442
19739
  try {
19443
- entries = readdirSync10(project.path, { withFileTypes: true });
19740
+ entries = readdirSync11(project.path, { withFileTypes: true });
19444
19741
  } catch {
19445
19742
  return out;
19446
19743
  }
@@ -19449,7 +19746,7 @@ function listClaudeTranscripts(project) {
19449
19746
  const sessionId = entry.name.slice(0, -".jsonl".length);
19450
19747
  if (!UUID_RE2.test(sessionId))
19451
19748
  continue;
19452
- const transcriptPath = join26(project.path, entry.name);
19749
+ const transcriptPath = join27(project.path, entry.name);
19453
19750
  try {
19454
19751
  const s = statSync12(transcriptPath);
19455
19752
  out.push({
@@ -19463,12 +19760,12 @@ function listClaudeTranscripts(project) {
19463
19760
  });
19464
19761
  } catch {}
19465
19762
  } else if (entry.isDirectory() && UUID_RE2.test(entry.name)) {
19466
- const subDir = join26(project.path, entry.name, "subagents");
19763
+ const subDir = join27(project.path, entry.name, "subagents");
19467
19764
  if (!existsSync15(subDir))
19468
19765
  continue;
19469
19766
  let subEntries;
19470
19767
  try {
19471
- subEntries = readdirSync10(subDir, { withFileTypes: true });
19768
+ subEntries = readdirSync11(subDir, { withFileTypes: true });
19472
19769
  } catch {
19473
19770
  continue;
19474
19771
  }
@@ -19476,7 +19773,7 @@ function listClaudeTranscripts(project) {
19476
19773
  if (!sub.isFile() || !sub.name.endsWith(".jsonl"))
19477
19774
  continue;
19478
19775
  const agentId = sub.name.slice(0, -".jsonl".length);
19479
- const transcriptPath = join26(subDir, sub.name);
19776
+ const transcriptPath = join27(subDir, sub.name);
19480
19777
  try {
19481
19778
  const s = statSync12(transcriptPath);
19482
19779
  out.push({
@@ -20051,7 +20348,7 @@ async function listHermesTranscriptMetadata(opts = {}) {
20051
20348
  continue;
20052
20349
  out.push({
20053
20350
  cli: "hermes",
20054
- projectName: s.source ? `hermes:${s.source}` : "hermes",
20351
+ projectName: s.source ? hermesProjectPath(s.profile, s.source) : `hermes:${s.profile}`,
20055
20352
  sessionId: s.sessionId,
20056
20353
  transcriptPath: `hermes://${s.sessionId}`,
20057
20354
  mtimeMs: s.mtimeMs,
@@ -20073,6 +20370,7 @@ async function streamHermesEvents(meta) {
20073
20370
  }
20074
20371
  var init_hermes = __esm(() => {
20075
20372
  init_hermes_projects();
20373
+ init_hermes_profiles();
20076
20374
  init_hermes_sessions();
20077
20375
  init_shared();
20078
20376
  });
@@ -20083,16 +20381,16 @@ async function listOpenClawTranscriptMetadata(opts = {}) {
20083
20381
  return [];
20084
20382
  const sinceMs = opts.sinceMs ?? 0;
20085
20383
  const out = [];
20086
- for (const t of listOpenClawTranscripts()) {
20087
- if (t.mtimeMs < sinceMs)
20384
+ for (const s of await getOpenClawSessions()) {
20385
+ if (s.mtimeMs < sinceMs)
20088
20386
  continue;
20089
20387
  out.push({
20090
20388
  cli: "openclaw",
20091
- projectName: `openclaw:${t.agentId}`,
20092
- sessionId: t.sessionId,
20093
- transcriptPath: t.transcriptPath,
20094
- mtimeMs: t.mtimeMs,
20095
- sizeBytes: t.sizeBytes
20389
+ projectName: openClawProjectPath(s.agentId, s.channel),
20390
+ sessionId: s.sessionId,
20391
+ transcriptPath: s.transcriptPath,
20392
+ mtimeMs: s.mtimeMs,
20393
+ sizeBytes: s.sizeBytes
20096
20394
  });
20097
20395
  }
20098
20396
  return out;
@@ -20109,6 +20407,7 @@ async function streamOpenClawEvents(meta) {
20109
20407
  });
20110
20408
  }
20111
20409
  var init_openclaw = __esm(() => {
20410
+ init_openclaw_projects();
20112
20411
  init_openclaw_sessions();
20113
20412
  init_shared();
20114
20413
  });
@@ -20731,7 +21030,7 @@ var init_features = __esm(() => {
20731
21030
  // src/audit/cache.ts
20732
21031
  import { createHash } from "node:crypto";
20733
21032
  import { existsSync as existsSync16, mkdirSync as mkdirSync9, readFileSync as readFileSync14, writeFileSync as writeFileSync8, chmodSync as chmodSync2 } from "node:fs";
20734
- import { join as join27 } from "node:path";
21033
+ import { join as join28 } from "node:path";
20735
21034
  import { homedir as homedir26 } from "node:os";
20736
21035
  function getEngineVersion() {
20737
21036
  if (cachedEngineVersion)
@@ -20750,9 +21049,9 @@ function getDetectorVersion() {
20750
21049
  return cachedDetectorVersion;
20751
21050
  }
20752
21051
  function getCachePathFor(transcriptPath) {
20753
- const root = join27(homedir26(), ".failproofai", "cache", "audit");
21052
+ const root = join28(homedir26(), ".failproofai", "cache", "audit");
20754
21053
  const key = createHash("sha1").update(transcriptPath).digest("hex");
20755
- return join27(root, `${key}.json`);
21054
+ return join28(root, `${key}.json`);
20756
21055
  }
20757
21056
  function readCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes) {
20758
21057
  if (sizeBytes === 0)
@@ -20785,7 +21084,7 @@ function writeCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes, result)
20785
21084
  return;
20786
21085
  const cachePath = getCachePathFor(transcriptPath);
20787
21086
  try {
20788
- mkdirSync9(join27(homedir26(), ".failproofai", "cache", "audit"), { recursive: true });
21087
+ mkdirSync9(join28(homedir26(), ".failproofai", "cache", "audit"), { recursive: true });
20789
21088
  const entry = {
20790
21089
  schemaVersion: CACHE_SCHEMA_VERSION,
20791
21090
  cachedAt: Date.now(),
@@ -21157,10 +21456,10 @@ var init_audit = __esm(() => {
21157
21456
  });
21158
21457
 
21159
21458
  // src/audit/dashboard-cache.ts
21160
- import { join as join28 } from "node:path";
21459
+ import { join as join29 } from "node:path";
21161
21460
  import { homedir as homedir27 } from "node:os";
21162
21461
  function getCachePath() {
21163
- return join28(homedir27(), ".failproofai", "audit-dashboard.json");
21462
+ return join29(homedir27(), ".failproofai", "audit-dashboard.json");
21164
21463
  }
21165
21464
  function writeDashboardCache(params, result) {
21166
21465
  try {
@@ -21250,14 +21549,14 @@ var POLL_INTERVAL_MS = 150, POLL_TIMEOUT_MS = 30000;
21250
21549
  var init_open_browser = () => {};
21251
21550
 
21252
21551
  // scripts/parse-script-args.ts
21253
- import { resolve as resolve12 } from "path";
21552
+ import { resolve as resolve13 } from "path";
21254
21553
  function parseStringFlag(flagName, errorLabel, inlineValue, args, index, options) {
21255
21554
  const raw = inlineValue ?? args[index + 1];
21256
21555
  if (raw === undefined || inlineValue === null && raw.startsWith("-")) {
21257
21556
  console.error(`Error: ${flagName} requires ${errorLabel}`);
21258
21557
  process.exit(1);
21259
21558
  }
21260
- const value = options?.resolve ? resolve12(raw) : raw;
21559
+ const value = options?.resolve ? resolve13(raw) : raw;
21261
21560
  return { value, spliceCount: inlineValue !== null ? 1 : 2 };
21262
21561
  }
21263
21562
  function parseScriptArgs(argv) {
@@ -21306,17 +21605,17 @@ var init_parse_script_args = () => {};
21306
21605
 
21307
21606
  // scripts/install-diagnosis.mjs
21308
21607
  import { existsSync as existsSync17, readFileSync as readFileSync15, realpathSync } from "node:fs";
21309
- import { dirname as dirname6, resolve as resolve13 } from "node:path";
21608
+ import { dirname as dirname7, resolve as resolve14 } from "node:path";
21310
21609
  import { homedir as homedir28, platform as platform4 } from "node:os";
21311
21610
  import { spawnSync } from "node:child_process";
21312
21611
  function findPackageRoot(start) {
21313
21612
  try {
21314
21613
  let dir = realpathSync(start);
21315
- if (existsSync17(dir) && !existsSync17(resolve13(dir, "package.json"))) {
21316
- dir = dirname6(dir);
21614
+ if (existsSync17(dir) && !existsSync17(resolve14(dir, "package.json"))) {
21615
+ dir = dirname7(dir);
21317
21616
  }
21318
21617
  while (true) {
21319
- const pkgPath = resolve13(dir, "package.json");
21618
+ const pkgPath = resolve14(dir, "package.json");
21320
21619
  if (existsSync17(pkgPath)) {
21321
21620
  try {
21322
21621
  const pkg = JSON.parse(readFileSync15(pkgPath, "utf8"));
@@ -21324,7 +21623,7 @@ function findPackageRoot(start) {
21324
21623
  return dir;
21325
21624
  } catch {}
21326
21625
  }
21327
- const parent = dirname6(dir);
21626
+ const parent = dirname7(dir);
21328
21627
  if (parent === dir)
21329
21628
  return null;
21330
21629
  dir = parent;
@@ -21337,7 +21636,7 @@ function readPackageVersion(packageRoot) {
21337
21636
  if (!packageRoot)
21338
21637
  return null;
21339
21638
  try {
21340
- const pkg = JSON.parse(readFileSync15(resolve13(packageRoot, "package.json"), "utf8"));
21639
+ const pkg = JSON.parse(readFileSync15(resolve14(packageRoot, "package.json"), "utf8"));
21341
21640
  return typeof pkg.version === "string" ? pkg.version : null;
21342
21641
  } catch {
21343
21642
  return null;
@@ -21363,16 +21662,16 @@ function locateNpmGlobal() {
21363
21662
  const root = (res.stdout || "").trim();
21364
21663
  if (!root)
21365
21664
  return null;
21366
- const candidate = resolve13(root, PKG_NAME);
21367
- return existsSync17(resolve13(candidate, "package.json")) ? candidate : null;
21665
+ const candidate = resolve14(root, PKG_NAME);
21666
+ return existsSync17(resolve14(candidate, "package.json")) ? candidate : null;
21368
21667
  } catch {
21369
21668
  return null;
21370
21669
  }
21371
21670
  }
21372
21671
  function locateBunGlobal() {
21373
21672
  try {
21374
- const candidate = resolve13(homedir28(), ".bun", "install", "global", "node_modules", PKG_NAME);
21375
- return existsSync17(resolve13(candidate, "package.json")) ? candidate : null;
21673
+ const candidate = resolve14(homedir28(), ".bun", "install", "global", "node_modules", PKG_NAME);
21674
+ return existsSync17(resolve14(candidate, "package.json")) ? candidate : null;
21376
21675
  } catch {
21377
21676
  return null;
21378
21677
  }
@@ -21380,8 +21679,8 @@ function locateBunGlobal() {
21380
21679
  function buildRecommendation(pathFirstBin) {
21381
21680
  if (!pathFirstBin)
21382
21681
  return null;
21383
- const bunBinPrefix = resolve13(homedir28(), ".bun", "bin") + "/";
21384
- const bunGlobalPrefix = resolve13(homedir28(), ".bun", "install", "global") + "/";
21682
+ const bunBinPrefix = resolve14(homedir28(), ".bun", "bin") + "/";
21683
+ const bunGlobalPrefix = resolve14(homedir28(), ".bun", "install", "global") + "/";
21385
21684
  const isBun = pathFirstBin.startsWith(bunBinPrefix) || pathFirstBin.startsWith(bunGlobalPrefix);
21386
21685
  if (isBun) {
21387
21686
  return `rm -f ~/.bun/bin/${PKG_NAME} && rm -rf ~/.bun/install/global/node_modules/${PKG_NAME}`;
@@ -21462,7 +21761,7 @@ __export(exports_launch, {
21462
21761
  });
21463
21762
  import { spawn as spawn2 } from "child_process";
21464
21763
  import { realpathSync as realpathSync2, existsSync as existsSync18 } from "node:fs";
21465
- import { resolve as resolve14, dirname as dirname7 } from "node:path";
21764
+ import { resolve as resolve15, dirname as dirname8 } from "node:path";
21466
21765
  import { fileURLToPath as fileURLToPath2 } from "node:url";
21467
21766
  import { createInterface as createInterface2 } from "node:readline";
21468
21767
  function launch(mode) {
@@ -21477,8 +21776,8 @@ function launch(mode) {
21477
21776
  process.env.PORT = port;
21478
21777
  process.env.HOSTNAME = "0.0.0.0";
21479
21778
  cmd = "node";
21480
- const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve14(dirname7(realpathSync2(fileURLToPath2(import.meta.url))), "..");
21481
- const serverJsPath = resolve14(packageRoot, ".next/standalone/server.js");
21779
+ const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve15(dirname8(realpathSync2(fileURLToPath2(import.meta.url))), "..");
21780
+ const serverJsPath = resolve15(packageRoot, ".next/standalone/server.js");
21482
21781
  if (!existsSync18(serverJsPath)) {
21483
21782
  let shadowMessage = null;
21484
21783
  try {
@@ -21517,6 +21816,7 @@ Error: Cannot find server.js at:
21517
21816
  stdio: filterLogs ? ["inherit", "pipe", "pipe"] : "inherit",
21518
21817
  env: {
21519
21818
  ...process.env,
21819
+ FAILPROOFAI_LAUNCH_CWD: process.env.FAILPROOFAI_LAUNCH_CWD ?? process.cwd(),
21520
21820
  ...filterLogs ? { FORCE_COLOR: process.env.FORCE_COLOR ?? "1" } : {},
21521
21821
  ...loggingLevel ? { FAILPROOFAI_LOG_LEVEL: loggingLevel } : {},
21522
21822
  ...disableTelemetry ? { FAILPROOFAI_TELEMETRY_DISABLED: "1" } : {},
@@ -21830,7 +22130,7 @@ WHAT IT DOES
21830
22130
 
21831
22131
  // src/hooks/manager.ts
21832
22132
  import { execSync as execSync7 } from "node:child_process";
21833
- import { resolve as resolve15, basename as basename5 } from "node:path";
22133
+ import { resolve as resolve16, basename as basename6 } from "node:path";
21834
22134
  import { homedir as homedir29, platform as platform5, arch as arch4, release as release3, hostname as hostname4 } from "node:os";
21835
22135
  function getSettingsPath2(scope, cwd) {
21836
22136
  return claudeCode.getSettingsPath(scope, cwd);
@@ -21937,7 +22237,7 @@ async function installHooksImpl2(policyNames, scope = "user", cwd, includeBeta =
21937
22237
  if (removeCustomHooks) {
21938
22238
  delete configToWrite.customPoliciesPath;
21939
22239
  } else if (customPoliciesPath) {
21940
- configToWrite.customPoliciesPath = resolve15(customPoliciesPath);
22240
+ configToWrite.customPoliciesPath = resolve16(customPoliciesPath);
21941
22241
  let validatedHooks = [];
21942
22242
  try {
21943
22243
  validatedHooks = await loadCustomHooks(configToWrite.customPoliciesPath, { strict: true });
@@ -21977,12 +22277,14 @@ Enabled ${selectedPolicies.length} policy(ies): ${selectedPolicies.join(", ")}
21977
22277
  const writtenSettingsPaths = [];
21978
22278
  for (const cliId of selectedClis) {
21979
22279
  const integration = getIntegration(cliId);
21980
- const settingsPath = integration.getSettingsPath(scope, cwd);
22280
+ const settingsPaths = settingsPathsFor(integration, scope, cwd);
21981
22281
  try {
21982
- const settings = integration.readSettings(settingsPath);
21983
- integration.writeHookEntries(settings, binaryPath, scope);
21984
- integration.writeSettings(settingsPath, settings);
21985
- writtenSettingsPaths.push({ cli: cliId, path: settingsPath });
22282
+ for (const settingsPath of settingsPaths) {
22283
+ const settings = integration.readSettings(settingsPath);
22284
+ integration.writeHookEntries(settings, binaryPath, scope);
22285
+ integration.writeSettings(settingsPath, settings);
22286
+ writtenSettingsPaths.push({ cli: cliId, path: settingsPath });
22287
+ }
21986
22288
  } catch (err) {
21987
22289
  const errorType = err instanceof Error && /EACCES|EPERM/.test(err.message) ? "permission_denied" : err instanceof Error && /ENOENT|ENOTDIR/.test(err.message) ? "path_not_found" : "write_error";
21988
22290
  try {
@@ -22073,6 +22375,7 @@ var init_manager2 = __esm(() => {
22073
22375
  init_hook_telemetry2();
22074
22376
  init_telemetry_id2();
22075
22377
  init_cli_error();
22378
+ init_hook_logger();
22076
22379
  VALID_POLICY_NAMES2 = new Set(BUILTIN_POLICIES.map((p) => p.name));
22077
22380
  });
22078
22381
 
@@ -22413,7 +22716,7 @@ __export(exports_configure_wizard, {
22413
22716
  });
22414
22717
  import { existsSync as existsSync19, mkdirSync as mkdirSync10, writeFileSync as writeFileSync9, readFileSync as readFileSync16 } from "node:fs";
22415
22718
  import { homedir as homedir30 } from "node:os";
22416
- import { resolve as resolve16, sep as sep5 } from "node:path";
22719
+ import { resolve as resolve17, sep as sep5 } from "node:path";
22417
22720
  async function emit(event, props) {
22418
22721
  try {
22419
22722
  await trackHookEvent2(getInstanceId2(), event, props);
@@ -22470,12 +22773,21 @@ function buildAgentChoices(scope, cwd) {
22470
22773
  } catch {
22471
22774
  installedHere = false;
22472
22775
  }
22776
+ let partialHint;
22777
+ if (id === "hermes" && !installedHere) {
22778
+ try {
22779
+ const unhooked = unhookedHermesProfiles();
22780
+ if (unhooked.length > 0) {
22781
+ partialHint = `${unhooked.length} unhooked profile(s): ${unhooked.join(", ")}`;
22782
+ }
22783
+ } catch {}
22784
+ }
22473
22785
  return {
22474
22786
  label: integration.displayName,
22475
22787
  value: id,
22476
22788
  checked: isDetected || installedHere,
22477
22789
  section: isDetected ? "Detected" : "Not installed · set up ahead of time",
22478
- hint: installedHere ? "already configured" : isDetected ? undefined : "not on PATH"
22790
+ hint: installedHere ? "already configured" : partialHint ?? (isDetected ? undefined : "not on PATH")
22479
22791
  };
22480
22792
  });
22481
22793
  }
@@ -22545,8 +22857,8 @@ function describeCustomPolicies(cwd) {
22545
22857
  const scopes = [];
22546
22858
  let fileCount = 0;
22547
22859
  const dirs = [
22548
- { dir: resolve16(cwd, ".failproofai", "policies"), label: "project" },
22549
- { dir: resolve16(homedir30(), ".failproofai", "policies"), label: "global" }
22860
+ { dir: resolve17(cwd, ".failproofai", "policies"), label: "project" },
22861
+ { dir: resolve17(homedir30(), ".failproofai", "policies"), label: "global" }
22550
22862
  ];
22551
22863
  for (const { dir, label } of dirs) {
22552
22864
  const found = discoverPolicyFiles(dir);
@@ -22556,7 +22868,7 @@ function describeCustomPolicies(cwd) {
22556
22868
  fileCount += found.length;
22557
22869
  }
22558
22870
  for (const name of findSkippedPolicyFiles(dir)) {
22559
- warnings.push(`! ${homeify(resolve16(dir, name))} is NOT loaded — rename to ` + `${name.replace(/\.(js|mjs|ts)$/, "-policies.$1")}`);
22871
+ warnings.push(`! ${homeify(resolve17(dir, name))} is NOT loaded — rename to ` + `${name.replace(/\.(js|mjs|ts)$/, "-policies.$1")}`);
22560
22872
  }
22561
22873
  }
22562
22874
  return { active, warnings, fileCount, scopes };
@@ -22579,20 +22891,22 @@ function reviewLines(state) {
22579
22891
  lines.push(" This will update:");
22580
22892
  for (const cli of clis) {
22581
22893
  const integration = getIntegration(cli);
22582
- lines.push(` ${homeify(integration.getSettingsPath(scope, cwd))} ${integration.displayName} hooks`);
22894
+ for (const p of settingsPathsFor(integration, scope, cwd)) {
22895
+ lines.push(` ${homeify(p)} ${integration.displayName} hooks`);
22896
+ }
22583
22897
  }
22584
22898
  lines.push(` ${homeify(getConfigPathForScope(scope, cwd))} ${policies.length} policies`);
22585
22899
  return lines;
22586
22900
  }
22587
22901
  function firstRunMarkerPath() {
22588
- return resolve16(homedir30(), ".failproofai", ".launcher-configured");
22902
+ return resolve17(homedir30(), ".failproofai", ".launcher-configured");
22589
22903
  }
22590
22904
  function hasSeenLauncher() {
22591
22905
  return existsSync19(firstRunMarkerPath());
22592
22906
  }
22593
22907
  function markLauncherSeen() {
22594
22908
  try {
22595
- mkdirSync10(resolve16(homedir30(), ".failproofai"), { recursive: true });
22909
+ mkdirSync10(resolve17(homedir30(), ".failproofai"), { recursive: true });
22596
22910
  writeFileSync9(firstRunMarkerPath(), "1", "utf8");
22597
22911
  } catch {}
22598
22912
  }
@@ -22743,7 +23057,7 @@ __export(exports_launch2, {
22743
23057
  });
22744
23058
  import { spawn as spawn3 } from "child_process";
22745
23059
  import { realpathSync as realpathSync3, existsSync as existsSync20 } from "node:fs";
22746
- import { resolve as resolve17, dirname as dirname8 } from "node:path";
23060
+ import { resolve as resolve18, dirname as dirname9 } from "node:path";
22747
23061
  import { fileURLToPath as fileURLToPath3 } from "node:url";
22748
23062
  import { createInterface as createInterface3 } from "node:readline";
22749
23063
  function launch2(mode) {
@@ -22758,8 +23072,8 @@ function launch2(mode) {
22758
23072
  process.env.PORT = port;
22759
23073
  process.env.HOSTNAME = "0.0.0.0";
22760
23074
  cmd = "node";
22761
- const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve17(dirname8(realpathSync3(fileURLToPath3(import.meta.url))), "..");
22762
- const serverJsPath = resolve17(packageRoot, ".next/standalone/server.js");
23075
+ const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve18(dirname9(realpathSync3(fileURLToPath3(import.meta.url))), "..");
23076
+ const serverJsPath = resolve18(packageRoot, ".next/standalone/server.js");
22763
23077
  if (!existsSync20(serverJsPath)) {
22764
23078
  let shadowMessage = null;
22765
23079
  try {
@@ -22798,6 +23112,7 @@ Error: Cannot find server.js at:
22798
23112
  stdio: filterLogs ? ["inherit", "pipe", "pipe"] : "inherit",
22799
23113
  env: {
22800
23114
  ...process.env,
23115
+ FAILPROOFAI_LAUNCH_CWD: process.env.FAILPROOFAI_LAUNCH_CWD ?? process.cwd(),
22801
23116
  ...filterLogs ? { FORCE_COLOR: process.env.FORCE_COLOR ?? "1" } : {},
22802
23117
  ...loggingLevel ? { FAILPROOFAI_LOG_LEVEL: loggingLevel } : {},
22803
23118
  ...disableTelemetry ? { FAILPROOFAI_TELEMETRY_DISABLED: "1" } : {},
@@ -22854,17 +23169,17 @@ var init_cli_error2 = __esm(() => {
22854
23169
 
22855
23170
  // bin/failproofai.mjs
22856
23171
  import { realpathSync as realpathSync4 } from "fs";
22857
- import { dirname as dirname9, resolve as resolve18 } from "path";
23172
+ import { dirname as dirname10, resolve as resolve19 } from "path";
22858
23173
  import { fileURLToPath as fileURLToPath4 } from "url";
22859
23174
  // package.json
22860
- var version = "0.0.14";
23175
+ var version = "0.0.15-beta.0";
22861
23176
 
22862
23177
  // bin/failproofai.mjs
22863
23178
  if (!process.env.FAILPROOFAI_PACKAGE_ROOT) {
22864
- process.env.FAILPROOFAI_PACKAGE_ROOT = resolve18(dirname9(realpathSync4(fileURLToPath4(import.meta.url))), "..");
23179
+ process.env.FAILPROOFAI_PACKAGE_ROOT = resolve19(dirname10(realpathSync4(fileURLToPath4(import.meta.url))), "..");
22865
23180
  }
22866
23181
  if (!process.env.FAILPROOFAI_DIST_PATH) {
22867
- process.env.FAILPROOFAI_DIST_PATH = resolve18(dirname9(realpathSync4(fileURLToPath4(import.meta.url))), "..", "dist");
23182
+ process.env.FAILPROOFAI_DIST_PATH = resolve19(dirname10(realpathSync4(fileURLToPath4(import.meta.url))), "..", "dist");
22868
23183
  }
22869
23184
  var args = process.argv.slice(2);
22870
23185
  if (args[0] === "p")