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
@@ -0,0 +1,369 @@
1
+ /**
2
+ * `runAudit` — entry point for the `failproofai audit` command.
3
+ *
4
+ * Drives the pipeline: per-CLI adapters → tool events → (replay + audit
5
+ * detectors) → per-transcript results → aggregated `AuditResult`.
6
+ *
7
+ * Parallelizes transcript scans via `lib/concurrency.ts` `batchAll` (8 at a
8
+ * time — bounds disk I/O without overwhelming the policy engine).
9
+ */
10
+ import { batchAll } from "../../lib/concurrency";
11
+ import { BUILTIN_POLICIES } from "../hooks/builtin-policies";
12
+ import { readMergedHooksConfig } from "../hooks/hooks-config";
13
+ import { normalizePolicyName } from "../hooks/policy-registry";
14
+ import { INTEGRATION_TYPES, type IntegrationType } from "../hooks/types";
15
+ import { ADAPTERS } from "./cli-adapters";
16
+ import { AUDIT_DETECTORS } from "./detectors";
17
+ import { readCachedTranscriptResult, writeCachedTranscriptResult } from "./cache";
18
+ import { initReplay, replayEvent } from "./replay";
19
+ import {
20
+ trackAuditCompleted,
21
+ trackAuditInstallCtaShown,
22
+ trackAuditPatternDetected,
23
+ trackAuditStarted,
24
+ } from "./telemetry";
25
+ import {
26
+ AUDIT_EXAMPLE_MAX_CHARS,
27
+ AUDIT_MAX_EXAMPLES_PER_NAME,
28
+ type AuditCount,
29
+ type AuditResult,
30
+ type DetectorSessionState,
31
+ type NormalizedToolEvent,
32
+ type RunAuditOptions,
33
+ type TranscriptAuditResult,
34
+ type TranscriptMetadata,
35
+ } from "./types";
36
+
37
+ const TRANSCRIPT_CONCURRENCY = 8;
38
+
39
+ /** Canonicalize a policy name to its short, qualified form for display
40
+ * (`failproofai/foo` → `foo`). */
41
+ function shortPolicyName(name: string): string {
42
+ const slash = name.indexOf("/");
43
+ return slash >= 0 ? name.slice(slash + 1) : name;
44
+ }
45
+
46
+ /** Look up a builtin policy definition by canonical name; null when the name
47
+ * doesn't match a builtin (e.g. user custom policy). */
48
+ function findBuiltin(name: string) {
49
+ const short = shortPolicyName(name);
50
+ for (const p of BUILTIN_POLICIES) {
51
+ if (p.name === name || shortPolicyName(p.name) === short) return p;
52
+ }
53
+ return null;
54
+ }
55
+
56
+ /** Build the per-row install hint shown in the report:
57
+ * - Already enabled builtin: a check phrase ("Already enforced — currently blocking these in real time")
58
+ * - Unenabled builtin: `failproofai policies --install <short-name>`
59
+ * - Audit-only detector: soft notice ("Audit-only — `failproofai audit` will keep tracking these")
60
+ * - Unknown / custom: empty string
61
+ */
62
+ function buildInstallHint(
63
+ name: string,
64
+ source: "builtin" | "audit-detector",
65
+ enabled: boolean,
66
+ ): string {
67
+ if (source === "audit-detector") {
68
+ return "Audit-only — `failproofai audit` will keep tracking these.";
69
+ }
70
+ if (enabled) {
71
+ return "Already enforced — failproofai is blocking these in real time.";
72
+ }
73
+ return `Enable in one command: failproofai policies --install ${shortPolicyName(name)}`;
74
+ }
75
+
76
+ function truncateExample(s: string): string {
77
+ if (s.length <= AUDIT_EXAMPLE_MAX_CHARS) return s;
78
+ return s.slice(0, AUDIT_EXAMPLE_MAX_CHARS - 1) + "…";
79
+ }
80
+
81
+ function parseSinceOpt(since: string | undefined): number | undefined {
82
+ if (!since) return undefined;
83
+ const m = /^(\d+)\s*([dhm])$/i.exec(since.trim());
84
+ if (m) {
85
+ const n = parseInt(m[1], 10);
86
+ const unit = m[2].toLowerCase();
87
+ const ms = unit === "d" ? 86400000 : unit === "h" ? 3600000 : 60000;
88
+ return Date.now() - n * ms;
89
+ }
90
+ const t = Date.parse(since);
91
+ if (!Number.isNaN(t)) return t;
92
+ throw new Error(`Invalid --since value: "${since}" (expected e.g. "7d", "30d", or "2026-04-01")`);
93
+ }
94
+
95
+ async function scanOneTranscript(meta: TranscriptMetadata): Promise<TranscriptAuditResult> {
96
+ const empty: TranscriptAuditResult = {
97
+ transcriptPath: meta.transcriptPath,
98
+ cli: meta.cli,
99
+ projectName: meta.projectName,
100
+ sessionId: meta.sessionId,
101
+ mtimeMs: meta.mtimeMs,
102
+ sizeBytes: meta.sizeBytes,
103
+ hitsByName: {},
104
+ examplesByName: {},
105
+ rangeByName: {},
106
+ };
107
+
108
+ // Stream failures must propagate so the orchestrator counts them in
109
+ // `errors` rather than silently returning an empty hits map.
110
+ const events = await ADAPTERS[meta.cli].streamEvents(meta);
111
+ if (events.length === 0) return empty;
112
+
113
+ const result = empty;
114
+ const sessionState: DetectorSessionState = {};
115
+
116
+ for (const event of events) {
117
+ // Run audit detectors first (stateful, must see every event).
118
+ for (const detector of AUDIT_DETECTORS) {
119
+ const hit = detector.detect(event, sessionState);
120
+ if (!hit) continue;
121
+ recordHit(
122
+ result,
123
+ detector.name,
124
+ event.timestamp,
125
+ event.cwd,
126
+ truncateExample(hit.example),
127
+ );
128
+ }
129
+ // Then replay through every builtin policy.
130
+ let replayHits;
131
+ try {
132
+ replayHits = await replayEvent(event);
133
+ } catch {
134
+ continue;
135
+ }
136
+ for (const hit of replayHits) {
137
+ const example = formatPolicyExample(hit.policyName, event);
138
+ recordHit(
139
+ result,
140
+ hit.policyName,
141
+ event.timestamp,
142
+ event.cwd,
143
+ truncateExample(example),
144
+ );
145
+ }
146
+ }
147
+
148
+ return result;
149
+ }
150
+
151
+ function formatPolicyExample(_policyName: string, event: NormalizedToolEvent): string {
152
+ if (event.toolName === "Bash") {
153
+ const command = (event.toolInput as { command?: unknown }).command;
154
+ if (typeof command === "string") return command.replace(/\s+/g, " ");
155
+ }
156
+ const filePath = (event.toolInput as { file_path?: unknown }).file_path;
157
+ if (typeof filePath === "string") return `${event.toolName} ${filePath}`;
158
+ return `${event.toolName}`;
159
+ }
160
+
161
+ function recordHit(
162
+ result: TranscriptAuditResult,
163
+ name: string,
164
+ timestamp: string,
165
+ cwd: string,
166
+ example: string,
167
+ ): void {
168
+ result.hitsByName[name] = (result.hitsByName[name] ?? 0) + 1;
169
+ const exs = result.examplesByName[name] ?? [];
170
+ if (exs.length < AUDIT_MAX_EXAMPLES_PER_NAME) {
171
+ exs.push({ timestamp, cwd, example });
172
+ result.examplesByName[name] = exs;
173
+ }
174
+ const range = result.rangeByName[name];
175
+ if (!range) {
176
+ result.rangeByName[name] = { first: timestamp, last: timestamp };
177
+ } else {
178
+ if (timestamp < range.first) range.first = timestamp;
179
+ if (timestamp > range.last) range.last = timestamp;
180
+ }
181
+ }
182
+
183
+ function aggregateResults(
184
+ perTranscript: TranscriptAuditResult[],
185
+ enabledBuiltins: Set<string>,
186
+ ): AuditCount[] {
187
+ // For each name: sum hits, count distinct projects, merge ranges + examples.
188
+ const byName = new Map<string, {
189
+ hits: number;
190
+ projects: Set<string>;
191
+ examples: { sessionId: string; cwd: string; timestamp: string; example: string }[];
192
+ first?: string;
193
+ last?: string;
194
+ }>();
195
+
196
+ for (const t of perTranscript) {
197
+ for (const [name, count] of Object.entries(t.hitsByName)) {
198
+ const bucket = byName.get(name) ?? {
199
+ hits: 0,
200
+ projects: new Set<string>(),
201
+ examples: [],
202
+ };
203
+ bucket.hits += count;
204
+ bucket.projects.add(t.projectName);
205
+ const tExs = t.examplesByName[name] ?? [];
206
+ for (const e of tExs) {
207
+ if (bucket.examples.length < AUDIT_MAX_EXAMPLES_PER_NAME) {
208
+ bucket.examples.push({ ...e, sessionId: t.sessionId });
209
+ }
210
+ }
211
+ const range = t.rangeByName[name];
212
+ if (range) {
213
+ if (!bucket.first || range.first < bucket.first) bucket.first = range.first;
214
+ if (!bucket.last || range.last > bucket.last) bucket.last = range.last;
215
+ }
216
+ byName.set(name, bucket);
217
+ }
218
+ }
219
+
220
+ const detectorByName = new Map(AUDIT_DETECTORS.map((d) => [d.name, d]));
221
+ const out: AuditCount[] = [];
222
+ for (const [name, bucket] of byName) {
223
+ const detector = detectorByName.get(name);
224
+ const isDetector = !!detector;
225
+ const builtin = isDetector ? null : findBuiltin(name);
226
+ const source: "builtin" | "audit-detector" = isDetector ? "audit-detector" : "builtin";
227
+ const enabled = isDetector ? false : enabledBuiltins.has(normalizePolicyName(name));
228
+
229
+ const displayTitle =
230
+ detector?.displayTitle
231
+ ?? builtin?.displayTitle
232
+ ?? detector?.description
233
+ ?? builtin?.description
234
+ ?? shortPolicyName(name);
235
+ const impact = detector?.impact ?? builtin?.impact ?? "";
236
+
237
+ out.push({
238
+ name,
239
+ source,
240
+ category: detector?.category ?? builtin?.category ?? "Custom",
241
+ severity: isDetector ? (detector?.severity ?? "info") : "deny",
242
+ hits: bucket.hits,
243
+ projects: bucket.projects.size,
244
+ firstSeen: bucket.first,
245
+ lastSeen: bucket.last,
246
+ examples: bucket.examples,
247
+ displayTitle,
248
+ impact,
249
+ enabledInConfig: enabled,
250
+ installHint: buildInstallHint(name, source, enabled),
251
+ });
252
+ }
253
+
254
+ out.sort((a, b) => b.hits - a.hits);
255
+ return out;
256
+ }
257
+
258
+ export async function runAudit(opts: RunAuditOptions = {}): Promise<AuditResult> {
259
+ const startedAt = Date.now();
260
+ initReplay();
261
+
262
+ const outputMode = opts.json ? "json" : opts.noReport ? "text" : "text+markdown";
263
+ trackAuditStarted(opts, outputMode);
264
+
265
+ const clis = (opts.clis ?? Array.from(INTEGRATION_TYPES)) as IntegrationType[];
266
+ const sinceMs = parseSinceOpt(opts.since);
267
+
268
+ // Snapshot which builtin policies the user currently has enabled — drives
269
+ // the "already protected" vs "slipping through" split in the report.
270
+ const userConfig = readMergedHooksConfig();
271
+ const enabledBuiltins = new Set(
272
+ (userConfig.enabledPolicies ?? []).map((n) => normalizePolicyName(n)),
273
+ );
274
+
275
+ // 1. Discover transcripts across all selected CLIs.
276
+ const allTranscripts: TranscriptMetadata[] = [];
277
+ for (const cli of clis) {
278
+ const adapter = ADAPTERS[cli];
279
+ let list: TranscriptMetadata[];
280
+ try {
281
+ list = await adapter.listTranscripts({ projects: opts.projects, sinceMs });
282
+ } catch {
283
+ continue; // adapter failures shouldn't kill the whole audit
284
+ }
285
+ allTranscripts.push(...list);
286
+ }
287
+
288
+ // 2. Scan each transcript (cache-aware), 8 in parallel.
289
+ let skipped = 0;
290
+ let errors = 0;
291
+ const tasks = allTranscripts.map((meta) => async (): Promise<TranscriptAuditResult> => {
292
+ if (!opts.noCache) {
293
+ const cached = readCachedTranscriptResult(meta.transcriptPath, meta.mtimeMs, meta.sizeBytes);
294
+ if (cached) return cached;
295
+ }
296
+ try {
297
+ const fresh = await scanOneTranscript(meta);
298
+ if (!opts.noCache) {
299
+ writeCachedTranscriptResult(meta.transcriptPath, meta.mtimeMs, meta.sizeBytes, fresh);
300
+ }
301
+ return fresh;
302
+ } catch {
303
+ errors++;
304
+ return {
305
+ transcriptPath: meta.transcriptPath,
306
+ cli: meta.cli,
307
+ projectName: meta.projectName,
308
+ sessionId: meta.sessionId,
309
+ mtimeMs: meta.mtimeMs,
310
+ sizeBytes: meta.sizeBytes,
311
+ hitsByName: {},
312
+ examplesByName: {},
313
+ rangeByName: {},
314
+ };
315
+ }
316
+ });
317
+
318
+ const settled = await batchAll(tasks, TRANSCRIPT_CONCURRENCY);
319
+ const perTranscript: TranscriptAuditResult[] = [];
320
+ for (const s of settled) {
321
+ if (s.status === "fulfilled") perTranscript.push(s.value);
322
+ else skipped++;
323
+ }
324
+
325
+ // 3. Aggregate.
326
+ let results = aggregateResults(perTranscript, enabledBuiltins);
327
+ if (opts.policies?.length) {
328
+ const wanted = new Set(opts.policies.map(shortPolicyName));
329
+ results = results.filter((r) => wanted.has(shortPolicyName(r.name)));
330
+ }
331
+
332
+ const totalsHits = results.reduce((sum, r) => sum + r.hits, 0);
333
+ const projectsWithHits = new Set<string>();
334
+ for (const t of perTranscript) {
335
+ if (Object.keys(t.hitsByName).length > 0) projectsWithHits.add(t.projectName);
336
+ }
337
+
338
+ const auditResult: AuditResult = {
339
+ version: 1,
340
+ scannedAt: new Date(startedAt).toISOString(),
341
+ scope: {
342
+ cli: clis,
343
+ projects: opts.projects ?? "all",
344
+ since: opts.since ?? null,
345
+ },
346
+ transcripts: {
347
+ scanned: allTranscripts.length,
348
+ skipped,
349
+ errors,
350
+ durationMs: Date.now() - startedAt,
351
+ },
352
+ results,
353
+ totals: {
354
+ hits: totalsHits,
355
+ projectsWithHits: projectsWithHits.size,
356
+ },
357
+ };
358
+
359
+ // Telemetry — fire-and-forget, never blocks the CLI. See src/audit/telemetry.ts
360
+ // for the privacy contract (slugs + counts + booleans only).
361
+ for (const count of results) trackAuditPatternDetected(count);
362
+ const unenabledBuiltinNames = results
363
+ .filter((r) => r.source === "builtin" && !r.enabledInConfig)
364
+ .map((r) => r.name);
365
+ trackAuditInstallCtaShown(unenabledBuiltinNames);
366
+ trackAuditCompleted(auditResult, outputMode);
367
+
368
+ return auditResult;
369
+ }
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Replay engine — turns a NormalizedToolEvent into one (or two) synthetic hook
3
+ * payloads, runs them through the existing `evaluatePolicies` function, and
4
+ * returns the policy decisions.
5
+ *
6
+ * Why two events: builtin sanitize-* policies match on PostToolUse and inspect
7
+ * the tool result text. PreToolUse alone misses them. Per event we synthesize:
8
+ * 1. PreToolUse — { tool_name, tool_input }
9
+ * 2. PostToolUse — { tool_name, tool_input, tool_response } (only when the
10
+ * transcript captured a tool_result)
11
+ *
12
+ * Workflow policies (`require-*-before-stop`) match only on `Stop` and
13
+ * execSync against live git, so they never fire on PreToolUse/PostToolUse
14
+ * replay — no explicit skip needed.
15
+ */
16
+ import type { EvaluationResult } from "../hooks/policy-evaluator";
17
+ import { evaluatePolicies } from "../hooks/policy-evaluator";
18
+ import { BUILTIN_POLICIES, registerBuiltinPolicies } from "../hooks/builtin-policies";
19
+ import { clearPolicies, normalizePolicyName } from "../hooks/policy-registry";
20
+ import type { SessionMetadata } from "../hooks/types";
21
+ import type { NormalizedToolEvent } from "./types";
22
+
23
+ /** Policies the audit skips on purpose. `warn-repeated-tool-calls` mutates a
24
+ * per-session sidecar file on every evaluation, which would pollute the
25
+ * user's real transcript directory during a replay (and inflate counts
26
+ * because the replay always re-traverses the full session). */
27
+ const SKIP_POLICIES = new Set(
28
+ ["warn-repeated-tool-calls"].map((n) => normalizePolicyName(n)),
29
+ );
30
+
31
+ let initialized = false;
32
+
33
+ /** Register every builtin policy (regardless of user config) so the replay
34
+ * shows what *could* be caught, not just what's currently enabled. Called
35
+ * once per `runAudit` invocation. */
36
+ export function initReplay(): void {
37
+ if (initialized) return;
38
+ clearPolicies();
39
+ const enabled = BUILTIN_POLICIES
40
+ .map((p) => p.name)
41
+ .filter((n) => !SKIP_POLICIES.has(normalizePolicyName(n)));
42
+ registerBuiltinPolicies(enabled);
43
+ initialized = true;
44
+ }
45
+
46
+ /** Reset for tests / repeated audits in the same process. */
47
+ export function resetReplay(): void {
48
+ initialized = false;
49
+ clearPolicies();
50
+ }
51
+
52
+ export interface ReplayHit {
53
+ policyName: string;
54
+ decision: "deny" | "instruct" | "allow";
55
+ reason: string | null;
56
+ eventType: "PreToolUse" | "PostToolUse";
57
+ }
58
+
59
+ /** Replay one normalized tool event through every registered policy. Returns
60
+ * one ReplayHit per non-allow decision (deny + instruct). Allow-with-reason
61
+ * is reported too, so sanitize policies that emit informational notes still
62
+ * surface in the audit. */
63
+ export async function replayEvent(event: NormalizedToolEvent): Promise<ReplayHit[]> {
64
+ if (!initialized) initReplay();
65
+
66
+ const session: SessionMetadata = {
67
+ sessionId: event.sessionId,
68
+ transcriptPath: event.transcriptPath,
69
+ cwd: event.cwd,
70
+ cli: event.cli,
71
+ };
72
+
73
+ const baseToolPayload: Record<string, unknown> = {
74
+ tool_name: event.toolName,
75
+ tool_input: event.toolInput,
76
+ session_id: event.sessionId,
77
+ cwd: event.cwd,
78
+ transcript_path: event.transcriptPath,
79
+ };
80
+
81
+ const out: ReplayHit[] = [];
82
+
83
+ // PreToolUse
84
+ const pre = await evaluatePolicies("PreToolUse", baseToolPayload, session);
85
+ collectHits(pre, "PreToolUse", out);
86
+
87
+ // PostToolUse — only if the transcript captured a tool result.
88
+ if (event.toolResultText !== undefined) {
89
+ const postPayload = { ...baseToolPayload, tool_response: event.toolResultText };
90
+ const post = await evaluatePolicies("PostToolUse", postPayload, session);
91
+ collectHits(post, "PostToolUse", out);
92
+ }
93
+
94
+ return out;
95
+ }
96
+
97
+ function collectHits(
98
+ result: EvaluationResult,
99
+ eventType: "PreToolUse" | "PostToolUse",
100
+ out: ReplayHit[],
101
+ ): void {
102
+ // `policyNames` is set when multiple policies fired (sanitize stack);
103
+ // otherwise fall back to `policyName`.
104
+ const names = result.policyNames && result.policyNames.length > 0
105
+ ? result.policyNames
106
+ : result.policyName
107
+ ? [result.policyName]
108
+ : [];
109
+ for (const name of names) {
110
+ // The aggregate `decision` reflects the most severe firing, but the audit
111
+ // wants per-policy counts. We re-tag each name with the aggregate decision
112
+ // for now — accurate enough for the table; a future audit-detail mode can
113
+ // re-evaluate per-policy if precision becomes important.
114
+ out.push({
115
+ policyName: name,
116
+ decision: result.decision,
117
+ reason: result.reason,
118
+ eventType,
119
+ });
120
+ }
121
+ }