failproofai 0.0.10 → 0.0.11-beta.2

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 (279) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +7 -7
  3. package/.next/standalone/.next/prerender-manifest.json +3 -3
  4. package/.next/standalone/.next/required-server-files.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +4 -4
  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 +4 -4
  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 +4 -4
  18. package/.next/standalone/.next/server/app/_not-found/page/next-font-manifest.json +1 -1
  19. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  20. package/.next/standalone/.next/server/app/_not-found/page.js +4 -4
  21. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  22. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  23. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  24. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  25. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  26. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  27. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
  28. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  29. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  30. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  31. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js +1 -1
  32. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/index.html +1 -1
  34. package/.next/standalone/.next/server/app/index.rsc +16 -16
  35. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  36. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +16 -16
  37. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  38. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
  39. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +3 -3
  40. package/.next/standalone/.next/server/app/page/build-manifest.json +4 -4
  41. package/.next/standalone/.next/server/app/page/next-font-manifest.json +1 -1
  42. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  43. package/.next/standalone/.next/server/app/page.js +4 -4
  44. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  45. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  46. package/.next/standalone/.next/server/app/policies/page/build-manifest.json +4 -4
  47. package/.next/standalone/.next/server/app/policies/page/next-font-manifest.json +1 -1
  48. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
  49. package/.next/standalone/.next/server/app/policies/page.js +4 -4
  50. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  51. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  52. package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +4 -4
  53. package/.next/standalone/.next/server/app/project/[name]/page/next-font-manifest.json +1 -1
  54. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  55. package/.next/standalone/.next/server/app/project/[name]/page.js +4 -4
  56. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  57. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  58. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +4 -4
  59. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/next-font-manifest.json +1 -1
  60. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  61. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  62. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +4 -4
  63. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  64. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  65. package/.next/standalone/.next/server/app/projects/page/build-manifest.json +4 -4
  66. package/.next/standalone/.next/server/app/projects/page/next-font-manifest.json +1 -1
  67. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  68. package/.next/standalone/.next/server/app/projects/page.js +4 -4
  69. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  70. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  71. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d_ob4n._.js +1 -1
  72. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__044xt9.._.js → [root-of-the-server]__0fwb7ao._.js} +2 -2
  73. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0g48iv.._.js +1 -1
  74. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0j8-xkl._.js +1 -1
  75. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0bdfoky.js +1 -1
  76. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_05pz9._._.js +1 -1
  77. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_0z7w.hh._.js +1 -1
  78. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0-wn51s._.js +4 -0
  79. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01as125._.js +3 -0
  80. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__098zro9._.js +19 -0
  81. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__02r.cjq._.js → [root-of-the-server]__09v.ljl._.js} +2 -2
  82. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0agrcb8._.js +4 -0
  83. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0b7hkr~._.js +3 -0
  84. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ehh6vp._.js +4 -0
  85. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g8l0tu._.js +3 -0
  86. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0j4l6hl._.js +3 -0
  87. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0ye1w50._.js → [root-of-the-server]__0k5n2kz._.js} +3 -3
  88. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0lp08ll._.js +3 -0
  89. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n0yaqw._.js +4 -0
  90. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0o21f.o._.js +3 -0
  91. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0t8juvy._.js +4 -0
  92. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__10xgshr._.js → [root-of-the-server]__0tcyn68._.js} +2 -2
  93. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ts150~._.js +3 -0
  94. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0podumr._.js → [root-of-the-server]__0uylufv._.js} +3 -3
  95. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ymlddl._.js +5 -5
  96. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0~03grs._.js +3 -0
  97. package/.next/standalone/.next/server/chunks/ssr/app_0cdqd9w._.js +1 -1
  98. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_0xerkr6._.js +1 -1
  99. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_0q-m0y-._.js +2 -2
  100. package/.next/standalone/.next/server/chunks/ssr/lib_utils_ts_068jk73._.js +1 -1
  101. package/.next/standalone/.next/server/chunks/ssr/node_modules_0ttbz1~._.js +1 -1
  102. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_06u0kr8._.js +1 -1
  103. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_0h9llsw._.js +1 -1
  104. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0a_7sdg.js +2 -2
  105. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0ef3uwk.js +2 -2
  106. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0j79~gv.js +2 -2
  107. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0pbja1x.js +2 -2
  108. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0r6o0i2.js +2 -2
  109. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_11y81~_.js +2 -2
  110. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_12or2kf.js +2 -2
  111. package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_0mebn66._.js +1 -1
  112. package/.next/standalone/.next/server/functions-config-manifest.json +2 -2
  113. package/.next/standalone/.next/server/middleware-build-manifest.js +7 -7
  114. package/.next/standalone/.next/server/next-font-manifest.js +1 -1
  115. package/.next/standalone/.next/server/next-font-manifest.json +6 -6
  116. package/.next/standalone/.next/server/pages/404.html +1 -1
  117. package/.next/standalone/.next/server/pages/500.html +1 -1
  118. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  119. package/.next/standalone/.next/server/server-reference-manifest.json +9 -9
  120. package/.next/standalone/.next/static/chunks/07kpqoo7kuckx.js +6 -0
  121. package/.next/standalone/.next/static/chunks/0a40sy4tk8ioe.js +1 -0
  122. package/.next/standalone/.next/static/chunks/{12l2t63hkyo2q.js → 0azb~vy9ds_uy.js} +1 -1
  123. package/.next/standalone/.next/static/chunks/{0j171xiqge4rv.js → 0bke.~atnsbeb.js} +1 -1
  124. package/.next/standalone/.next/static/chunks/{0lt8ko3lw.5yt.js → 0bv1oyxspkpkb.js} +1 -1
  125. package/.next/standalone/.next/static/chunks/{179yytvmam0ug.js → 0dvhi-prcsh3~.js} +1 -1
  126. package/.next/standalone/.next/static/chunks/0f5p9plm.aqlp.css +2 -0
  127. package/.next/standalone/.next/static/chunks/0ffvlbgzgnlw7.js +2 -0
  128. package/.next/standalone/.next/static/chunks/{150i0n26fnvso.js → 0n1n67imq.udf.js} +1 -1
  129. package/.next/standalone/.next/static/chunks/0spktq7xqab9h.js +1 -0
  130. package/.next/standalone/.next/static/chunks/{14lii11wmo450.js → 118q3uljozd5z.js} +1 -1
  131. package/.next/standalone/.next/static/chunks/{0pkl..xgo-qox.js → 11w14gnqzprir.js} +1 -1
  132. package/.next/standalone/.next/static/chunks/{0rnqmir4cd5p9.js → 17mubwtqwijpu.js} +1 -1
  133. package/.next/standalone/.next/static/chunks/{turbopack-05z7a19q43zfq.js → turbopack-0nh.aopesgj~5.js} +1 -1
  134. package/.next/standalone/.next/static/media/4fa387ec64143e14-s.0.qu-9752pffj.woff2 +0 -0
  135. package/.next/standalone/.next/static/media/5ce348bf30bf5439-s.0ee55_hj9qcer.woff2 +0 -0
  136. package/.next/standalone/.next/static/media/6306c77e7c8268e4-s.0mao5jbfbduzp.woff2 +0 -0
  137. package/.next/standalone/.next/static/media/797e433ab948586e-s.p.09zddjkbdep5a.woff2 +0 -0
  138. package/.next/standalone/.next/static/media/7d817b4c03b0c5f1-s.0uzt.a6d44yda.woff2 +0 -0
  139. package/.next/standalone/.next/static/media/bbc41e54d2fcbd21-s.0mvwgmnhv29no.woff2 +0 -0
  140. package/.next/standalone/.next/static/{dAuQps6jUwCz9X1Q5FFOO → tGVQM5SE3NvbVu0gbAJm7}/_clientMiddlewareManifest.js +2 -2
  141. package/.next/standalone/app/policies/hooks-client.tsx +111 -14
  142. package/.next/standalone/components/navbar.tsx +1 -1
  143. package/.next/standalone/components/reach-developers.tsx +2 -2
  144. package/.next/standalone/lib/claude-sessions.ts +181 -0
  145. package/.next/standalone/node_modules/@next/env/package.json +1 -1
  146. package/.next/standalone/node_modules/next/dist/build/static-paths/app.js +2 -1
  147. package/.next/standalone/node_modules/next/dist/build/swc/index.js +1 -1
  148. package/.next/standalone/node_modules/next/dist/build/utils.js +2 -1
  149. package/.next/standalone/node_modules/next/dist/client/components/router-reducer/fetch-server-response.js +2 -2
  150. package/.next/standalone/node_modules/next/dist/client/components/router-reducer/set-cache-busting-search-param.js +8 -2
  151. package/.next/standalone/node_modules/next/dist/client/route-params.js +23 -6
  152. package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js +13 -13
  153. package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js +11 -11
  154. package/.next/standalone/node_modules/next/dist/compiled/next-server/app-route-turbo.runtime.prod.js +2 -2
  155. package/.next/standalone/node_modules/next/dist/compiled/next-server/pages-turbo.runtime.prod.js +10 -10
  156. package/.next/standalone/node_modules/next/dist/lib/patch-incorrect-lockfile.js +3 -3
  157. package/.next/standalone/node_modules/next/dist/server/app-render/action-handler.js +3 -6
  158. package/.next/standalone/node_modules/next/dist/server/app-render/app-render.js +62 -9
  159. package/.next/standalone/node_modules/next/dist/server/app-render/collect-segment-data.js +16 -0
  160. package/.next/standalone/node_modules/next/dist/server/app-render/create-component-tree.js +49 -19
  161. package/.next/standalone/node_modules/next/dist/server/app-render/get-script-nonce-from-header.js +8 -20
  162. package/.next/standalone/node_modules/next/dist/server/app-render/metadata-insertion/create-server-inserted-metadata.js +8 -7
  163. package/.next/standalone/node_modules/next/dist/server/app-render/use-flight-response.js +2 -2
  164. package/.next/standalone/node_modules/next/dist/server/async-storage/work-store.js +2 -1
  165. package/.next/standalone/node_modules/next/dist/server/base-server.js +13 -5
  166. package/.next/standalone/node_modules/next/dist/server/config.js +1 -1
  167. package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-turbopack.js +2 -2
  168. package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-webpack.js +1 -1
  169. package/.next/standalone/node_modules/next/dist/server/dev/static-paths-worker.js +2 -1
  170. package/.next/standalone/node_modules/next/dist/server/image-optimizer.js +22 -2
  171. package/.next/standalone/node_modules/next/dist/server/lib/app-info-log.js +1 -1
  172. package/.next/standalone/node_modules/next/dist/server/lib/is-rsc-request.js +18 -0
  173. package/.next/standalone/node_modules/next/dist/server/lib/mock-request.js +30 -5
  174. package/.next/standalone/node_modules/next/dist/server/lib/patch-set-header.js +7 -0
  175. package/.next/standalone/node_modules/next/dist/server/lib/router-server.js +6 -3
  176. package/.next/standalone/node_modules/next/dist/server/lib/router-utils/resolve-routes.js +18 -4
  177. package/.next/standalone/node_modules/next/dist/server/lib/server-ipc/utils.js +3 -1
  178. package/.next/standalone/node_modules/next/dist/server/lib/start-server.js +1 -1
  179. package/.next/standalone/node_modules/next/dist/server/next-server.js +1 -1
  180. package/.next/standalone/node_modules/next/dist/server/request/fallback-params.js +27 -1
  181. package/.next/standalone/node_modules/next/dist/server/route-modules/app-route/module.js +1 -0
  182. package/.next/standalone/node_modules/next/dist/server/route-modules/route-module.js +11 -1
  183. package/.next/standalone/node_modules/next/dist/server/server-utils.js +19 -2
  184. package/.next/standalone/node_modules/next/dist/server/stream-utils/node-web-streams-helper.js +5 -5
  185. package/.next/standalone/node_modules/next/dist/server/use-cache/use-cache-wrapper.js +1 -1
  186. package/.next/standalone/node_modules/next/dist/server/web/adapter.js +4 -1
  187. package/.next/standalone/node_modules/next/dist/server/web/edge-route-module-wrapper.js +2 -1
  188. package/.next/standalone/node_modules/next/dist/shared/lib/errors/canary-only-config-error.js +1 -1
  189. package/.next/standalone/node_modules/next/dist/{server → shared/lib}/htmlescape.js +15 -0
  190. package/.next/standalone/node_modules/next/dist/shared/lib/router/routes/app.js +13 -1
  191. package/.next/standalone/node_modules/next/dist/shared/lib/router/utils/cache-busting-search-param.js +56 -10
  192. package/.next/standalone/node_modules/next/dist/telemetry/anonymous-meta.js +1 -1
  193. package/.next/standalone/node_modules/next/dist/telemetry/events/swc-load-failure.js +1 -1
  194. package/.next/standalone/node_modules/next/dist/telemetry/events/version.js +2 -2
  195. package/.next/standalone/node_modules/next/package.json +15 -15
  196. package/.next/standalone/node_modules/react/cjs/react.development.js +1 -1
  197. package/.next/standalone/node_modules/react/cjs/react.production.js +1 -1
  198. package/.next/standalone/node_modules/react/package.json +1 -1
  199. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.browser.production.js +1 -1
  200. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.node.production.js +1 -1
  201. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.browser.production.js +3 -3
  202. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.edge.production.js +3 -3
  203. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.node.production.js +3 -3
  204. package/.next/standalone/node_modules/react-dom/cjs/react-dom.production.js +1 -1
  205. package/.next/standalone/node_modules/react-dom/package.json +2 -2
  206. package/.next/standalone/package.json +5 -5
  207. package/.next/standalone/proxy.ts +1 -1
  208. package/.next/standalone/server.js +1 -1
  209. package/README.md +4 -4
  210. package/bin/failproofai.mjs +230 -73
  211. package/dist/cli.mjs +3028 -1453
  212. package/lib/claude-sessions.ts +181 -0
  213. package/package.json +5 -5
  214. package/scripts/launch.ts +1 -1
  215. package/scripts/postinstall.mjs +89 -1
  216. package/src/audit/cache.ts +113 -0
  217. package/src/audit/cli-adapters/claude.ts +97 -0
  218. package/src/audit/cli-adapters/codex.ts +56 -0
  219. package/src/audit/cli-adapters/copilot.ts +51 -0
  220. package/src/audit/cli-adapters/cursor.ts +51 -0
  221. package/src/audit/cli-adapters/gemini.ts +51 -0
  222. package/src/audit/cli-adapters/index.ts +70 -0
  223. package/src/audit/cli-adapters/opencode.ts +52 -0
  224. package/src/audit/cli-adapters/pi.ts +51 -0
  225. package/src/audit/cli-adapters/shared.ts +85 -0
  226. package/src/audit/detectors/find-from-root.ts +27 -0
  227. package/src/audit/detectors/git-commit-no-verify.ts +22 -0
  228. package/src/audit/detectors/index.ts +33 -0
  229. package/src/audit/detectors/prefer-edit-over-read-cat.ts +31 -0
  230. package/src/audit/detectors/prefer-edit-over-sed-awk.ts +27 -0
  231. package/src/audit/detectors/prefer-write-over-heredoc.ts +36 -0
  232. package/src/audit/detectors/redundant-cd-cwd.ts +28 -0
  233. package/src/audit/detectors/reread-after-edit.ts +58 -0
  234. package/src/audit/detectors/sleep-polling-loop.ts +34 -0
  235. package/src/audit/index.ts +369 -0
  236. package/src/audit/replay.ts +121 -0
  237. package/src/audit/report.ts +349 -0
  238. package/src/audit/telemetry.ts +113 -0
  239. package/src/audit/types.ts +193 -0
  240. package/src/hooks/builtin-policies.ts +79 -1
  241. package/src/hooks/custom-hooks-loader.ts +19 -3
  242. package/src/hooks/first-run-nudge.ts +146 -0
  243. package/src/hooks/handler.ts +21 -102
  244. package/src/hooks/install-prompt.ts +34 -4
  245. package/src/hooks/manager.ts +72 -5
  246. package/src/hooks/policy-evaluator.ts +19 -4
  247. package/src/hooks/policy-registry.ts +1 -1
  248. package/src/hooks/policy-types.ts +9 -0
  249. package/src/hooks/tool-name-canonicalize.ts +65 -0
  250. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0609ezh._.js +0 -3
  251. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__07_-mkc._.js +0 -3
  252. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__09z7o2x._.js +0 -19
  253. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0_sh2n0._.js +0 -3
  254. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e9o9ri._.js +0 -4
  255. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0l6swv1._.js +0 -3
  256. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0logebz._.js +0 -3
  257. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0mi5ejy._.js +0 -4
  258. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0odijkc._.js +0 -3
  259. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rkxer-._.js +0 -3
  260. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rl2kwi._.js +0 -4
  261. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0vg0uey._.js +0 -4
  262. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0x5limi._.js +0 -3
  263. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__10._f0s._.js +0 -4
  264. package/.next/standalone/.next/static/chunks/01q52wg_amm60.js +0 -2
  265. package/.next/standalone/.next/static/chunks/0kqar56yl~41o.js +0 -6
  266. package/.next/standalone/.next/static/chunks/0ml1.ck_5t36i.js +0 -1
  267. package/.next/standalone/.next/static/chunks/0zig0fh30t6ou.js +0 -1
  268. package/.next/standalone/.next/static/chunks/17rm86uz2nd5a.css +0 -2
  269. package/.next/standalone/.next/static/media/4fa387ec64143e14-s.0q3udbd2bu5yp.woff2 +0 -0
  270. package/.next/standalone/.next/static/media/797e433ab948586e-s.p.0.q-h669a_dqa.woff2 +0 -0
  271. package/.next/standalone/.next/static/media/bbc41e54d2fcbd21-s.0gw~uztddq1df.woff2 +0 -0
  272. package/src/auth/login.ts +0 -104
  273. package/src/auth/logout.ts +0 -50
  274. package/src/auth/token-store.ts +0 -64
  275. package/src/relay/daemon.ts +0 -362
  276. package/src/relay/pid.ts +0 -76
  277. package/src/relay/queue.ts +0 -225
  278. /package/.next/standalone/.next/static/{dAuQps6jUwCz9X1Q5FFOO → tGVQM5SE3NvbVu0gbAJm7}/_buildManifest.js +0 -0
  279. /package/.next/standalone/.next/static/{dAuQps6jUwCz9X1Q5FFOO → tGVQM5SE3NvbVu0gbAJm7}/_ssgManifest.js +0 -0
@@ -1502,6 +1502,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1502
1502
  {
1503
1503
  name: "sanitize-jwt",
1504
1504
  description: "Stop Claude from reading JWTs in tool responses",
1505
+ displayTitle: "Redacted JWT tokens from tool output",
1506
+ impact: "Stops the agent from echoing auth tokens it saw in command output.",
1505
1507
  fn: sanitizeJwt,
1506
1508
  match: { events: ["PostToolUse"] },
1507
1509
  defaultEnabled: true,
@@ -1510,6 +1512,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1510
1512
  {
1511
1513
  name: "sanitize-api-keys",
1512
1514
  description: "Stop Claude from reading API keys (OpenAI, Anthropic, GitHub, AWS, Stripe, Google) in tool responses",
1515
+ displayTitle: "Redacted API keys from tool output",
1516
+ impact: "Catches OpenAI / Anthropic / GitHub / AWS / Stripe / Google keys before the model sees them.",
1513
1517
  fn: sanitizeApiKeys,
1514
1518
  match: { events: ["PostToolUse"] },
1515
1519
  defaultEnabled: true,
@@ -1525,6 +1529,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1525
1529
  {
1526
1530
  name: "sanitize-connection-strings",
1527
1531
  description: "Stop Claude from reading database connection strings with embedded credentials in tool responses",
1532
+ displayTitle: "Redacted database connection strings from tool output",
1533
+ impact: "Strips embedded DB credentials before they reach the model context.",
1528
1534
  fn: sanitizeConnectionStrings,
1529
1535
  match: { events: ["PostToolUse"] },
1530
1536
  defaultEnabled: true,
@@ -1533,6 +1539,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1533
1539
  {
1534
1540
  name: "sanitize-private-key-content",
1535
1541
  description: "Stop Claude from reading PEM private key content in tool responses",
1542
+ displayTitle: "Redacted PEM private keys from tool output",
1543
+ impact: "Prevents private key bodies from being echoed into chat context.",
1536
1544
  fn: sanitizePrivateKeyContent,
1537
1545
  match: { events: ["PostToolUse"] },
1538
1546
  defaultEnabled: true,
@@ -1540,6 +1548,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1540
1548
  },
1541
1549
  {
1542
1550
  name: "sanitize-bearer-tokens",
1551
+ displayTitle: "Redacted bearer tokens from tool output",
1552
+ impact: "Strips Authorization: Bearer values before they hit the model.",
1543
1553
  description: "Stop Claude from reading Authorization Bearer tokens in tool responses",
1544
1554
  fn: sanitizeBearerTokens,
1545
1555
  match: { events: ["PostToolUse"] },
@@ -1548,6 +1558,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1548
1558
  },
1549
1559
  {
1550
1560
  name: "protect-env-vars",
1561
+ displayTitle: "Tried to dump environment variables to chat",
1562
+ impact: "Env vars often contain secrets; blocking `env` / `printenv` keeps them out of the model context.",
1551
1563
  description: "Prevent commands that read environment variables",
1552
1564
  fn: protectEnvVars,
1553
1565
  match: { events: ["PreToolUse"], toolNames: ["Bash"] },
@@ -1556,6 +1568,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1556
1568
  },
1557
1569
  {
1558
1570
  name: "block-env-files",
1571
+ displayTitle: "Tried to read or write a .env file",
1572
+ impact: "`.env` files routinely contain API keys and DB credentials.",
1559
1573
  description: "Block reading/writing .env files",
1560
1574
  fn: blockEnvFiles,
1561
1575
  match: { events: ["PreToolUse"] },
@@ -1564,6 +1578,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1564
1578
  },
1565
1579
  {
1566
1580
  name: "block-read-outside-cwd",
1581
+ displayTitle: "Tried to read files outside your project directory",
1582
+ impact: "Stops the agent from peeking at neighboring repos or your home directory.",
1567
1583
  description: "Block file reads outside the session working directory",
1568
1584
  fn: blockReadOutsideCwd,
1569
1585
  match: { events: ["PreToolUse"], toolNames: ["Read", "Glob", "Grep", "Bash"] },
@@ -1579,6 +1595,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1579
1595
  },
1580
1596
  {
1581
1597
  name: "block-sudo",
1598
+ displayTitle: "Tried to run a command with sudo",
1599
+ impact: "Sudo gives the agent root — blocked unless explicitly allow-listed.",
1582
1600
  description: "Block sudo commands",
1583
1601
  fn: blockSudo,
1584
1602
  // PermissionRequest is Codex's escalation-approval event; fire the same
@@ -1596,6 +1614,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1596
1614
  },
1597
1615
  {
1598
1616
  name: "block-curl-pipe-sh",
1617
+ displayTitle: "Tried to pipe a downloaded script straight to a shell",
1618
+ impact: "`curl ... | sh` runs unverified remote code on your machine.",
1599
1619
  description: "Block piping downloads to shell",
1600
1620
  fn: blockCurlPipeSh,
1601
1621
  match: { events: ["PreToolUse"], toolNames: ["Bash"] },
@@ -1604,6 +1624,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1604
1624
  },
1605
1625
  {
1606
1626
  name: "block-rm-rf",
1627
+ displayTitle: "Tried to recursively delete a system path",
1628
+ impact: "Catches catastrophic `rm -rf /` and Windows equivalents.",
1607
1629
  description: "Prevent catastrophic deletions",
1608
1630
  fn: blockRmRf,
1609
1631
  match: { events: ["PreToolUse"], toolNames: ["Bash"] },
@@ -1619,6 +1641,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1619
1641
  },
1620
1642
  {
1621
1643
  name: "block-failproofai-commands",
1644
+ displayTitle: "Tried to disable or modify failproofai itself",
1645
+ impact: "Prevents the agent from turning off the policies that protect you.",
1622
1646
  description: "Block failproofai CLI commands and uninstallation",
1623
1647
  fn: blockFailproofaiCommands,
1624
1648
  match: { events: ["PreToolUse"], toolNames: ["Bash"] },
@@ -1627,6 +1651,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1627
1651
  },
1628
1652
  {
1629
1653
  name: "block-kubectl",
1654
+ displayTitle: "Tried to run a Kubernetes command",
1655
+ impact: "kubectl can change live cluster state — gated unless allow-listed.",
1630
1656
  description: "Block kubectl commands (Kubernetes cluster mutations)",
1631
1657
  fn: blockKubectl,
1632
1658
  match: { events: ["PreToolUse"], toolNames: ["Bash"] },
@@ -1642,6 +1668,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1642
1668
  },
1643
1669
  {
1644
1670
  name: "block-terraform",
1671
+ displayTitle: "Tried to run a Terraform/OpenTofu command",
1672
+ impact: "Terraform mutates real infrastructure — gated unless allow-listed.",
1645
1673
  description: "Block terraform and tofu (OpenTofu) commands",
1646
1674
  fn: blockTerraform,
1647
1675
  match: { events: ["PreToolUse"], toolNames: ["Bash"] },
@@ -1657,6 +1685,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1657
1685
  },
1658
1686
  {
1659
1687
  name: "block-aws-cli",
1688
+ displayTitle: "Tried to run an AWS CLI command",
1689
+ impact: "AWS CLI can spend money or break prod — gated.",
1660
1690
  description: "Block aws CLI commands",
1661
1691
  fn: blockAwsCli,
1662
1692
  match: { events: ["PreToolUse"], toolNames: ["Bash"] },
@@ -1672,6 +1702,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1672
1702
  },
1673
1703
  {
1674
1704
  name: "block-gcloud",
1705
+ displayTitle: "Tried to run a Google Cloud command",
1706
+ impact: "gcloud can spend money or break prod — gated.",
1675
1707
  description: "Block gcloud (Google Cloud) CLI commands",
1676
1708
  fn: blockGcloud,
1677
1709
  match: { events: ["PreToolUse"], toolNames: ["Bash"] },
@@ -1687,6 +1719,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1687
1719
  },
1688
1720
  {
1689
1721
  name: "block-az-cli",
1722
+ displayTitle: "Tried to run an Azure CLI command",
1723
+ impact: "az can spend money or break prod — gated.",
1690
1724
  description: "Block az (Azure) CLI commands",
1691
1725
  fn: blockAzCli,
1692
1726
  match: { events: ["PreToolUse"], toolNames: ["Bash"] },
@@ -1702,6 +1736,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1702
1736
  },
1703
1737
  {
1704
1738
  name: "block-helm",
1739
+ displayTitle: "Tried to run a Helm command",
1740
+ impact: "Helm releases mutate cluster state — gated.",
1705
1741
  description: "Block helm commands",
1706
1742
  fn: blockHelm,
1707
1743
  match: { events: ["PreToolUse"], toolNames: ["Bash"] },
@@ -1717,6 +1753,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1717
1753
  },
1718
1754
  {
1719
1755
  name: "block-gh-pipeline",
1756
+ displayTitle: "Tried to run a privileged GitHub CLI pipeline command",
1757
+ impact: "Catches `gh workflow run`, `gh pr merge`, `gh secret set`, etc.",
1720
1758
  description: "Block gh CLI pipeline-trigger subcommands (workflow run, run rerun/cancel, pr merge, release create/delete, cache delete, secret set/delete)",
1721
1759
  fn: blockGhPipeline,
1722
1760
  match: { events: ["PreToolUse"], toolNames: ["Bash"] },
@@ -1732,6 +1770,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1732
1770
  },
1733
1771
  {
1734
1772
  name: "block-secrets-write",
1773
+ displayTitle: "Tried to write a secret-key file",
1774
+ impact: "Stops the agent from creating `.pem`, `id_rsa`, `credentials.json`, etc.",
1735
1775
  description: "Block writing secret key files",
1736
1776
  fn: blockSecretsWrite,
1737
1777
  match: { events: ["PreToolUse"], toolNames: ["Write"] },
@@ -1747,6 +1787,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1747
1787
  },
1748
1788
  {
1749
1789
  name: "block-push-master",
1790
+ displayTitle: "Tried to push directly to main/master",
1791
+ impact: "Direct pushes to a protected branch bypass review.",
1750
1792
  description: "Block pushing to main/master",
1751
1793
  fn: blockPushMaster,
1752
1794
  match: { events: ["PreToolUse"], toolNames: ["Bash"] },
@@ -1762,6 +1804,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1762
1804
  },
1763
1805
  {
1764
1806
  name: "block-force-push",
1807
+ displayTitle: "Tried to force-push",
1808
+ impact: "Force-pushes rewrite history and can clobber teammates' work.",
1765
1809
  description: "Prevent force-pushing to any branch",
1766
1810
  fn: blockForcePush,
1767
1811
  match: { events: ["PreToolUse"], toolNames: ["Bash"] },
@@ -1770,6 +1814,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1770
1814
  },
1771
1815
  {
1772
1816
  name: "block-work-on-main",
1817
+ displayTitle: "Tried to commit or merge on main/master",
1818
+ impact: "Work should land via PR — direct commits skip review.",
1773
1819
  description: "Block git commits and merges on main/master branch",
1774
1820
  fn: blockWorkOnMain,
1775
1821
  match: { events: ["PreToolUse"], toolNames: ["Bash"] },
@@ -1785,6 +1831,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1785
1831
  },
1786
1832
  {
1787
1833
  name: "warn-git-amend",
1834
+ displayTitle: "Used git commit --amend",
1835
+ impact: "Amending after a push rewrites history that others may have pulled.",
1788
1836
  description: "Warns before amending git commits, which rewrites history",
1789
1837
  fn: warnGitAmend,
1790
1838
  match: { events: ["PreToolUse"], toolNames: ["Bash"] },
@@ -1793,6 +1841,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1793
1841
  },
1794
1842
  {
1795
1843
  name: "warn-git-stash-drop",
1844
+ displayTitle: "Tried to drop or clear git stash",
1845
+ impact: "Stash deletions are permanent and silent.",
1796
1846
  description: "Warns before permanently deleting stashed changes",
1797
1847
  fn: warnGitStashDrop,
1798
1848
  match: { events: ["PreToolUse"], toolNames: ["Bash"] },
@@ -1801,6 +1851,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1801
1851
  },
1802
1852
  {
1803
1853
  name: "warn-all-files-staged",
1854
+ displayTitle: "Staged all files with git add -A / .",
1855
+ impact: "Wide stages routinely catch generated files or secrets you didn't intend to commit.",
1804
1856
  description: "Warns before staging all working tree files with git add -A / . / --all",
1805
1857
  fn: warnAllFilesStaged,
1806
1858
  match: { events: ["PreToolUse"], toolNames: ["Bash"] },
@@ -1809,6 +1861,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1809
1861
  },
1810
1862
  {
1811
1863
  name: "warn-destructive-sql",
1864
+ displayTitle: "Ran destructive SQL (DROP / TRUNCATE / DELETE without WHERE)",
1865
+ impact: "Easy way to wipe a table by accident.",
1812
1866
  description: "Warn before executing destructive SQL (DROP/TRUNCATE/DELETE without WHERE) via database clients",
1813
1867
  fn: warnDestructiveSql,
1814
1868
  match: { events: ["PreToolUse"], toolNames: ["Bash"] },
@@ -1817,6 +1871,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1817
1871
  },
1818
1872
  {
1819
1873
  name: "warn-schema-alteration",
1874
+ displayTitle: "Altered a database schema column",
1875
+ impact: "ALTER TABLE operations can lock tables and break readers.",
1820
1876
  description: "Warns before SQL schema changes (ALTER TABLE with column or rename operations)",
1821
1877
  fn: warnSchemaAlteration,
1822
1878
  match: { events: ["PreToolUse"], toolNames: ["Bash"] },
@@ -1825,6 +1881,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1825
1881
  },
1826
1882
  {
1827
1883
  name: "warn-package-publish",
1884
+ displayTitle: "Tried to publish a package",
1885
+ impact: "Publishes are irreversible — `npm publish` / `cargo publish` shouldn't happen without intent.",
1828
1886
  description: "Warn before publishing packages to public registries (npm, PyPI, crates.io, RubyGems, etc.)",
1829
1887
  fn: warnPackagePublish,
1830
1888
  match: { events: ["PreToolUse"], toolNames: ["Bash"] },
@@ -1833,6 +1891,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1833
1891
  },
1834
1892
  {
1835
1893
  name: "warn-global-package-install",
1894
+ displayTitle: "Installed a package globally",
1895
+ impact: "`npm i -g`, `cargo install`, `pip --user` pollute your machine outside the project.",
1836
1896
  description: "Warns before installing packages globally (npm -g, cargo install, etc.)",
1837
1897
  fn: warnGlobalPackageInstall,
1838
1898
  match: { events: ["PreToolUse"], toolNames: ["Bash"] },
@@ -1841,6 +1901,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1841
1901
  },
1842
1902
  {
1843
1903
  name: "prefer-package-manager",
1904
+ displayTitle: "Used a non-preferred package manager",
1905
+ impact: "Mixing package managers creates lockfile churn for your team.",
1844
1906
  description: "Blocks non-preferred package managers and tells Claude to use an allowed one (e.g., uv instead of pip)",
1845
1907
  fn: preferPackageManager,
1846
1908
  match: { events: ["PreToolUse"], toolNames: ["Bash"] },
@@ -1861,6 +1923,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1861
1923
  },
1862
1924
  {
1863
1925
  name: "warn-large-file-write",
1926
+ displayTitle: "Wrote a file larger than the configured threshold",
1927
+ impact: "Catches accidentally large file writes (logs, binaries, model dumps).",
1864
1928
  description: "Warn before writing files larger than 1MB (configurable via thresholdKb param)",
1865
1929
  fn: warnLargeFileWrite,
1866
1930
  match: { events: ["PreToolUse"], toolNames: ["Write"] },
@@ -1876,6 +1940,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1876
1940
  },
1877
1941
  {
1878
1942
  name: "warn-background-process",
1943
+ displayTitle: "Started a long-lived background process",
1944
+ impact: "Catches `nohup` / `&` / `screen` / `tmux` / `disown` patterns that the agent often forgets to clean up.",
1879
1945
  description: "Warns before starting detached or background processes",
1880
1946
  fn: warnBackgroundProcess,
1881
1947
  match: { events: ["PreToolUse"], toolNames: ["Bash"] },
@@ -1884,6 +1950,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1884
1950
  },
1885
1951
  {
1886
1952
  name: "warn-repeated-tool-calls",
1953
+ displayTitle: "Called the same tool 3+ times with identical arguments",
1954
+ impact: "Usually a sign of a stuck loop burning tokens.",
1887
1955
  description: "Warn when the same tool is called 3+ times with identical parameters",
1888
1956
  fn: warnRepeatedToolCalls,
1889
1957
  match: { events: ["PreToolUse"] },
@@ -1892,6 +1960,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1892
1960
  },
1893
1961
  {
1894
1962
  name: "require-commit-before-stop",
1963
+ displayTitle: "Stopped with uncommitted changes",
1964
+ impact: "Work not in a commit is invisible to teammates and easy to lose.",
1895
1965
  description: "Require all changes to be committed before Claude stops",
1896
1966
  fn: requireCommitBeforeStop,
1897
1967
  match: { events: ["Stop"] },
@@ -1900,6 +1970,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1900
1970
  },
1901
1971
  {
1902
1972
  name: "require-push-before-stop",
1973
+ displayTitle: "Stopped with unpushed commits",
1974
+ impact: "Local-only commits won't trigger CI or be reviewable.",
1903
1975
  description: "Require all commits to be pushed to remote before Claude stops",
1904
1976
  fn: requirePushBeforeStop,
1905
1977
  match: { events: ["Stop"] },
@@ -1920,6 +1992,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1920
1992
  },
1921
1993
  {
1922
1994
  name: "require-pr-before-stop",
1995
+ displayTitle: "Stopped without a PR for the branch",
1996
+ impact: "Branches without PRs don't get reviewed.",
1923
1997
  description: "Require a pull request to exist for the current branch before Claude stops",
1924
1998
  fn: requirePrBeforeStop,
1925
1999
  match: { events: ["Stop"] },
@@ -1935,6 +2009,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1935
2009
  },
1936
2010
  {
1937
2011
  name: "require-no-conflicts-before-stop",
2012
+ displayTitle: "Stopped with a branch that conflicts with main",
2013
+ impact: "Conflicting branches can't merge — surface them early.",
1938
2014
  description: "Require the current branch to merge cleanly with the base branch before Claude stops",
1939
2015
  fn: requireNoConflictsBeforeStop,
1940
2016
  match: { events: ["Stop"] },
@@ -1950,6 +2026,8 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1950
2026
  },
1951
2027
  {
1952
2028
  name: "require-ci-green-before-stop",
2029
+ displayTitle: "Stopped with failing CI",
2030
+ impact: "Failing CI blocks deploy.",
1953
2031
  description: "Require CI checks to pass on the current HEAD commit before Claude stops (ignores stale runs on prior commits)",
1954
2032
  fn: requireCiGreenBeforeStop,
1955
2033
  match: { events: ["Stop"] },
@@ -1959,7 +2037,7 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1959
2037
  ];
1960
2038
 
1961
2039
  export function registerBuiltinPolicies(enabledNames: string[]): void {
1962
- // Tolerate both flat ("sanitize-jwt") and qualified ("exospherehost/sanitize-jwt")
2040
+ // Tolerate both flat ("sanitize-jwt") and qualified ("failproofai/sanitize-jwt")
1963
2041
  // forms in the user's enabledPolicies config — canonicalize both sides.
1964
2042
  const enabledSet = new Set(enabledNames.map(normalizePolicyName));
1965
2043
  for (const policy of BUILTIN_POLICIES) {
@@ -18,6 +18,8 @@ import { hookLogWarn, hookLogError, hookLogInfo } from "./hook-logger";
18
18
  import { getCustomHooks, clearCustomHooks } from "./custom-hooks-registry";
19
19
  import { findDistIndex, rewriteFileTree, TMP_SUFFIX, cleanupTmpFiles } from "./loader-utils";
20
20
  import { findProjectConfigDir } from "./hooks-config";
21
+ import { trackHookEvent } from "./hook-telemetry";
22
+ import { getInstanceId } from "../../lib/telemetry-id";
21
23
  import type { CustomHook } from "./policy-types";
22
24
 
23
25
  const LOADING_KEY = "__FAILPROOFAI_LOADING_HOOKS__";
@@ -46,7 +48,10 @@ export function discoverPolicyFiles(dir: string): string[] {
46
48
  * Load a single policy file into the globalThis custom hooks registry.
47
49
  * Does NOT clear the registry — caller is responsible for that.
48
50
  */
49
- async function loadSingleFile(absPath: string, opts?: { strict?: boolean }): Promise<void> {
51
+ async function loadSingleFile(
52
+ absPath: string,
53
+ opts?: { strict?: boolean; conventionScope?: "project" | "user" },
54
+ ): Promise<void> {
50
55
  const g = globalThis as Record<string, unknown>;
51
56
  g[LOADING_KEY] = true;
52
57
 
@@ -62,6 +67,17 @@ async function loadSingleFile(absPath: string, opts?: { strict?: boolean }): Pro
62
67
  await import(/* webpackIgnore: true */ fileUrl);
63
68
  } catch (err) {
64
69
  const msg = err instanceof Error ? err.message : String(err);
70
+ const errorType = /Cannot find module|MODULE_NOT_FOUND|ENOENT/i.test(msg)
71
+ ? "module_not_found"
72
+ : /SyntaxError|Unexpected token/i.test(msg)
73
+ ? "syntax_error"
74
+ : "runtime_error";
75
+ void trackHookEvent(getInstanceId(), "custom_hooks_load_error", {
76
+ error_type: errorType,
77
+ is_convention: !!opts?.conventionScope,
78
+ convention_scope: opts?.conventionScope ?? null,
79
+ file_basename: basename(absPath),
80
+ });
65
81
  if (opts?.strict) throw new Error(`Failed to load custom hooks from ${absPath}: ${msg}`);
66
82
  hookLogError(`failed to load custom hooks from ${absPath}: ${msg}`);
67
83
  } finally {
@@ -148,7 +164,7 @@ export async function loadAllCustomHooks(
148
164
  const projectFiles = discoverPolicyFiles(projectDir);
149
165
  for (const file of projectFiles) {
150
166
  const hooksBefore = getCustomHooks().length;
151
- await loadSingleFile(file);
167
+ await loadSingleFile(file, { conventionScope: "project" });
152
168
  const newHooks = getCustomHooks().slice(hooksBefore);
153
169
  if (newHooks.length > 0) {
154
170
  conventionSources.push({
@@ -164,7 +180,7 @@ export async function loadAllCustomHooks(
164
180
  const userFiles = discoverPolicyFiles(userDir);
165
181
  for (const file of userFiles) {
166
182
  const hooksBefore = getCustomHooks().length;
167
- await loadSingleFile(file);
183
+ await loadSingleFile(file, { conventionScope: "user" });
168
184
  const newHooks = getCustomHooks().slice(hooksBefore);
169
185
  if (newHooks.length > 0) {
170
186
  conventionSources.push({
@@ -0,0 +1,146 @@
1
+ /**
2
+ * First-run nudge for `failproofai` (no-args invocation).
3
+ *
4
+ * Fires when a user runs the bare CLI without having installed any policies on
5
+ * any detected agent CLI. PostHog data showed only ~10% of npm-installed users
6
+ * ran `failproofai policies --install`; this prompt closes the awareness gap
7
+ * by offering to run that install inline.
8
+ *
9
+ * The hooks themselves are the sentinel — if any are installed for any
10
+ * detected CLI, we never prompt again. No separate state file needed.
11
+ *
12
+ * Honors `FAILPROOFAI_NO_FIRST_RUN=1` for opt-out, falls back to a short
13
+ * stderr hint in non-TTY contexts (CI, piped invocations).
14
+ */
15
+ import * as readline from "node:readline";
16
+
17
+ import { detectInstalledClis, getIntegration } from "./integrations";
18
+ import { installHooks } from "./manager";
19
+ import { trackHookEvent } from "./hook-telemetry";
20
+ import { getInstanceId } from "../../lib/telemetry-id";
21
+ import type { IntegrationType } from "./types";
22
+
23
+ type TTYIn = NodeJS.ReadableStream & { isTTY?: boolean };
24
+ type TTYOut = NodeJS.WritableStream & { isTTY?: boolean };
25
+
26
+ export interface FirstRunNudgeOptions {
27
+ stdin?: TTYIn;
28
+ stdout?: TTYOut;
29
+ }
30
+
31
+ async function emit(event: string, props: Record<string, unknown>): Promise<void> {
32
+ try {
33
+ await trackHookEvent(getInstanceId(), event, props);
34
+ } catch {
35
+ // Telemetry must never break first-run UX.
36
+ }
37
+ }
38
+
39
+ function anyHooksInstalled(detected: IntegrationType[]): boolean {
40
+ for (const id of detected) {
41
+ const integration = getIntegration(id);
42
+ for (const scope of integration.scopes) {
43
+ try {
44
+ if (integration.hooksInstalledInSettings(scope)) return true;
45
+ } catch {
46
+ // A broken settings file shouldn't suppress the nudge.
47
+ }
48
+ }
49
+ }
50
+ return false;
51
+ }
52
+
53
+ function clisLabel(detected: IntegrationType[]): string {
54
+ return detected.map((id) => getIntegration(id).displayName).join(", ");
55
+ }
56
+
57
+ async function promptYesNo(
58
+ stdin: TTYIn,
59
+ stdout: TTYOut,
60
+ ): Promise<"yes" | "no" | "sigint"> {
61
+ return new Promise((resolve) => {
62
+ const rl = readline.createInterface({ input: stdin, output: stdout });
63
+ let settled = false;
64
+ const finish = (answer: "yes" | "no" | "sigint") => {
65
+ if (settled) return;
66
+ settled = true;
67
+ rl.close();
68
+ resolve(answer);
69
+ };
70
+ rl.on("SIGINT", () => finish("sigint"));
71
+ rl.question("Install policies now? [Y/n] ", (raw) => {
72
+ const a = (raw ?? "").trim().toLowerCase();
73
+ if (a === "" || a === "y" || a === "yes") finish("yes");
74
+ else finish("no");
75
+ });
76
+ });
77
+ }
78
+
79
+ export async function maybeRunFirstRunNudge(opts: FirstRunNudgeOptions = {}): Promise<void> {
80
+ if (process.env.FAILPROOFAI_NO_FIRST_RUN === "1") return;
81
+
82
+ const stdin: TTYIn = opts.stdin ?? process.stdin;
83
+ const stdout: TTYOut = opts.stdout ?? process.stdout;
84
+
85
+ let detected: IntegrationType[];
86
+ try {
87
+ detected = detectInstalledClis();
88
+ } catch {
89
+ return;
90
+ }
91
+ if (detected.length === 0) return;
92
+
93
+ if (anyHooksInstalled(detected)) return;
94
+
95
+ const detectedProps = { detected_clis: detected, detected_count: detected.length };
96
+
97
+ if (!stdin.isTTY || !stdout.isTTY) {
98
+ stdout.write(
99
+ `\n[failproofai] No policies are installed. Run \`failproofai policies --install\` to set them up.\n` +
100
+ `[failproofai] Launching dashboard…\n\n`,
101
+ );
102
+ await emit("first_run_nudge_skipped_noninteractive", detectedProps);
103
+ return;
104
+ }
105
+
106
+ stdout.write(
107
+ `\n┌─ Failproof AI — first-run setup ────────────────────────────────────\n` +
108
+ `│ Detected agent CLI(s): ${clisLabel(detected)}\n` +
109
+ `│ Policies block unsafe actions (sudo, rm -rf /, secret leaks, …)\n` +
110
+ `│ before your agent runs them. Nothing is installed yet.\n` +
111
+ `└──────────────────────────────────────────────────────────────────────\n\n` +
112
+ ` Disable this prompt anytime: FAILPROOFAI_NO_FIRST_RUN=1\n\n`,
113
+ );
114
+
115
+ await emit("first_run_nudge_shown", detectedProps);
116
+
117
+ const answer = await promptYesNo(stdin, stdout);
118
+
119
+ if (answer === "sigint") {
120
+ await emit("first_run_nudge_declined", { ...detectedProps, reason: "sigint" });
121
+ process.exit(130);
122
+ }
123
+
124
+ if (answer === "no") {
125
+ await emit("first_run_nudge_declined", { ...detectedProps, reason: "user_no" });
126
+ return;
127
+ }
128
+
129
+ await emit("first_run_nudge_accepted", {
130
+ ...detectedProps,
131
+ target_scope: "user",
132
+ source: "first-run-nudge",
133
+ });
134
+
135
+ await installHooks(
136
+ undefined,
137
+ "user",
138
+ undefined,
139
+ false,
140
+ "first-run-nudge",
141
+ undefined,
142
+ false,
143
+ detected,
144
+ );
145
+ process.exit(0);
146
+ }