failproofai 0.0.11-beta.2 → 0.0.11-beta.4

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 (474) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +8 -1
  3. package/.next/standalone/.next/build-manifest.json +10 -10
  4. package/.next/standalone/.next/prerender-manifest.json +3 -32
  5. package/.next/standalone/.next/required-server-files.json +2 -1
  6. package/.next/standalone/.next/routes-manifest.json +45 -3
  7. package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +7 -7
  8. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  9. package/.next/standalone/.next/server/app/_global-error/page.js +6 -6
  10. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  11. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  12. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  13. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  14. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  15. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  16. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
  17. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  18. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  19. package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +7 -7
  20. package/.next/standalone/.next/server/app/_not-found/page/next-font-manifest.json +2 -6
  21. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  22. package/.next/standalone/.next/server/app/_not-found/page.js +12 -13
  23. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  25. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  26. package/.next/standalone/.next/server/app/_not-found.rsc +16 -16
  27. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +16 -16
  28. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  29. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
  30. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  31. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  32. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  33. package/.next/standalone/.next/server/app/api/audit/run/route/app-paths-manifest.json +3 -0
  34. package/.next/standalone/.next/server/app/api/audit/run/route/server-reference-manifest.json +4 -0
  35. package/.next/standalone/.next/server/app/api/audit/run/route.js +8 -0
  36. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -0
  37. package/.next/standalone/.next/server/app/api/audit/run/route_client-reference-manifest.js +3 -0
  38. package/.next/standalone/.next/server/app/api/audit/status/route/app-paths-manifest.json +3 -0
  39. package/.next/standalone/.next/server/app/api/audit/status/route/build-manifest.json +9 -0
  40. package/.next/standalone/.next/server/app/api/audit/status/route/server-reference-manifest.json +4 -0
  41. package/.next/standalone/.next/server/app/api/audit/status/route.js +6 -0
  42. package/.next/standalone/.next/server/app/api/audit/status/route.js.map +5 -0
  43. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -0
  44. package/.next/standalone/.next/server/app/api/audit/status/route_client-reference-manifest.js +3 -0
  45. package/.next/standalone/.next/server/app/api/auth/login-request/route/app-paths-manifest.json +3 -0
  46. package/.next/standalone/.next/server/app/api/auth/login-request/route/build-manifest.json +9 -0
  47. package/.next/standalone/.next/server/app/api/auth/login-request/route/server-reference-manifest.json +4 -0
  48. package/.next/standalone/.next/server/app/api/auth/login-request/route.js +6 -0
  49. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.map +5 -0
  50. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -0
  51. package/.next/standalone/.next/server/app/api/auth/login-request/route_client-reference-manifest.js +3 -0
  52. package/.next/standalone/.next/server/app/api/auth/login-verify/route/app-paths-manifest.json +3 -0
  53. package/.next/standalone/.next/server/app/api/auth/login-verify/route/build-manifest.json +9 -0
  54. package/.next/standalone/.next/server/app/api/auth/login-verify/route/server-reference-manifest.json +4 -0
  55. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +7 -0
  56. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.map +5 -0
  57. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -0
  58. package/.next/standalone/.next/server/app/api/auth/login-verify/route_client-reference-manifest.js +3 -0
  59. package/.next/standalone/.next/server/app/api/auth/logout/route/app-paths-manifest.json +3 -0
  60. package/.next/standalone/.next/server/app/api/auth/logout/route/build-manifest.json +9 -0
  61. package/.next/standalone/.next/server/app/api/auth/logout/route/server-reference-manifest.json +4 -0
  62. package/.next/standalone/.next/server/app/api/auth/logout/route.js +7 -0
  63. package/.next/standalone/.next/server/app/api/auth/logout/route.js.map +5 -0
  64. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -0
  65. package/.next/standalone/.next/server/app/api/auth/logout/route_client-reference-manifest.js +3 -0
  66. package/.next/standalone/.next/server/app/api/auth/reminder/route/app-paths-manifest.json +3 -0
  67. package/.next/standalone/.next/server/app/api/auth/reminder/route/build-manifest.json +9 -0
  68. package/.next/standalone/.next/server/app/api/auth/reminder/route/server-reference-manifest.json +4 -0
  69. package/.next/standalone/.next/server/app/api/auth/reminder/route.js +7 -0
  70. package/.next/standalone/.next/server/app/api/auth/reminder/route.js.map +5 -0
  71. package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -0
  72. package/.next/standalone/.next/server/app/api/auth/reminder/route_client-reference-manifest.js +3 -0
  73. package/.next/standalone/.next/server/app/api/auth/status/route/app-paths-manifest.json +3 -0
  74. package/.next/standalone/.next/server/app/api/auth/status/route/build-manifest.json +9 -0
  75. package/.next/standalone/.next/server/app/api/auth/status/route/server-reference-manifest.json +4 -0
  76. package/.next/standalone/.next/server/app/api/auth/status/route.js +7 -0
  77. package/.next/standalone/.next/server/app/api/auth/status/route.js.map +5 -0
  78. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -0
  79. package/.next/standalone/.next/server/app/api/auth/status/route_client-reference-manifest.js +3 -0
  80. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js +3 -3
  81. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  82. package/.next/standalone/.next/server/app/audit/page/app-paths-manifest.json +3 -0
  83. package/.next/standalone/.next/server/app/audit/page/build-manifest.json +18 -0
  84. package/.next/standalone/.next/server/app/audit/page/next-font-manifest.json +6 -0
  85. package/.next/standalone/.next/server/app/audit/page/react-loadable-manifest.json +1 -0
  86. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +29 -0
  87. package/.next/standalone/.next/server/app/audit/page.js +17 -0
  88. package/.next/standalone/.next/server/app/audit/page.js.map +5 -0
  89. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -0
  90. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +3 -0
  91. package/.next/standalone/.next/server/app/index.html +1 -1
  92. package/.next/standalone/.next/server/app/index.rsc +16 -17
  93. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  94. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +16 -17
  95. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  96. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
  97. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -3
  98. package/.next/standalone/.next/server/app/page/build-manifest.json +7 -7
  99. package/.next/standalone/.next/server/app/page/next-font-manifest.json +2 -6
  100. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  101. package/.next/standalone/.next/server/app/page.js +14 -15
  102. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  103. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  104. package/.next/standalone/.next/server/app/policies/page/build-manifest.json +7 -7
  105. package/.next/standalone/.next/server/app/policies/page/next-font-manifest.json +2 -6
  106. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
  107. package/.next/standalone/.next/server/app/policies/page.js +16 -16
  108. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  109. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  110. package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +7 -7
  111. package/.next/standalone/.next/server/app/project/[name]/page/next-font-manifest.json +2 -6
  112. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  113. package/.next/standalone/.next/server/app/project/[name]/page.js +16 -17
  114. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  115. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  116. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +7 -7
  117. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/next-font-manifest.json +2 -6
  118. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  119. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  120. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +19 -20
  121. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  122. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  123. package/.next/standalone/.next/server/app/projects/page/build-manifest.json +7 -7
  124. package/.next/standalone/.next/server/app/projects/page/next-font-manifest.json +2 -6
  125. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  126. package/.next/standalone/.next/server/app/projects/page.js +15 -16
  127. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  128. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  129. package/.next/standalone/.next/server/app-paths-manifest.json +8 -1
  130. package/.next/standalone/.next/server/chunks/[externals]__14odj07._.js +3 -0
  131. package/.next/standalone/.next/server/chunks/{[externals]__0z0j--b._.js → [externals]__1nl3dvw._.js} +1 -1
  132. package/.next/standalone/.next/server/chunks/{[externals]__0-p9.k~._.js → [externals]__1s61mel._.js} +1 -1
  133. package/.next/standalone/.next/server/chunks/{[externals]_node_os_06ur78j._.js → [externals]_node_os_0by37l-._.js} +1 -1
  134. package/.next/standalone/.next/server/chunks/[root-of-the-server]__07tgnzi._.js +3 -0
  135. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0kjo7d_._.js → [root-of-the-server]__0_0xu5z._.js} +2 -2
  136. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cag8qd._.js +3 -0
  137. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0z-180.._.js → [root-of-the-server]__0cycwg6._.js} +2 -2
  138. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__08px0ym._.js → [root-of-the-server]__0f7mikp._.js} +1 -1
  139. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0oeun7z._.js +3 -0
  140. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q-v9z2._.js +3 -0
  141. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0rv7m0k._.js +3 -0
  142. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0g48iv.._.js → [root-of-the-server]__0sb_5m8._.js} +3 -3
  143. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0j8-xkl._.js → [root-of-the-server]__0xuaoik._.js} +2 -2
  144. package/.next/standalone/.next/server/chunks/[root-of-the-server]__12pit4m._.js +3 -0
  145. package/.next/standalone/.next/server/chunks/[root-of-the-server]__13h8pzr._.js +3 -0
  146. package/.next/standalone/.next/server/chunks/[root-of-the-server]__13ra2jq._.js +3 -0
  147. package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +3 -0
  148. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0d_ob4n._.js → [root-of-the-server]__1_mqemn._.js} +2 -2
  149. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1b9z5-i._.js +3 -0
  150. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0vlhtkc._.js → [root-of-the-server]__1hgv_75._.js} +1 -1
  151. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ixjiy8._.js +3 -0
  152. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0wu7fr7._.js → [root-of-the-server]__1jm9fw6._.js} +1 -1
  153. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1legmza._.js +3 -0
  154. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0fwb7ao._.js → [root-of-the-server]__1m2_4t0._.js} +2 -2
  155. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0yfq1yr._.js → [root-of-the-server]__1mhmdzs._.js} +1 -1
  156. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0zso~62._.js → [root-of-the-server]__1ou2ehh._.js} +1 -1
  157. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1qxztj-._.js +3 -0
  158. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1rhmvod._.js +3 -0
  159. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0.~nmr9._.js → [root-of-the-server]__1w9zl9-._.js} +1 -1
  160. package/.next/standalone/.next/server/chunks/{_0ebx_lc._.js → _0p53ge1._.js} +2 -2
  161. package/.next/standalone/.next/server/chunks/_1-1804f._.js +3 -0
  162. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_audit_run_route_actions_1qgp9io.js +3 -0
  163. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_audit_status_route_actions_1f7pjof.js +3 -0
  164. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_auth_login-request_route_actions_1c49co0.js +3 -0
  165. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_auth_login-verify_route_actions_1r3slzk.js +3 -0
  166. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_auth_logout_route_actions_0regwyr.js +3 -0
  167. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_auth_reminder_route_actions_1kjgxf8.js +3 -0
  168. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_auth_status_route_actions_1aho9zu.js +3 -0
  169. package/.next/standalone/.next/server/chunks/{_next-internal_server_app_api_download_[project]_[session]_route_actions_0wb00i-.js → _next-internal_server_app_api_download_[project]_[session]_route_actions_1is7vs7.js} +1 -1
  170. package/.next/standalone/.next/server/chunks/{lib_logger_ts_047tt9f._.js → lib_logger_ts_07e65t5._.js} +1 -1
  171. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +23 -0
  172. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_01r25oi._.js +3 -0
  173. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_09z9-p7._.js +3 -0
  174. package/.next/standalone/.next/server/chunks/{package_json_[json]_cjs_0z7w.hh._.js → package_json_[json]_cjs_1nxcc4v._.js} +2 -2
  175. package/.next/standalone/.next/server/chunks/ssr/{[externals]__12dv.x0._.js → [externals]__1_g_b3t._.js} +1 -1
  176. package/.next/standalone/.next/server/chunks/ssr/{[externals]_node_async_hooks_0v0ln8c._.js → [externals]_node_async_hooks_1gjz99j._.js} +1 -1
  177. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0ts150~._.js → [root-of-the-server]__0-wdurj._.js} +2 -2
  178. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__00jkjmt._.js +4 -0
  179. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013du6r._.js +4 -0
  180. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__06f-yix._.js +3 -0
  181. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0989_dx._.js +3 -0
  182. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e85wxv._.js +4 -0
  183. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0gfxvb1._.js +3 -0
  184. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h12me5._.js +3 -0
  185. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0l13qf2._.js +3 -0
  186. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1-scthx._.js +3 -0
  187. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11rtg6s._.js +3 -0
  188. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__14dd6h8._.js +3 -0
  189. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1cd25c7._.js +4 -0
  190. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0t5l7a5._.js → [root-of-the-server]__1d8omgc._.js} +1 -1
  191. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0tcyn68._.js → [root-of-the-server]__1dky4g0._.js} +1 -1
  192. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__098zro9._.js → [root-of-the-server]__1fax1sl._.js} +4 -4
  193. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1hlrq6y._.js +4 -0
  194. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ihxdo5._.js +4 -0
  195. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1mt35_w._.js +221 -0
  196. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0-wn51s._.js → [root-of-the-server]__1pcxxwg._.js} +3 -3
  197. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1usf8v2._.js +3 -0
  198. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1vvfde2._.js +4 -0
  199. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__212nf49._.js +3 -0
  200. package/.next/standalone/.next/server/chunks/ssr/{_03d7qyt._.js → _05whahf._.js} +1 -1
  201. package/.next/standalone/.next/server/chunks/ssr/_11_p9y8._.js +3 -0
  202. package/.next/standalone/.next/server/chunks/ssr/{_0xb8ngh._.js → _1kje4fm._.js} +1 -1
  203. package/.next/standalone/.next/server/chunks/ssr/{_0zx~s__._.js → _1p0-leb._.js} +1 -1
  204. package/.next/standalone/.next/server/chunks/ssr/{app_04qfs8z._.js → app_087bt9w._.js} +1 -1
  205. package/.next/standalone/.next/server/chunks/ssr/{app_0uosk1e._.js → app_1fvisnp._.js} +1 -1
  206. package/.next/standalone/.next/server/chunks/ssr/{app_13f0ohr._.js → app_209u41o._.js} +1 -1
  207. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +43 -0
  208. package/.next/standalone/.next/server/chunks/ssr/app_audit_loading_tsx_1j1kc6j._.js +3 -0
  209. package/.next/standalone/.next/server/chunks/ssr/{app_error_tsx_11t4ysq._.js → app_error_tsx_1zds1ns._.js} +1 -1
  210. package/.next/standalone/.next/server/chunks/ssr/{app_global-error_tsx_0m9qisk._.js → app_global-error_tsx_113y3za._.js} +1 -1
  211. package/.next/standalone/.next/server/chunks/ssr/{app_global-error_tsx_0xerkr6._.js → app_global-error_tsx_1kp6l3x._.js} +2 -2
  212. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +8 -0
  213. package/.next/standalone/.next/server/chunks/ssr/{app_project_[name]_error_tsx_0.9-fod._.js → app_project_[name]_error_tsx_1v02_5n._.js} +1 -1
  214. package/.next/standalone/.next/server/chunks/ssr/{app_project_[name]_loading_tsx_03g9xy0._.js → app_project_[name]_loading_tsx_05-l4uf._.js} +1 -1
  215. package/.next/standalone/.next/server/chunks/ssr/{app_project_[name]_session_[sessionId]_error_tsx_0ler-mr._.js → app_project_[name]_session_[sessionId]_error_tsx_0-lj3nd._.js} +1 -1
  216. package/.next/standalone/.next/server/chunks/ssr/{app_project_[name]_session_[sessionId]_loading_tsx_0c0e3yx._.js → app_project_[name]_session_[sessionId]_loading_tsx_0l4aixs._.js} +1 -1
  217. package/.next/standalone/.next/server/chunks/ssr/app_projects_loading_tsx_20-3u8b._.js +3 -0
  218. package/.next/standalone/.next/server/chunks/ssr/{lib_codex-projects_ts_0eosib~._.js → lib_codex-projects_ts_0pqlw37._.js} +1 -1
  219. package/.next/standalone/.next/server/chunks/ssr/{lib_copilot-projects_ts_0r8xkn8._.js → lib_copilot-projects_ts_19wl7tp._.js} +1 -1
  220. package/.next/standalone/.next/server/chunks/ssr/{lib_cursor-projects_ts_0qt1scg._.js → lib_cursor-projects_ts_18-iwyk._.js} +1 -1
  221. package/.next/standalone/.next/server/chunks/ssr/{lib_gemini-projects_ts_0sl~yqr._.js → lib_gemini-projects_ts_1c7bgx-._.js} +1 -1
  222. package/.next/standalone/.next/server/chunks/ssr/{lib_opencode-projects_ts_0op9gyp._.js → lib_opencode-projects_ts_15bjxkm._.js} +1 -1
  223. package/.next/standalone/.next/server/chunks/ssr/{lib_pi-projects_ts_103tsh1._.js → lib_pi-projects_ts_1wikofb._.js} +1 -1
  224. package/.next/standalone/.next/server/chunks/ssr/{lib_utils_ts_068jk73._.js → lib_utils_ts_0az0sfq._.js} +1 -1
  225. package/.next/standalone/.next/server/chunks/ssr/node_modules_1ynf7el._.js +3 -0
  226. package/.next/standalone/.next/server/chunks/ssr/node_modules_html2canvas_dist_html2canvas_esm_0hmsdod.js +3 -0
  227. package/.next/standalone/.next/server/chunks/ssr/node_modules_html2canvas_dist_html2canvas_esm_1n-0xws.js +3 -0
  228. package/.next/standalone/.next/server/chunks/ssr/{node_modules_next_0rd0oc-._.js → node_modules_next_1a1kch7._.js} +1 -1
  229. package/.next/standalone/.next/server/chunks/ssr/{node_modules_next_dist_0h9llsw._.js → node_modules_next_dist_0uboya6._.js} +2 -2
  230. package/.next/standalone/.next/server/chunks/ssr/{node_modules_next_dist_11dij6w._.js → node_modules_next_dist_1d_onnt._.js} +3 -3
  231. package/.next/standalone/.next/server/chunks/ssr/{node_modules_next_dist_client_components_0inhx6q._.js → node_modules_next_dist_client_components_0wpq8j3._.js} +1 -1
  232. package/.next/standalone/.next/server/chunks/ssr/{node_modules_next_dist_client_components_builtin_forbidden_0ghu-f7.js → node_modules_next_dist_client_components_builtin_forbidden_0symwr9.js} +1 -1
  233. package/.next/standalone/.next/server/chunks/ssr/{node_modules_next_dist_client_components_builtin_unauthorized_0cjv-23.js → node_modules_next_dist_client_components_builtin_unauthorized_0l_sp0x.js} +1 -1
  234. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0-uvagv.js +4 -0
  235. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_03c7gi5.js +4 -0
  236. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_09p-8om.js +4 -0
  237. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0v-kfiu.js +4 -0
  238. package/.next/standalone/.next/server/chunks/ssr/{node_modules_next_dist_esm_build_templates_app-page_0j79~gv.js → node_modules_next_dist_esm_build_templates_app-page_0xrgzyz.js} +1 -1
  239. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_1806lsc.js +4 -0
  240. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_1j6dd-e.js +4 -0
  241. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_1sa65r-.js +4 -0
  242. package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_11bnuzn._.js +3 -0
  243. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1ezd2jf._.js +5 -0
  244. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1tnuifj._.js +5 -0
  245. package/.next/standalone/.next/server/functions-config-manifest.json +3 -0
  246. package/.next/standalone/.next/server/instrumentation.js +1 -1
  247. package/.next/standalone/.next/server/middleware-build-manifest.js +10 -10
  248. package/.next/standalone/.next/server/middleware.js +2 -2
  249. package/.next/standalone/.next/server/next-font-manifest.js +1 -1
  250. package/.next/standalone/.next/server/next-font-manifest.json +2 -21
  251. package/.next/standalone/.next/server/pages/404.html +1 -1
  252. package/.next/standalone/.next/server/pages/500.html +1 -1
  253. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  254. package/.next/standalone/.next/server/server-reference-manifest.json +27 -9
  255. package/.next/standalone/.next/static/chunks/{07uz2g0_38qia.js → 03fmihek9n986.js} +1 -1
  256. package/.next/standalone/.next/static/chunks/09ueq8s1as8xs.css +2 -0
  257. package/.next/standalone/.next/static/chunks/0fkntmojmibda.js +6 -0
  258. package/.next/standalone/.next/static/chunks/{11w14gnqzprir.js → 0nbmu4_n1j2-c.js} +1 -1
  259. package/.next/standalone/.next/static/chunks/0qassxjx1ef04.js +1 -0
  260. package/.next/standalone/.next/static/chunks/0zbxssxh53n-3.js +1 -0
  261. package/.next/standalone/.next/static/chunks/13f1kmjea-0md.js +2 -0
  262. package/.next/standalone/.next/static/chunks/1btx2c49fk9xt.css +1 -0
  263. package/.next/standalone/.next/static/chunks/1bxdpd036n3l9.js +41 -0
  264. package/.next/standalone/.next/static/chunks/{0bke.~atnsbeb.js → 1e0o-6kjfnwzh.js} +1 -1
  265. package/.next/standalone/.next/static/chunks/20b5bz43so-1k.js +1 -0
  266. package/.next/standalone/.next/static/chunks/2zjavpea8glet.js +1 -0
  267. package/.next/standalone/.next/static/chunks/{0d3shmwh5_nmn.js → 33u59vf_8xpd-.js} +1 -1
  268. package/.next/standalone/.next/static/chunks/{0dvhi-prcsh3~.js → 36l507r2mbf5h.js} +1 -1
  269. package/.next/standalone/.next/static/chunks/3gti1qdk5epqn.js +1 -0
  270. package/.next/standalone/.next/static/chunks/{17mubwtqwijpu.js → 3w8d8k_dca5rp.js} +1 -1
  271. package/.next/standalone/.next/static/chunks/{0bv1oyxspkpkb.js → 3y3l184vijlfg.js} +1 -1
  272. package/.next/standalone/.next/static/chunks/41jjdgqqpl7em.js +1 -0
  273. package/.next/standalone/.next/static/chunks/{turbopack-0nh.aopesgj~5.js → turbopack-00qy7zfa7m--m.js} +1 -1
  274. package/.next/standalone/SECURITY.md +73 -0
  275. package/.next/standalone/app/actions/get-audit-result.ts +24 -0
  276. package/.next/standalone/app/api/audit/_state.ts +72 -0
  277. package/.next/standalone/app/api/audit/run/route.ts +89 -0
  278. package/.next/standalone/app/api/audit/status/route.ts +23 -0
  279. package/.next/standalone/app/api/auth/login-request/route.ts +91 -0
  280. package/.next/standalone/app/api/auth/login-verify/route.ts +98 -0
  281. package/.next/standalone/app/api/auth/logout/route.ts +48 -0
  282. package/.next/standalone/app/api/auth/reminder/route.ts +213 -0
  283. package/.next/standalone/app/api/auth/status/route.ts +42 -0
  284. package/.next/standalone/app/audit/_components/audit-dashboard.tsx +364 -0
  285. package/.next/standalone/app/audit/_components/auth-dialog.tsx +401 -0
  286. package/.next/standalone/app/audit/_components/empty-state.tsx +146 -0
  287. package/.next/standalone/app/audit/_components/findings-section.tsx +135 -0
  288. package/.next/standalone/app/audit/_components/identity-section.tsx +126 -0
  289. package/.next/standalone/app/audit/_components/policies-section.tsx +194 -0
  290. package/.next/standalone/app/audit/_components/report-footer.tsx +35 -0
  291. package/.next/standalone/app/audit/_components/rerun-button.tsx +81 -0
  292. package/.next/standalone/app/audit/_components/return-section.tsx +428 -0
  293. package/.next/standalone/app/audit/_components/run-progress.tsx +120 -0
  294. package/.next/standalone/app/audit/_components/score-section.tsx +179 -0
  295. package/.next/standalone/app/audit/_components/share-dock.tsx +265 -0
  296. package/.next/standalone/app/audit/_components/share-templates.ts +67 -0
  297. package/.next/standalone/app/audit/_components/show-off-cta.tsx +135 -0
  298. package/.next/standalone/app/audit/_components/sigil.tsx +93 -0
  299. package/.next/standalone/app/audit/_components/strengths-section.tsx +57 -0
  300. package/.next/standalone/app/audit/audit-styles.css +2066 -0
  301. package/.next/standalone/app/audit/loading.tsx +24 -0
  302. package/.next/standalone/app/audit/page.tsx +53 -0
  303. package/.next/standalone/app/globals.css +570 -137
  304. package/.next/standalone/app/layout.tsx +16 -9
  305. package/.next/standalone/app/policies/hooks-client.tsx +223 -129
  306. package/.next/standalone/app/project/[name]/page.tsx +89 -39
  307. package/.next/standalone/app/projects/loading.tsx +30 -8
  308. package/.next/standalone/app/projects/page.tsx +76 -18
  309. package/.next/standalone/assets/audit/Audit Report.html +22 -0
  310. package/.next/standalone/assets/audit/Show Off Your Agent.html +22 -0
  311. package/.next/standalone/assets/audit/archetypes.jsx +277 -0
  312. package/.next/standalone/assets/audit/assets/fonts/bitcount-prop-single.woff2 +0 -0
  313. package/.next/standalone/assets/audit/audit.jsx +825 -0
  314. package/.next/standalone/assets/audit/poster-styles.css +424 -0
  315. package/.next/standalone/assets/audit/poster.jsx +247 -0
  316. package/.next/standalone/assets/audit/screenshots/poster-optimist.png +0 -0
  317. package/.next/standalone/assets/audit/screenshots/poster-scrolled.png +0 -0
  318. package/.next/standalone/assets/audit/styles.css +1225 -0
  319. package/.next/standalone/assets/audit/tweaks-panel.jsx +425 -0
  320. package/.next/standalone/assets/logos/company/icon.svg +1 -0
  321. package/.next/standalone/assets/logos/company/logo.svg +1 -0
  322. package/.next/standalone/components/navbar.tsx +154 -65
  323. package/.next/standalone/components/reach-developers.tsx +37 -9
  324. package/.next/standalone/lib/atomic-write.ts +67 -0
  325. package/.next/standalone/lib/auth/api-server-client.ts +281 -0
  326. package/.next/standalone/lib/auth/auth-store.ts +250 -0
  327. package/.next/standalone/lib/client-telemetry.ts +2 -0
  328. package/.next/standalone/lib/fetch-with-timeout.ts +42 -0
  329. package/.next/standalone/lib/share-card.ts +144 -0
  330. package/.next/standalone/lib/telemetry.ts +12 -7
  331. package/.next/standalone/node_modules/@next/env/package.json +1 -1
  332. package/.next/standalone/node_modules/next/dist/build/swc/index.js +1 -1
  333. package/.next/standalone/node_modules/next/dist/client/dev/debug-channel.js +102 -2
  334. package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js +11 -11
  335. package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js +13 -13
  336. package/.next/standalone/node_modules/next/dist/compiled/next-server/app-route-turbo.runtime.prod.js +2 -2
  337. package/.next/standalone/node_modules/next/dist/compiled/next-server/pages-turbo.runtime.prod.js +1 -1
  338. package/.next/standalone/node_modules/next/dist/lib/patch-incorrect-lockfile.js +3 -3
  339. package/.next/standalone/node_modules/next/dist/server/app-render/action-handler.js +18 -8
  340. package/.next/standalone/node_modules/next/dist/server/config-schema.js +1 -0
  341. package/.next/standalone/node_modules/next/dist/server/config.js +1 -1
  342. package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-turbopack.js +2 -2
  343. package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-webpack.js +1 -1
  344. package/.next/standalone/node_modules/next/dist/server/lib/app-info-log.js +1 -1
  345. package/.next/standalone/node_modules/next/dist/server/lib/encode-cache-tag.js +45 -0
  346. package/.next/standalone/node_modules/next/dist/server/lib/implicit-tags.js +6 -3
  347. package/.next/standalone/node_modules/next/dist/server/lib/patch-fetch.js +5 -1
  348. package/.next/standalone/node_modules/next/dist/server/lib/start-server.js +1 -1
  349. package/.next/standalone/node_modules/next/dist/server/web/spec-extension/revalidate.js +4 -3
  350. package/.next/standalone/node_modules/next/dist/server/web/spec-extension/unstable-cache.js +6 -2
  351. package/.next/standalone/node_modules/next/dist/shared/lib/errors/canary-only-config-error.js +1 -1
  352. package/.next/standalone/node_modules/next/dist/telemetry/anonymous-meta.js +1 -1
  353. package/.next/standalone/node_modules/next/dist/telemetry/events/swc-load-failure.js +1 -1
  354. package/.next/standalone/node_modules/next/dist/telemetry/events/version.js +2 -2
  355. package/.next/standalone/node_modules/next/package.json +15 -15
  356. package/.next/standalone/node_modules/react/cjs/react.development.js +1 -1
  357. package/.next/standalone/node_modules/react/cjs/react.production.js +1 -1
  358. package/.next/standalone/node_modules/react/package.json +1 -1
  359. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.browser.production.js +1 -1
  360. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.node.production.js +1 -1
  361. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.browser.production.js +3 -3
  362. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.edge.production.js +3 -3
  363. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.node.production.js +3 -3
  364. package/.next/standalone/node_modules/react-dom/cjs/react-dom.production.js +1 -1
  365. package/.next/standalone/node_modules/react-dom/package.json +2 -2
  366. package/.next/standalone/osv-scanner.toml +17 -0
  367. package/.next/standalone/package.json +8 -3
  368. package/.next/standalone/public/audit/fonts/bitcount-prop-single.woff2 +0 -0
  369. package/.next/standalone/public/icon.svg +1 -0
  370. package/.next/standalone/public/logo.svg +1 -0
  371. package/.next/standalone/server.js +1 -1
  372. package/.next/standalone/templates/bitcount-font/README.md +42 -0
  373. package/.next/standalone/templates/bitcount-font/bitcount-prop-single.woff2 +0 -0
  374. package/.next/standalone/templates/bitcount-font/bitcount.css +49 -0
  375. package/.next/standalone/templates/bitcount-font/fonts.ts.example +23 -0
  376. package/README.md +2 -1
  377. package/bin/failproofai.mjs +165 -144
  378. package/dist/cli.mjs +607 -1858
  379. package/lib/atomic-write.ts +67 -0
  380. package/lib/auth/api-server-client.ts +281 -0
  381. package/lib/auth/auth-store.ts +250 -0
  382. package/lib/client-telemetry.ts +2 -0
  383. package/lib/fetch-with-timeout.ts +42 -0
  384. package/lib/share-card.ts +144 -0
  385. package/lib/telemetry.ts +12 -7
  386. package/package.json +8 -3
  387. package/scripts/install-telemetry.mjs +4 -0
  388. package/src/audit/archetypes.ts +924 -0
  389. package/src/audit/cache.ts +21 -2
  390. package/src/audit/dashboard-cache.ts +111 -0
  391. package/src/audit/features.ts +268 -0
  392. package/src/audit/findings.ts +298 -0
  393. package/src/audit/index.ts +39 -21
  394. package/src/audit/replay.ts +29 -3
  395. package/src/audit/scoring.ts +174 -0
  396. package/src/audit/strengths.ts +138 -0
  397. package/src/audit/types.ts +24 -1
  398. package/src/auth/cli.ts +359 -0
  399. package/src/hooks/builtin-policies.ts +2 -1
  400. package/src/hooks/hook-telemetry.ts +2 -2
  401. package/src/hooks/policy-registry.ts +20 -0
  402. package/src/posthog-key.ts +9 -0
  403. package/.next/standalone/.next/server/app/icon.png/route/app-paths-manifest.json +0 -3
  404. package/.next/standalone/.next/server/app/icon.png/route.js +0 -7
  405. package/.next/standalone/.next/server/app/icon.png/route.js.nft.json +0 -1
  406. package/.next/standalone/.next/server/app/icon.png.body +0 -0
  407. package/.next/standalone/.next/server/app/icon.png.meta +0 -1
  408. package/.next/standalone/.next/server/chunks/[externals]_next_dist_0sqmaqd._.js +0 -3
  409. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06.arfm._.js +0 -3
  410. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0__i0h0._.js +0 -3
  411. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0fe7_q_._.js +0 -3
  412. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0fw.e.h._.js +0 -3
  413. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0pxn0e1._.js +0 -3
  414. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0xv0jh2._.js +0 -3
  415. package/.next/standalone/.next/server/chunks/_next-internal_server_app_icon_png_route_actions_12.gv.r.js +0 -3
  416. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0bdfoky.js +0 -3
  417. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_05pz9._._.js +0 -3
  418. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01as125._.js +0 -3
  419. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0370~qj._.js +0 -3
  420. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__09v.ljl._.js +0 -3
  421. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0agrcb8._.js +0 -4
  422. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0b7hkr~._.js +0 -3
  423. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ehh6vp._.js +0 -4
  424. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g8l0tu._.js +0 -3
  425. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0j4l6hl._.js +0 -3
  426. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0k5n2kz._.js +0 -4
  427. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0lp08ll._.js +0 -3
  428. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n0yaqw._.js +0 -4
  429. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0o21f.o._.js +0 -3
  430. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0t8juvy._.js +0 -4
  431. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0uylufv._.js +0 -4
  432. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ymlddl._.js +0 -223
  433. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0~03grs._.js +0 -3
  434. package/.next/standalone/.next/server/chunks/ssr/app_0cdqd9w._.js +0 -3
  435. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_0q-m0y-._.js +0 -8
  436. package/.next/standalone/.next/server/chunks/ssr/app_projects_loading_tsx_13veom4._.js +0 -3
  437. package/.next/standalone/.next/server/chunks/ssr/node_modules_0ttbz1~._.js +0 -3
  438. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_06u0kr8._.js +0 -3
  439. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0a_7sdg.js +0 -4
  440. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0ef3uwk.js +0 -4
  441. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0pbja1x.js +0 -4
  442. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0r6o0i2.js +0 -4
  443. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_11y81~_.js +0 -4
  444. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_12or2kf.js +0 -4
  445. package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_0mebn66._.js +0 -3
  446. package/.next/standalone/.next/static/chunks/07kpqoo7kuckx.js +0 -6
  447. package/.next/standalone/.next/static/chunks/0azb~vy9ds_uy.js +0 -1
  448. package/.next/standalone/.next/static/chunks/0f5p9plm.aqlp.css +0 -2
  449. package/.next/standalone/.next/static/chunks/0ffvlbgzgnlw7.js +0 -2
  450. package/.next/standalone/.next/static/chunks/0spktq7xqab9h.js +0 -1
  451. package/.next/standalone/.next/static/chunks/118q3uljozd5z.js +0 -4
  452. package/.next/standalone/.next/static/chunks/12pt~2f.c1sha.js +0 -1
  453. package/.next/standalone/.next/static/media/4fa387ec64143e14-s.0.qu-9752pffj.woff2 +0 -0
  454. package/.next/standalone/.next/static/media/5ce348bf30bf5439-s.0ee55_hj9qcer.woff2 +0 -0
  455. package/.next/standalone/.next/static/media/6306c77e7c8268e4-s.0mao5jbfbduzp.woff2 +0 -0
  456. package/.next/standalone/.next/static/media/797e433ab948586e-s.p.09zddjkbdep5a.woff2 +0 -0
  457. package/.next/standalone/.next/static/media/7d817b4c03b0c5f1-s.0uzt.a6d44yda.woff2 +0 -0
  458. package/.next/standalone/.next/static/media/bbc41e54d2fcbd21-s.0mvwgmnhv29no.woff2 +0 -0
  459. package/.next/standalone/.next/static/media/icon.0a.gigb3_x5pd.png +0 -0
  460. package/.next/standalone/app/icon.png +0 -0
  461. package/src/audit/telemetry.ts +0 -113
  462. /package/.next/standalone/.next/server/app/{icon.png → api/audit/run}/route/build-manifest.json +0 -0
  463. /package/.next/standalone/.next/server/app/{icon.png → api/audit/run}/route.js.map +0 -0
  464. /package/.next/standalone/.next/static/chunks/{03~yq9q893hmn.js → 0cz1d0mv5g_q7.js} +0 -0
  465. /package/.next/standalone/.next/static/chunks/{0a40sy4tk8ioe.js → 0wwt5o04i4zwh.js} +0 -0
  466. /package/.next/standalone/.next/static/chunks/{0n1n67imq.udf.js → 1__i9af9g78vd.js} +0 -0
  467. /package/.next/standalone/.next/static/chunks/{0w6fzf.07a24u.js → 2so39wg7mjbi7.js} +0 -0
  468. /package/.next/standalone/.next/static/chunks/{0xbo5nl6w4lka.js → 2wbuxnsvux4di.js} +0 -0
  469. /package/.next/standalone/.next/static/chunks/{0_s0luks5tay-.js → 35fgpd_feci6x.js} +0 -0
  470. /package/.next/standalone/.next/static/chunks/{15fklyav5py5m.js → 3xpjn3cdgm-7m.js} +0 -0
  471. /package/.next/standalone/.next/static/chunks/{17.b3suj8zjjj.js → 4448_qq7bd963.js} +0 -0
  472. /package/.next/standalone/.next/static/{tGVQM5SE3NvbVu0gbAJm7 → t4nu8RTRp3Z2srol-9pVb}/_buildManifest.js +0 -0
  473. /package/.next/standalone/.next/static/{tGVQM5SE3NvbVu0gbAJm7 → t4nu8RTRp3Z2srol-9pVb}/_clientMiddlewareManifest.js +0 -0
  474. /package/.next/standalone/.next/static/{tGVQM5SE3NvbVu0gbAJm7 → t4nu8RTRp3Z2srol-9pVb}/_ssgManifest.js +0 -0
package/dist/cli.mjs CHANGED
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import { createRequire } from "node:module";
3
2
  var __defProp = Object.defineProperty;
4
3
  var __returnValue = (v) => v;
5
4
  function __exportSetter(name, newValue) {
@@ -15,14 +14,13 @@ var __export = (target, all) => {
15
14
  });
16
15
  };
17
16
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
18
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
17
 
20
18
  // package.json
21
- var version2 = "0.0.11-beta.2";
19
+ var version2 = "0.0.11-beta.4";
22
20
  var init_package = () => {};
23
21
 
24
22
  // src/posthog-key.ts
25
- var POSTHOG_API_KEY = "phc_Ac1Ww1GqKc0z1SyrRWbmatEeQdlOQIsDEEdP8l8JRgX";
23
+ var POSTHOG_API_KEY = "phc_Ac1Ww1GqKc0z1SyrRWbmatEeQdlOQIsDEEdP8l8JRgX", POSTHOG_PRODUCT = "failproofai-oss";
26
24
 
27
25
  // src/hooks/hook-telemetry.ts
28
26
  var exports_hook_telemetry = {};
@@ -36,7 +34,7 @@ async function trackHookEvent(distinctId, event, properties) {
36
34
  api_key: process.env.FAILPROOFAI_POSTHOG_KEY ?? API_KEY,
37
35
  event,
38
36
  distinct_id: distinctId,
39
- properties: { ...properties, $lib: "failproofai-hooks", failproofai_version: version2 }
37
+ properties: { ...properties, $lib: "failproofai-hooks", failproofai_version: version2, product: POSTHOG_PRODUCT }
40
38
  });
41
39
  try {
42
40
  await fetch(process.env.FAILPROOFAI_POSTHOG_HOST ? `${process.env.FAILPROOFAI_POSTHOG_HOST}/capture/` : CAPTURE_URL, {
@@ -1618,7 +1616,7 @@ function requireCiGreenBeforeStop(ctx) {
1618
1616
  const allChecks = [...workflowRuns, ...thirdPartyChecks, ...commitStatuses];
1619
1617
  if (allChecks.length === 0)
1620
1618
  return allow(`No CI runs found for branch "${branch}".`);
1621
- const failing = allChecks.filter((r) => r.status === "completed" && r.conclusion !== "success" && r.conclusion !== "skipped" && r.conclusion !== "cancelled");
1619
+ const failing = allChecks.filter((r) => r.status === "completed" && r.conclusion !== "success" && r.conclusion !== "skipped" && r.conclusion !== "cancelled" && r.conclusion !== "neutral");
1622
1620
  if (failing.length > 0) {
1623
1621
  const names = failing.map((r) => `"${r.name}"`).join(", ");
1624
1622
  return deny(`CI checks are failing on branch "${branch}": ${names}. Fix the failing checks now.`);
@@ -2271,7 +2269,7 @@ async function trackHookEvent2(distinctId, event, properties) {
2271
2269
  api_key: process.env.FAILPROOFAI_POSTHOG_KEY ?? API_KEY2,
2272
2270
  event,
2273
2271
  distinct_id: distinctId,
2274
- properties: { ...properties, $lib: "failproofai-hooks", failproofai_version: version2 }
2272
+ properties: { ...properties, $lib: "failproofai-hooks", failproofai_version: version2, product: POSTHOG_PRODUCT }
2275
2273
  });
2276
2274
  try {
2277
2275
  await fetch(process.env.FAILPROOFAI_POSTHOG_HOST ? `${process.env.FAILPROOFAI_POSTHOG_HOST}/capture/` : CAPTURE_URL2, {
@@ -4885,10 +4883,6 @@ async function parseFileContent(fileContent, source) {
4885
4883
  entries.sort((a, b) => a.timestampMs - b.timestampMs);
4886
4884
  return { entries, rawLines, subagentIds: Array.from(subagentIdSet) };
4887
4885
  }
4888
- async function parseLogContent(fileContent, source = "session") {
4889
- const result = await parseFileContent(fileContent, source);
4890
- return result.entries;
4891
- }
4892
4886
  async function parseSessionLog(projectName, sessionId) {
4893
4887
  const projectDir = resolveProjectPath(projectName);
4894
4888
  const projectsPath = getClaudeProjectsPath();
@@ -8730,1768 +8724,549 @@ var init_install_prompt2 = __esm(() => {
8730
8724
  init_telemetry_id2();
8731
8725
  });
8732
8726
 
8733
- // lib/claude-sessions.ts
8734
- import { readdirSync as readdirSync8, statSync as statSync9, existsSync as existsSync12 } from "node:fs";
8735
- import { join as join18, basename as basename4 } from "node:path";
8736
- function getClaudeProjectsRoot() {
8737
- return getClaudeProjectsPath();
8738
- }
8739
- function listClaudeProjects() {
8740
- const root = getClaudeProjectsRoot();
8741
- let entries;
8742
- try {
8743
- entries = readdirSync8(root, { withFileTypes: true });
8744
- } catch {
8745
- return [];
8746
- }
8747
- return entries.filter((e) => e.isDirectory()).map((e) => ({
8748
- name: e.name,
8749
- cwd: decodeFolderName(e.name),
8750
- path: join18(root, e.name)
8751
- }));
8727
+ // lib/telemetry.ts
8728
+ function isTelemetryEnabled() {
8729
+ return process.env.FAILPROOFAI_TELEMETRY_DISABLED !== "1";
8752
8730
  }
8753
- function listClaudeTranscripts(project) {
8754
- const out = [];
8755
- let entries;
8756
- try {
8757
- entries = readdirSync8(project.path, { withFileTypes: true });
8758
- } catch {
8759
- return out;
8760
- }
8761
- for (const entry of entries) {
8762
- if (entry.isFile() && entry.name.endsWith(".jsonl")) {
8763
- const sessionId = entry.name.slice(0, -".jsonl".length);
8764
- if (!UUID_RE4.test(sessionId))
8765
- continue;
8766
- const transcriptPath = join18(project.path, entry.name);
8767
- try {
8768
- const s = statSync9(transcriptPath);
8769
- out.push({
8770
- projectName: project.name,
8771
- cwd: project.cwd,
8772
- sessionId,
8773
- transcriptPath,
8774
- mtimeMs: s.mtimeMs,
8775
- sizeBytes: s.size,
8776
- isSubagent: false
8777
- });
8778
- } catch {}
8779
- } else if (entry.isDirectory() && UUID_RE4.test(entry.name)) {
8780
- const subDir = join18(project.path, entry.name, "subagents");
8781
- if (!existsSync12(subDir))
8782
- continue;
8783
- let subEntries;
8784
- try {
8785
- subEntries = readdirSync8(subDir, { withFileTypes: true });
8786
- } catch {
8787
- continue;
8788
- }
8789
- for (const sub of subEntries) {
8790
- if (!sub.isFile() || !sub.name.endsWith(".jsonl"))
8791
- continue;
8792
- const agentId = sub.name.slice(0, -".jsonl".length);
8793
- const transcriptPath = join18(subDir, sub.name);
8794
- try {
8795
- const s = statSync9(transcriptPath);
8796
- out.push({
8797
- projectName: project.name,
8798
- cwd: project.cwd,
8799
- sessionId: agentId,
8800
- transcriptPath,
8801
- mtimeMs: s.mtimeMs,
8802
- sizeBytes: s.size,
8803
- isSubagent: true
8804
- });
8805
- } catch {}
8806
- }
8807
- }
8808
- }
8809
- return out;
8731
+ function trackEvent(name, properties) {
8732
+ if (!isTelemetryEnabled())
8733
+ return;
8734
+ const client = globalThis.__FAILPROOFAI_POSTHOG__;
8735
+ if (!client)
8736
+ return;
8737
+ client.capture({
8738
+ distinctId: getInstanceId2(),
8739
+ event: name,
8740
+ properties: { ...properties, $lib: "failproofai", failproofai_version: version2, product: POSTHOG_PRODUCT }
8741
+ });
8810
8742
  }
8811
- var UUID_RE4;
8812
- var init_claude_sessions = __esm(() => {
8813
- init_paths();
8814
- UUID_RE4 = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i;
8815
- });
8816
-
8817
- // src/audit/types.ts
8818
- var AUDIT_TOOL_RESULT_MAX_BYTES, AUDIT_EXAMPLE_MAX_CHARS = 80, AUDIT_MAX_EXAMPLES_PER_NAME = 3;
8819
- var init_types2 = __esm(() => {
8820
- AUDIT_TOOL_RESULT_MAX_BYTES = 64 * 1024;
8743
+ var init_telemetry = __esm(() => {
8744
+ init_telemetry_id2();
8745
+ init_package();
8821
8746
  });
8822
8747
 
8823
- // src/audit/cli-adapters/shared.ts
8824
- function truncateToUtf8Bytes(s, maxBytes) {
8825
- const buf = Buffer.from(s, "utf-8");
8826
- if (buf.byteLength <= maxBytes)
8827
- return s;
8828
- let end = maxBytes;
8829
- while (end > 0 && (buf[end] & 192) === 128)
8830
- end--;
8831
- return buf.subarray(0, end).toString("utf-8");
8832
- }
8833
- function logEntriesToEvents(entries, ctx) {
8834
- const events = [];
8835
- for (const entry of entries) {
8836
- if (entry.type !== "assistant")
8837
- continue;
8838
- for (const block of entry.message.content) {
8839
- if (block.type !== "tool_use")
8840
- continue;
8841
- const rawName = block.name;
8842
- const canonicalName = canonicalizeToolName(rawName, ctx.cli) ?? rawName;
8843
- const canonicalInput = canonicalizeToolInput(canonicalName, block.input, ctx.cli);
8844
- let toolResultText;
8845
- if (block.result?.content) {
8846
- toolResultText = truncateToUtf8Bytes(block.result.content, AUDIT_TOOL_RESULT_MAX_BYTES);
8847
- }
8848
- events.push({
8849
- cli: ctx.cli,
8850
- sessionId: ctx.sessionId,
8851
- transcriptPath: ctx.transcriptPath,
8852
- cwd: ctx.cwd,
8853
- timestamp: entry.timestamp,
8854
- toolName: canonicalName,
8855
- rawToolName: rawName,
8856
- toolInput: canonicalInput ?? {},
8857
- toolResultText
8858
- });
8859
- }
8860
- }
8861
- return events;
8748
+ // lib/fetch-with-timeout.ts
8749
+ function isAbortError(err) {
8750
+ return err instanceof Error && (err.name === "AbortError" || err.name === "TimeoutError");
8862
8751
  }
8863
- var init_shared = __esm(() => {
8864
- init_tool_name_canonicalize();
8865
- init_types2();
8866
- });
8867
8752
 
8868
- // src/audit/cli-adapters/claude.ts
8869
- import { readFile as readFile13 } from "node:fs/promises";
8870
- async function listClaudeTranscriptMetadata(opts = {}) {
8871
- const projectFilter = opts.projects ? new Set(opts.projects) : null;
8872
- const sinceMs = opts.sinceMs ?? 0;
8873
- const out = [];
8874
- for (const project of listClaudeProjects()) {
8875
- if (projectFilter && !projectFilter.has(project.cwd))
8876
- continue;
8877
- let transcripts;
8878
- try {
8879
- transcripts = listClaudeTranscripts(project);
8880
- } catch {
8881
- continue;
8882
- }
8883
- for (const t of transcripts) {
8884
- if (t.mtimeMs < sinceMs)
8885
- continue;
8886
- out.push({
8887
- cli: "claude",
8888
- projectName: project.name,
8889
- sessionId: t.sessionId,
8890
- transcriptPath: t.transcriptPath,
8891
- mtimeMs: t.mtimeMs,
8892
- sizeBytes: t.sizeBytes
8893
- });
8894
- }
8895
- }
8896
- return out;
8753
+ // lib/auth/api-server-client.ts
8754
+ function getApiBase() {
8755
+ const raw = process.env.FAILPROOF_API_URL ?? process.env.FAILPROOFAI_API_URL ?? DEFAULT_API_BASE;
8756
+ return raw.replace(/\/+$/, "");
8897
8757
  }
8898
- async function streamClaudeEvents(meta) {
8899
- let content;
8758
+ async function parseError(res) {
8759
+ let body = {};
8900
8760
  try {
8901
- content = await readFile13(meta.transcriptPath, "utf-8");
8902
- } catch {
8903
- return [];
8761
+ body = await res.json();
8762
+ } catch {}
8763
+ const code = body.code ?? `http_${res.status}`;
8764
+ const message = body.message ?? body.detail ?? res.statusText ?? "request failed";
8765
+ let retryAfterSecs = body.retry_after_secs;
8766
+ if (retryAfterSecs === undefined) {
8767
+ const h = res.headers.get("retry-after");
8768
+ if (h) {
8769
+ const n = Number(h);
8770
+ if (Number.isFinite(n))
8771
+ retryAfterSecs = n;
8772
+ }
8773
+ }
8774
+ if (retryAfterSecs !== undefined) {
8775
+ retryAfterSecs = Math.max(0, Math.min(86400, retryAfterSecs));
8904
8776
  }
8905
- const source = "session";
8906
- let entries;
8777
+ return new AuthApiError(res.status, code, message, retryAfterSecs);
8778
+ }
8779
+ function timeoutSignal(extra) {
8780
+ const t = AbortSignal.timeout(REQUEST_TIMEOUT_MS);
8781
+ if (!extra)
8782
+ return t;
8783
+ const anyFn = AbortSignal.any;
8784
+ if (anyFn)
8785
+ return anyFn([t, extra]);
8786
+ const composed = new AbortController;
8787
+ const onAbort = (s) => composed.abort(s.reason);
8788
+ if (t.aborted)
8789
+ onAbort(t);
8790
+ else
8791
+ t.addEventListener("abort", () => onAbort(t), { once: true });
8792
+ if (extra.aborted)
8793
+ onAbort(extra);
8794
+ else
8795
+ extra.addEventListener("abort", () => onAbort(extra), { once: true });
8796
+ return composed.signal;
8797
+ }
8798
+ function pathFromUrl(url) {
8907
8799
  try {
8908
- entries = await parseLogContent(content, source);
8800
+ return new URL(url).pathname;
8909
8801
  } catch {
8910
- return [];
8911
- }
8912
- let cwd = "";
8913
- for (const line of content.split(`
8914
- `, 50)) {
8915
- if (!line.trim())
8916
- continue;
8917
- try {
8918
- const parsed = JSON.parse(line);
8919
- if (typeof parsed.cwd === "string" && parsed.cwd.length > 0) {
8920
- cwd = parsed.cwd;
8921
- break;
8922
- }
8923
- } catch {}
8802
+ return url;
8924
8803
  }
8925
- return logEntriesToEvents(entries, {
8926
- cli: "claude",
8927
- sessionId: meta.sessionId,
8928
- transcriptPath: meta.transcriptPath,
8929
- cwd
8930
- });
8931
8804
  }
8932
- var init_claude = __esm(() => {
8933
- init_claude_sessions();
8934
- init_log_entries();
8935
- init_shared();
8936
- });
8937
-
8938
- // src/audit/cli-adapters/codex.ts
8939
- import { statSync as statSync10 } from "node:fs";
8940
- async function listCodexTranscriptMetadata(opts = {}) {
8941
- const projectFilter = opts.projects ? new Set(opts.projects) : null;
8942
- const sinceMs = opts.sinceMs ?? 0;
8943
- const out = [];
8944
- const projects = await getCodexProjects();
8945
- for (const project of projects) {
8946
- const { cwd, sessions } = await getCodexSessionsByEncodedName(project.name);
8947
- const effectiveCwd = cwd ?? "";
8948
- if (projectFilter && !projectFilter.has(effectiveCwd))
8949
- continue;
8950
- for (const s of sessions) {
8951
- const mtimeMs = s.lastModified.getTime();
8952
- if (mtimeMs < sinceMs)
8953
- continue;
8954
- let sizeBytes = 0;
8955
- try {
8956
- sizeBytes = statSync10(s.path).size;
8957
- } catch {}
8958
- if (!s.sessionId)
8959
- continue;
8960
- out.push({
8961
- cli: "codex",
8962
- projectName: project.name,
8963
- sessionId: s.sessionId,
8964
- transcriptPath: s.path,
8965
- mtimeMs,
8966
- sizeBytes
8967
- });
8805
+ async function fetchWithTimeout(url, init) {
8806
+ try {
8807
+ return await fetch(url, { ...init, signal: timeoutSignal(init.signal ?? undefined) });
8808
+ } catch (err) {
8809
+ const isTimeout = isAbortError(err);
8810
+ trackEvent("api_server_unreachable", {
8811
+ kind: isTimeout ? "timeout" : "network",
8812
+ path: pathFromUrl(url),
8813
+ method: typeof init.method === "string" ? init.method : "GET"
8814
+ });
8815
+ if (isTimeout) {
8816
+ throw new AuthApiError(0, "timeout", `request to ${url} timed out after ${REQUEST_TIMEOUT_MS}ms`);
8968
8817
  }
8818
+ throw err;
8969
8819
  }
8970
- return out;
8971
8820
  }
8972
- async function streamCodexEvents(meta) {
8973
- const log = await getCodexSessionLog(meta.sessionId);
8974
- if (!log)
8975
- return [];
8976
- return logEntriesToEvents(log.entries, {
8977
- cli: "codex",
8978
- sessionId: meta.sessionId,
8979
- transcriptPath: meta.transcriptPath,
8980
- cwd: log.cwd ?? ""
8821
+ async function postJson(path3, body, init) {
8822
+ const headers = { "content-type": "application/json" };
8823
+ if (init?.accessToken)
8824
+ headers["authorization"] = `Bearer ${init.accessToken}`;
8825
+ const res = await fetchWithTimeout(`${getApiBase()}${path3}`, {
8826
+ method: "POST",
8827
+ headers,
8828
+ body: JSON.stringify(body)
8981
8829
  });
8830
+ if (res.status === 204)
8831
+ return;
8832
+ if (!res.ok)
8833
+ throw await parseError(res);
8834
+ return await res.json();
8982
8835
  }
8983
- var init_codex = __esm(() => {
8984
- init_codex_projects();
8985
- init_codex_sessions();
8986
- init_shared();
8987
- });
8988
-
8989
- // src/audit/cli-adapters/copilot.ts
8990
- import { statSync as statSync11 } from "node:fs";
8991
- async function listCopilotTranscriptMetadata(opts = {}) {
8992
- const projectFilter = opts.projects ? new Set(opts.projects) : null;
8993
- const sinceMs = opts.sinceMs ?? 0;
8994
- const out = [];
8995
- const projects = await getCopilotProjects();
8996
- for (const project of projects) {
8997
- const { cwd, sessions } = await getCopilotSessionsByEncodedName(project.name);
8998
- const effectiveCwd = cwd ?? "";
8999
- if (projectFilter && !projectFilter.has(effectiveCwd))
9000
- continue;
9001
- for (const s of sessions) {
9002
- const mtimeMs = s.lastModified.getTime();
9003
- if (mtimeMs < sinceMs)
9004
- continue;
9005
- let sizeBytes = 0;
9006
- try {
9007
- sizeBytes = statSync11(s.path).size;
9008
- } catch {}
9009
- if (!s.sessionId)
9010
- continue;
9011
- out.push({
9012
- cli: "copilot",
9013
- projectName: project.name,
9014
- sessionId: s.sessionId,
9015
- transcriptPath: s.path,
9016
- mtimeMs,
9017
- sizeBytes
9018
- });
9019
- }
9020
- }
9021
- return out;
9022
- }
9023
- async function streamCopilotEvents(meta) {
9024
- const log = await getCopilotSessionLog(meta.sessionId);
9025
- if (!log)
9026
- return [];
9027
- return logEntriesToEvents(log.entries, {
9028
- cli: "copilot",
9029
- sessionId: meta.sessionId,
9030
- transcriptPath: meta.transcriptPath,
9031
- cwd: log.cwd ?? ""
9032
- });
8836
+ async function requestLoginCode(email) {
8837
+ return postJson("/v0/auth/login/request", { email });
9033
8838
  }
9034
- var init_copilot = __esm(() => {
9035
- init_copilot_projects();
9036
- init_copilot_sessions();
9037
- init_shared();
9038
- });
9039
-
9040
- // src/audit/cli-adapters/cursor.ts
9041
- import { statSync as statSync12 } from "node:fs";
9042
- async function listCursorTranscriptMetadata(opts = {}) {
9043
- const projectFilter = opts.projects ? new Set(opts.projects) : null;
9044
- const sinceMs = opts.sinceMs ?? 0;
9045
- const out = [];
9046
- const projects = await getCursorProjects();
9047
- for (const project of projects) {
9048
- const { cwd, sessions } = await getCursorSessionsByEncodedName(project.name);
9049
- const effectiveCwd = cwd ?? "";
9050
- if (projectFilter && !projectFilter.has(effectiveCwd))
9051
- continue;
9052
- for (const s of sessions) {
9053
- const mtimeMs = s.lastModified.getTime();
9054
- if (mtimeMs < sinceMs)
9055
- continue;
9056
- let sizeBytes = 0;
9057
- try {
9058
- sizeBytes = statSync12(s.path).size;
9059
- } catch {}
9060
- if (!s.sessionId)
9061
- continue;
9062
- out.push({
9063
- cli: "cursor",
9064
- projectName: project.name,
9065
- sessionId: s.sessionId,
9066
- transcriptPath: s.path,
9067
- mtimeMs,
9068
- sizeBytes
9069
- });
9070
- }
9071
- }
9072
- return out;
8839
+ async function verifyLoginCode(email, code) {
8840
+ return postJson("/v0/auth/login/verify", { email, code });
9073
8841
  }
9074
- async function streamCursorEvents(meta) {
9075
- const log = await getCursorSessionLog(meta.sessionId);
9076
- if (!log)
9077
- return [];
9078
- return logEntriesToEvents(log.entries, {
9079
- cli: "cursor",
9080
- sessionId: meta.sessionId,
9081
- transcriptPath: meta.transcriptPath,
9082
- cwd: log.cwd ?? ""
9083
- });
8842
+ async function logoutSession(accessToken, refreshToken) {
8843
+ await postJson("/v0/auth/logout", { refresh_token: refreshToken }, { accessToken });
9084
8844
  }
9085
- var init_cursor = __esm(() => {
9086
- init_cursor_projects();
9087
- init_cursor_sessions();
9088
- init_shared();
8845
+ var DEFAULT_API_BASE = "https://api.befailproof.ai", AuthApiError, REQUEST_TIMEOUT_MS = 1e4;
8846
+ var init_api_server_client = __esm(() => {
8847
+ init_telemetry();
8848
+ AuthApiError = class AuthApiError extends Error {
8849
+ status;
8850
+ code;
8851
+ retryAfterSecs;
8852
+ constructor(status, code, message, retryAfterSecs) {
8853
+ super(message);
8854
+ this.status = status;
8855
+ this.code = code;
8856
+ this.retryAfterSecs = retryAfterSecs;
8857
+ this.name = "AuthApiError";
8858
+ }
8859
+ };
9089
8860
  });
9090
8861
 
9091
- // lib/opencode-sessions.ts
9092
- import { execFileSync as execFileSync3 } from "node:child_process";
9093
- function runOpenCodeDb2(sql) {
8862
+ // lib/atomic-write.ts
8863
+ import {
8864
+ chmodSync,
8865
+ existsSync as existsSync12,
8866
+ mkdirSync as mkdirSync6,
8867
+ renameSync as renameSync3,
8868
+ rmSync,
8869
+ statSync as statSync9,
8870
+ writeFileSync as writeFileSync5
8871
+ } from "node:fs";
8872
+ import { dirname as dirname5 } from "node:path";
8873
+ import { randomBytes } from "node:crypto";
8874
+ function writeJsonAtomically(filePath, value, opts = {}) {
8875
+ const mode = opts.mode ?? 384;
8876
+ const dirMode = opts.dirMode ?? 448;
8877
+ const dir = dirname5(filePath);
8878
+ if (!existsSync12(dir))
8879
+ mkdirSync6(dir, { recursive: true, mode: dirMode });
8880
+ const tmp = `${filePath}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
9094
8881
  try {
9095
- const stdout = execFileSync3("opencode", ["db", "--format", "json", sql], {
9096
- encoding: "utf8",
9097
- timeout: 5000,
9098
- stdio: ["ignore", "pipe", "pipe"]
9099
- });
9100
- if (!stdout.trim())
9101
- return [];
9102
- const parsed = JSON.parse(stdout);
9103
- if (!Array.isArray(parsed))
9104
- return null;
9105
- return parsed;
9106
- } catch {
9107
- return null;
8882
+ writeFileSync5(tmp, JSON.stringify(value, null, 2), { mode });
8883
+ try {
8884
+ if ((statSync9(tmp).mode & 63) !== 0)
8885
+ chmodSync(tmp, mode);
8886
+ } catch {}
8887
+ renameSync3(tmp, filePath);
8888
+ try {
8889
+ if ((statSync9(filePath).mode & 63) !== 0)
8890
+ chmodSync(filePath, mode);
8891
+ } catch {}
8892
+ } catch (err) {
8893
+ try {
8894
+ rmSync(tmp, { force: true });
8895
+ } catch {}
8896
+ throw err;
9108
8897
  }
9109
8898
  }
9110
- function isPlainObject(value) {
9111
- return !!value && typeof value === "object" && !Array.isArray(value);
9112
- }
9113
- function parseDataColumn(raw) {
9114
- if (typeof raw !== "string" || raw.length === 0)
8899
+ var init_atomic_write = () => {};
8900
+
8901
+ // lib/auth/auth-store.ts
8902
+ import { existsSync as existsSync13, readFileSync as readFileSync10, rmSync as rmSync2 } from "node:fs";
8903
+ import { homedir as homedir19 } from "node:os";
8904
+ import { join as join18 } from "node:path";
8905
+ function getAuthDir() {
8906
+ const override = process.env.FAILPROOFAI_AUTH_DIR;
8907
+ if (override)
8908
+ return override;
8909
+ return join18(homedir19(), ".failproofai");
8910
+ }
8911
+ function getAuthFilePath() {
8912
+ return join18(getAuthDir(), "auth.json");
8913
+ }
8914
+ function readAuth() {
8915
+ const p = getAuthFilePath();
8916
+ if (!existsSync13(p))
9115
8917
  return null;
9116
8918
  try {
8919
+ const raw = readFileSync10(p, "utf-8");
9117
8920
  const parsed = JSON.parse(raw);
9118
- return isPlainObject(parsed) ? parsed : null;
9119
- } catch {
9120
- return null;
9121
- }
9122
- }
9123
- function readContentText(data) {
9124
- if (typeof data.text === "string")
9125
- return data.text;
9126
- if (typeof data.content === "string")
9127
- return data.content;
9128
- return "";
9129
- }
9130
- function translateMessage(msgRow, partRows, source) {
9131
- const msgData = parseDataColumn(msgRow.data) ?? {};
9132
- const role = typeof msgData.role === "string" ? msgData.role : "system";
9133
- const date = new Date(msgRow.time_created);
9134
- const timestamp = date.toISOString();
9135
- const raw = { uuid: msgRow.id, parentUuid: null };
9136
- const base = baseEntry(raw, timestamp, date, source);
9137
- const content = [];
9138
- let userText = "";
9139
- for (const p of partRows) {
9140
- const data = parseDataColumn(p.data);
9141
- if (!data)
9142
- continue;
9143
- const type = typeof data.type === "string" ? data.type : "unknown";
9144
- if (type === "text") {
9145
- const text = readContentText(data);
9146
- if (text) {
9147
- content.push({ type: "text", text });
9148
- userText += (userText ? `
9149
- ` : "") + text;
9150
- }
9151
- continue;
8921
+ if (typeof parsed.access_token !== "string" || typeof parsed.refresh_token !== "string" || typeof parsed.access_expires_at !== "number" || typeof parsed.user !== "object" || !parsed.user || typeof parsed.user.id !== "string" || typeof parsed.user.email !== "string") {
8922
+ return null;
9152
8923
  }
9153
- if (type === "tool") {
9154
- const toolName = typeof data.tool === "string" ? data.tool : typeof data.name === "string" ? data.name : "tool";
9155
- const state = isPlainObject(data.state) ? data.state : null;
9156
- const input = state && isPlainObject(state.input) ? state.input : isPlainObject(data.input) ? data.input : isPlainObject(data.args) ? data.args : {};
9157
- const block = {
9158
- type: "tool_use",
9159
- id: p.id,
9160
- name: toolName,
9161
- input
9162
- };
9163
- const status = state && typeof state.status === "string" ? state.status : "";
9164
- if (state && (status === "completed" || status === "error")) {
9165
- const errorText = status === "error" && typeof state.error === "string" ? state.error : null;
9166
- const rawOutput = errorText ?? state.output;
9167
- const contentText = typeof rawOutput === "string" ? rawOutput : rawOutput != null ? JSON.stringify(rawOutput) : "";
9168
- const time = isPlainObject(state.time) ? state.time : {};
9169
- const startMs = typeof time.start === "number" ? time.start : p.time_created;
9170
- const endMs = typeof time.end === "number" ? time.end : p.time_updated;
9171
- const durationMs = Math.max(0, endMs - startMs);
9172
- const date2 = new Date(endMs);
9173
- block.result = {
9174
- timestamp: date2.toISOString(),
9175
- timestampFormatted: formatTimestamp(date2),
9176
- content: contentText,
9177
- durationMs,
9178
- durationFormatted: formatDuration(durationMs)
9179
- };
8924
+ return {
8925
+ access_token: parsed.access_token,
8926
+ refresh_token: parsed.refresh_token,
8927
+ access_expires_at: parsed.access_expires_at,
8928
+ refresh_expires_at: typeof parsed.refresh_expires_at === "number" ? parsed.refresh_expires_at : parsed.access_expires_at,
8929
+ user: {
8930
+ id: parsed.user.id,
8931
+ email: parsed.user.email
9180
8932
  }
9181
- content.push(block);
9182
- continue;
9183
- }
9184
- content.push({ type: "text", text: `[opencode ${type}]` });
9185
- }
9186
- if (role === "user") {
9187
- const entry2 = {
9188
- ...base,
9189
- type: "user",
9190
- message: { role: "user", content: userText }
9191
8933
  };
9192
- return entry2;
9193
- }
9194
- if (role === "assistant") {
9195
- const modelInfo = isPlainObject(msgData.model) ? msgData.model : null;
9196
- const modelStr = modelInfo && typeof modelInfo.modelID === "string" ? modelInfo.modelID : undefined;
9197
- const entry2 = {
9198
- ...base,
9199
- type: "assistant",
9200
- message: { role: "assistant", content, model: modelStr }
9201
- };
9202
- return entry2;
9203
- }
9204
- const entry = {
9205
- ...base,
9206
- type: "system",
9207
- raw: { id: msgRow.id, role, parts: content }
9208
- };
9209
- return entry;
9210
- }
9211
- async function getOpenCodeSessionLog(sessionId) {
9212
- if (!sessionId || !/^[A-Za-z0-9_-]+$/.test(sessionId))
9213
- return null;
9214
- const sessions = runOpenCodeDb2(`SELECT id, project_id, slug, directory, title, time_created, time_updated FROM session WHERE id = '${sessionId}'`);
9215
- if (!sessions || sessions.length === 0)
8934
+ } catch {
9216
8935
  return null;
9217
- const session = sessions[0];
9218
- const messages = runOpenCodeDb2(`SELECT id, session_id, time_created, time_updated, data FROM message WHERE session_id = '${sessionId}' ORDER BY time_created ASC`);
9219
- const parts = runOpenCodeDb2(`SELECT id, message_id, session_id, time_created, time_updated, data FROM part WHERE session_id = '${sessionId}' ORDER BY time_created ASC`);
9220
- if (!messages)
9221
- return { entries: [], rawLines: [], cwd: session.directory ?? undefined, filePath: `opencode://${sessionId}` };
9222
- const partsByMessage = new Map;
9223
- for (const p of parts ?? []) {
9224
- let bucket = partsByMessage.get(p.message_id);
9225
- if (!bucket) {
9226
- bucket = [];
9227
- partsByMessage.set(p.message_id, bucket);
9228
- }
9229
- bucket.push(p);
9230
8936
  }
9231
- const entries = [];
9232
- const rawLines = [];
9233
- for (const msg of messages) {
9234
- const partRows = partsByMessage.get(msg.id) ?? [];
9235
- entries.push(translateMessage(msg, partRows, "session"));
9236
- const data = parseDataColumn(msg.data);
9237
- rawLines.push({
9238
- id: msg.id,
9239
- session_id: msg.session_id,
9240
- time_created: msg.time_created,
9241
- data: data ?? msg.data
9242
- });
8937
+ }
8938
+ function writeAuth(auth) {
8939
+ writeJsonAtomically(getAuthFilePath(), auth);
8940
+ }
8941
+ function deleteAuth() {
8942
+ const p = getAuthFilePath();
8943
+ if (existsSync13(p))
8944
+ rmSync2(p, { force: true });
8945
+ }
8946
+ function authFromTokenResponse(token, existingUser) {
8947
+ const now = Math.floor(Date.now() / 1000);
8948
+ const user = token.user ?? existingUser;
8949
+ if (!user) {
8950
+ throw new Error("authFromTokenResponse: missing user identity");
9243
8951
  }
9244
8952
  return {
9245
- entries,
9246
- rawLines,
9247
- cwd: session.directory ?? undefined,
9248
- filePath: `opencode://${sessionId}`
8953
+ access_token: token.access_token,
8954
+ refresh_token: token.refresh_token,
8955
+ access_expires_at: now + token.access_expires_in,
8956
+ refresh_expires_at: now + token.refresh_expires_in,
8957
+ user
9249
8958
  };
9250
8959
  }
9251
- var getCachedOpenCodeSessionLog;
9252
- var init_opencode_sessions = __esm(() => {
9253
- init_log_entries();
9254
- getCachedOpenCodeSessionLog = runtimeCache((sessionId) => getOpenCodeSessionLog(sessionId), 30, { maxSize: 50 });
8960
+ var inFlightRefreshes;
8961
+ var init_auth_store = __esm(() => {
8962
+ init_atomic_write();
8963
+ init_api_server_client();
8964
+ inFlightRefreshes = new Map;
9255
8965
  });
9256
8966
 
9257
- // src/audit/cli-adapters/opencode.ts
9258
- async function listOpenCodeTranscriptMetadata(opts = {}) {
9259
- const projectFilter = opts.projects ? new Set(opts.projects) : null;
9260
- const sinceMs = opts.sinceMs ?? 0;
9261
- const out = [];
9262
- const projects = await getOpenCodeProjects();
9263
- for (const project of projects) {
9264
- const { cwd, sessions } = await getOpenCodeSessionsByEncodedName(project.name);
9265
- const effectiveCwd = cwd ?? "";
9266
- if (projectFilter && !projectFilter.has(effectiveCwd))
8967
+ // src/auth/cli.ts
8968
+ var exports_cli = {};
8969
+ __export(exports_cli, {
8970
+ runAuthCli: () => runAuthCli,
8971
+ parseAuthArgs: () => parseAuthArgs
8972
+ });
8973
+ import * as readline3 from "node:readline";
8974
+ function parseAuthArgs(args) {
8975
+ if (args.includes("--help") || args.includes("-h"))
8976
+ return { mode: "help" };
8977
+ const positional = [];
8978
+ const legacy = [];
8979
+ for (const a of args) {
8980
+ if (a === "--help" || a === "-h")
8981
+ continue;
8982
+ if (a in LEGACY_FLAG_TO_SUB) {
8983
+ legacy.push(LEGACY_FLAG_TO_SUB[a]);
9267
8984
  continue;
9268
- for (const s of sessions) {
9269
- const mtimeMs = s.lastModified.getTime();
9270
- if (mtimeMs < sinceMs)
9271
- continue;
9272
- if (!s.sessionId)
9273
- continue;
9274
- out.push({
9275
- cli: "opencode",
9276
- projectName: project.name,
9277
- sessionId: s.sessionId,
9278
- transcriptPath: s.path,
9279
- mtimeMs,
9280
- sizeBytes: 0
9281
- });
9282
8985
  }
8986
+ if (a.startsWith("-")) {
8987
+ throw new CliError(`Unknown flag for auth: ${a}
8988
+ Run \`failproofai auth help\` for usage.`);
8989
+ }
8990
+ positional.push(a);
8991
+ }
8992
+ const subs = [...positional, ...legacy];
8993
+ if (subs.length === 0)
8994
+ return { mode: "help" };
8995
+ if (subs.length > 1) {
8996
+ throw new CliError(`Pick one of login, logout, whoami.
8997
+ Run \`failproofai auth help\` for usage.`);
8998
+ }
8999
+ const sub = subs[0];
9000
+ if (!SUBCOMMANDS.has(sub)) {
9001
+ throw new CliError(`Unknown auth subcommand: ${sub}
9002
+ Run \`failproofai auth help\` for usage.`);
9003
+ }
9004
+ return { mode: sub };
9005
+ }
9006
+ function prompt(question, opts = {}) {
9007
+ const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
9008
+ if (opts.hidden && process.stdin.isTTY) {
9009
+ const r = rl;
9010
+ const orig = r._writeToOutput.bind(rl);
9011
+ r._writeToOutput = (s) => {
9012
+ if (s.length > 0 && s !== `\r
9013
+ ` && s !== `
9014
+ `)
9015
+ orig("*");
9016
+ else
9017
+ orig(s);
9018
+ };
9283
9019
  }
9284
- return out;
9285
- }
9286
- async function streamOpenCodeEvents(meta) {
9287
- const log = await getOpenCodeSessionLog(meta.sessionId);
9288
- if (!log)
9289
- return [];
9290
- return logEntriesToEvents(log.entries, {
9291
- cli: "opencode",
9292
- sessionId: meta.sessionId,
9293
- transcriptPath: meta.transcriptPath,
9294
- cwd: log.cwd ?? ""
9020
+ return new Promise((resolve12) => {
9021
+ rl.question(question, (answer) => {
9022
+ rl.close();
9023
+ if (opts.hidden && process.stdin.isTTY)
9024
+ process.stdout.write(`
9025
+ `);
9026
+ resolve12(answer.trim());
9027
+ });
9295
9028
  });
9296
9029
  }
9297
- var init_opencode = __esm(() => {
9298
- init_opencode_projects();
9299
- init_opencode_sessions();
9300
- init_shared();
9301
- });
9302
-
9303
- // src/audit/cli-adapters/pi.ts
9304
- import { statSync as statSync13 } from "node:fs";
9305
- async function listPiTranscriptMetadata(opts = {}) {
9306
- const projectFilter = opts.projects ? new Set(opts.projects) : null;
9307
- const sinceMs = opts.sinceMs ?? 0;
9308
- const out = [];
9309
- const projects = await getPiProjects();
9310
- for (const project of projects) {
9311
- const { cwd, sessions } = await getPiSessionsByEncodedName(project.name);
9312
- const effectiveCwd = cwd ?? "";
9313
- if (projectFilter && !projectFilter.has(effectiveCwd))
9314
- continue;
9315
- for (const s of sessions) {
9316
- const mtimeMs = s.lastModified.getTime();
9317
- if (mtimeMs < sinceMs)
9318
- continue;
9319
- let sizeBytes = 0;
9320
- try {
9321
- sizeBytes = statSync13(s.path).size;
9322
- } catch {}
9323
- if (!s.sessionId)
9324
- continue;
9325
- out.push({
9326
- cli: "pi",
9327
- projectName: project.name,
9328
- sessionId: s.sessionId,
9329
- transcriptPath: s.path,
9330
- mtimeMs,
9331
- sizeBytes
9030
+ function emailLooksValid(email) {
9031
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
9032
+ }
9033
+ async function runLogin() {
9034
+ const existing = readAuth();
9035
+ if (existing) {
9036
+ const nowSecs = Math.floor(Date.now() / 1000);
9037
+ const refreshUsable = existing.refresh_expires_at > nowSecs;
9038
+ if (refreshUsable) {
9039
+ trackHookEvent2(getInstanceId2(), "audit_cli_auth_login_completed", {
9040
+ source: "cli",
9041
+ status: "already_signed_in",
9042
+ user_id: existing.user.id
9332
9043
  });
9044
+ process.stdout.write(`${DIM}already signed in as${RESET} ${existing.user.email} ${DIM}(use \`failproofai auth logout\` to switch accounts)${RESET}
9045
+ `);
9046
+ return;
9333
9047
  }
9048
+ process.stdout.write(`${DIM}stored session for ${existing.user.email} has expired — re-authenticating.${RESET}
9049
+ `);
9050
+ deleteAuth();
9334
9051
  }
9335
- return out;
9336
- }
9337
- async function streamPiEvents(meta) {
9338
- const log = await getPiSessionLog(meta.sessionId);
9339
- if (!log)
9340
- return [];
9341
- return logEntriesToEvents(log.entries, {
9342
- cli: "pi",
9343
- sessionId: meta.sessionId,
9344
- transcriptPath: meta.transcriptPath,
9345
- cwd: log.cwd ?? ""
9052
+ trackHookEvent2(getInstanceId2(), "audit_cli_auth_login_started", {
9053
+ source: "cli",
9054
+ api_base: getApiBase(),
9055
+ replaced_stale: existing !== null
9346
9056
  });
9347
- }
9348
- var init_pi = __esm(() => {
9349
- init_pi_projects();
9350
- init_pi_sessions();
9351
- init_shared();
9352
- });
9057
+ process.stdout.write(`${PINK}━━ failproofai auth ━━${RESET}
9058
+ `);
9059
+ process.stdout.write(`${DIM}api: ${getApiBase()}${RESET}
9353
9060
 
9354
- // src/audit/cli-adapters/gemini.ts
9355
- import { statSync as statSync14 } from "node:fs";
9356
- async function listGeminiTranscriptMetadata(opts = {}) {
9357
- const projectFilter = opts.projects ? new Set(opts.projects) : null;
9358
- const sinceMs = opts.sinceMs ?? 0;
9359
- const out = [];
9360
- const projects = await getGeminiProjects();
9361
- for (const project of projects) {
9362
- const { cwd, sessions } = await getGeminiSessionsByEncodedName(project.name);
9363
- const effectiveCwd = cwd ?? "";
9364
- if (projectFilter && !projectFilter.has(effectiveCwd))
9061
+ `);
9062
+ let email = "";
9063
+ for (let attempt = 0;attempt < 3; attempt++) {
9064
+ email = await prompt("email: ");
9065
+ if (emailLooksValid(email))
9066
+ break;
9067
+ process.stdout.write(`${RED}that doesn't look like an email — try again.${RESET}
9068
+ `);
9069
+ email = "";
9070
+ }
9071
+ if (!email) {
9072
+ trackHookEvent2(getInstanceId2(), "audit_cli_auth_login_completed", {
9073
+ source: "cli",
9074
+ status: "aborted_invalid_email"
9075
+ });
9076
+ throw new CliError("Could not read a valid email after 3 attempts.");
9077
+ }
9078
+ try {
9079
+ const r = await requestLoginCode(email);
9080
+ trackHookEvent2(getInstanceId2(), "audit_otp_requested", {
9081
+ source: "cli",
9082
+ status: "success",
9083
+ expires_in: r.expires_in,
9084
+ resend_available_in: r.resend_available_in
9085
+ });
9086
+ process.stdout.write(`
9087
+ ${GREEN}code sent.${RESET} ${DIM}check ${email} — expires in ${r.expires_in}s.${RESET}
9088
+ `);
9089
+ } catch (err) {
9090
+ const isApi = err instanceof AuthApiError;
9091
+ trackHookEvent2(getInstanceId2(), "audit_otp_requested", {
9092
+ source: "cli",
9093
+ status: "failed",
9094
+ error_code: isApi ? err.code : "upstream_unreachable",
9095
+ http_status: isApi ? err.status : null
9096
+ });
9097
+ if (isApi && err.code === "rate_limited") {
9098
+ throw new CliError(`Rate limited — try again in ${err.retryAfterSecs ?? "a few"} seconds.`);
9099
+ }
9100
+ if (isApi) {
9101
+ throw new CliError(`Login request failed (${err.code}): ${err.message}`);
9102
+ }
9103
+ throw new CliError(`Could not reach the api-server at ${getApiBase()}.
9104
+ ` + `Check your network, or set FAILPROOF_API_URL to point at a different host.`);
9105
+ }
9106
+ let tokenResp;
9107
+ let verifyAttempts = 0;
9108
+ for (let attempt = 0;attempt < 5; attempt++) {
9109
+ const code = await prompt("code: ", { hidden: true });
9110
+ if (!code)
9365
9111
  continue;
9366
- for (const s of sessions) {
9367
- const mtimeMs = s.lastModified.getTime();
9368
- if (mtimeMs < sinceMs)
9369
- continue;
9370
- let sizeBytes = 0;
9371
- try {
9372
- sizeBytes = statSync14(s.path).size;
9373
- } catch {}
9374
- if (!s.sessionId)
9375
- continue;
9376
- out.push({
9377
- cli: "gemini",
9378
- projectName: project.name,
9379
- sessionId: s.sessionId,
9380
- transcriptPath: s.path,
9381
- mtimeMs,
9382
- sizeBytes
9112
+ verifyAttempts += 1;
9113
+ try {
9114
+ tokenResp = await verifyLoginCode(email, code);
9115
+ break;
9116
+ } catch (err) {
9117
+ const isApi = err instanceof AuthApiError;
9118
+ trackHookEvent2(getInstanceId2(), "audit_otp_verified", {
9119
+ source: "cli",
9120
+ status: "failed",
9121
+ attempt: verifyAttempts,
9122
+ error_code: isApi ? err.code : "upstream_unreachable",
9123
+ http_status: isApi ? err.status : null
9383
9124
  });
9125
+ if (isApi && err.status === 401) {
9126
+ process.stdout.write(`${RED}code rejected — try again.${RESET}
9127
+ `);
9128
+ continue;
9129
+ }
9130
+ if (isApi) {
9131
+ throw new CliError(`Verify failed (${err.code}): ${err.message}`);
9132
+ }
9133
+ throw new CliError(`Could not reach the api-server at ${getApiBase()}.`);
9384
9134
  }
9385
9135
  }
9386
- return out;
9387
- }
9388
- async function streamGeminiEvents(meta) {
9389
- const log = await getGeminiSessionLog(meta.sessionId);
9390
- if (!log)
9391
- return [];
9392
- return logEntriesToEvents(log.entries, {
9393
- cli: "gemini",
9394
- sessionId: meta.sessionId,
9395
- transcriptPath: meta.transcriptPath,
9396
- cwd: log.cwd ?? ""
9136
+ if (!tokenResp) {
9137
+ trackHookEvent2(getInstanceId2(), "audit_cli_auth_login_completed", {
9138
+ source: "cli",
9139
+ status: "exhausted_attempts",
9140
+ attempts: verifyAttempts
9141
+ });
9142
+ throw new CliError("Too many bad codes — start over.");
9143
+ }
9144
+ writeAuth(authFromTokenResponse(tokenResp));
9145
+ trackHookEvent2(getInstanceId2(), "audit_otp_verified", {
9146
+ source: "cli",
9147
+ status: "success",
9148
+ attempt: verifyAttempts,
9149
+ user_id: tokenResp.user.id,
9150
+ email: tokenResp.user.email
9151
+ });
9152
+ trackHookEvent2(getInstanceId2(), "audit_user_identity_linked", {
9153
+ source: "cli",
9154
+ user_id: tokenResp.user.id,
9155
+ email: tokenResp.user.email,
9156
+ local_random_id: getInstanceId2(),
9157
+ $set: { email: tokenResp.user.email, user_id: tokenResp.user.id }
9158
+ });
9159
+ trackHookEvent2(getInstanceId2(), "audit_cli_auth_login_completed", {
9160
+ source: "cli",
9161
+ status: "success",
9162
+ attempts: verifyAttempts,
9163
+ user_id: tokenResp.user.id
9397
9164
  });
9165
+ process.stdout.write(`
9166
+ ${GREEN}✓ signed in as ${tokenResp.user.email}${RESET}
9167
+ ` + `${DIM}session saved to ~/.failproofai/auth.json (mode 0600)${RESET}
9168
+ `);
9398
9169
  }
9399
- var init_gemini = __esm(() => {
9400
- init_gemini_projects();
9401
- init_gemini_sessions();
9402
- init_shared();
9403
- });
9404
-
9405
- // src/audit/cli-adapters/index.ts
9406
- var ADAPTERS;
9407
- var init_cli_adapters = __esm(() => {
9408
- init_claude();
9409
- init_codex();
9410
- init_copilot();
9411
- init_cursor();
9412
- init_opencode();
9413
- init_pi();
9414
- init_gemini();
9415
- ADAPTERS = {
9416
- claude: {
9417
- cli: "claude",
9418
- listTranscripts: listClaudeTranscriptMetadata,
9419
- streamEvents: streamClaudeEvents
9420
- },
9421
- codex: {
9422
- cli: "codex",
9423
- listTranscripts: listCodexTranscriptMetadata,
9424
- streamEvents: streamCodexEvents
9425
- },
9426
- copilot: {
9427
- cli: "copilot",
9428
- listTranscripts: listCopilotTranscriptMetadata,
9429
- streamEvents: streamCopilotEvents
9430
- },
9431
- cursor: {
9432
- cli: "cursor",
9433
- listTranscripts: listCursorTranscriptMetadata,
9434
- streamEvents: streamCursorEvents
9435
- },
9436
- opencode: {
9437
- cli: "opencode",
9438
- listTranscripts: listOpenCodeTranscriptMetadata,
9439
- streamEvents: streamOpenCodeEvents
9440
- },
9441
- pi: {
9442
- cli: "pi",
9443
- listTranscripts: listPiTranscriptMetadata,
9444
- streamEvents: streamPiEvents
9445
- },
9446
- gemini: {
9447
- cli: "gemini",
9448
- listTranscripts: listGeminiTranscriptMetadata,
9449
- streamEvents: streamGeminiEvents
9450
- }
9451
- };
9452
- });
9453
-
9454
- // src/audit/detectors/redundant-cd-cwd.ts
9455
- var redundantCdCwd;
9456
- var init_redundant_cd_cwd = __esm(() => {
9457
- redundantCdCwd = {
9458
- name: "redundant-cd-cwd",
9459
- description: "Bash commands prefixed with `cd <cwd> && …` even though commands already run in cwd.",
9460
- category: "Wasteful",
9461
- severity: "info",
9462
- displayTitle: "Prepended cd <cwd> before commands",
9463
- impact: "Pure waste — your agent's shell already runs in `cwd`.",
9464
- detect(event) {
9465
- if (event.toolName !== "Bash")
9466
- return null;
9467
- const command = event.toolInput.command;
9468
- if (typeof command !== "string" || !event.cwd)
9469
- return null;
9470
- const trimmed = command.trimStart();
9471
- const match = /^cd\s+(?:"([^"]+)"|'([^']+)'|(\S+))\s*&&\s*([\s\S]+)$/.exec(trimmed);
9472
- if (!match)
9473
- return null;
9474
- const path3 = (match[1] ?? match[2] ?? match[3] ?? "").replace(/\/+$/, "");
9475
- const cwd = event.cwd.replace(/\/+$/, "");
9476
- if (path3 !== cwd)
9477
- return null;
9478
- const rest = match[4].trim();
9479
- return { example: `cd ${path3} && ${rest}` };
9480
- }
9481
- };
9482
- });
9483
-
9484
- // src/audit/detectors/prefer-edit-over-read-cat.ts
9485
- var SOURCE_EXT_RE, preferEditOverReadCat;
9486
- var init_prefer_edit_over_read_cat = __esm(() => {
9487
- SOURCE_EXT_RE = /\.(?:ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|kt|swift|rb|php|c|h|cc|cpp|hpp|cs|scala|sh|bash|zsh|json|yaml|yml|toml|md|txt|sql|html|css|scss|sass)$/i;
9488
- preferEditOverReadCat = {
9489
- name: "prefer-edit-over-read-cat",
9490
- description: "Bash `cat`/`head`/`tail`/`less`/`more` on a single source file — use Read.",
9491
- category: "Wasteful",
9492
- severity: "info",
9493
- displayTitle: "Used `cat`/`head`/`tail` on a source file",
9494
- impact: "Burns tokens; the Read tool returns content directly without going through Bash output.",
9495
- detect(event) {
9496
- if (event.toolName !== "Bash")
9497
- return null;
9498
- const command = event.toolInput.command;
9499
- if (typeof command !== "string")
9500
- return null;
9501
- const cmd = command.trim();
9502
- if (/[|<>;&`$()]/.test(cmd))
9503
- return null;
9504
- const match = /^(cat|head|tail|less|more)\s+(?:-\S+\s+)*(?:"([^"]+)"|'([^']+)'|(\S+))\s*$/.exec(cmd);
9505
- if (!match)
9506
- return null;
9507
- const path3 = match[2] ?? match[3] ?? match[4] ?? "";
9508
- if (!path3)
9509
- return null;
9510
- if (/(?:^|\/)\.env(?:\..+)?$/.test(path3))
9511
- return null;
9512
- if (!SOURCE_EXT_RE.test(path3))
9513
- return null;
9514
- return { example: cmd };
9515
- }
9516
- };
9517
- });
9518
-
9519
- // src/audit/detectors/prefer-edit-over-sed-awk.ts
9520
- var preferEditOverSedAwk;
9521
- var init_prefer_edit_over_sed_awk = __esm(() => {
9522
- preferEditOverSedAwk = {
9523
- name: "prefer-edit-over-sed-awk",
9524
- description: "Bash `sed -i`/`awk` in-place edits — use Edit.",
9525
- category: "Wasteful",
9526
- severity: "info",
9527
- displayTitle: "Used sed -i or awk for an in-place edit",
9528
- impact: "Edit tool is safer and produces a diff the agent can verify.",
9529
- detect(event) {
9530
- if (event.toolName !== "Bash")
9531
- return null;
9532
- const command = event.toolInput.command;
9533
- if (typeof command !== "string")
9534
- return null;
9535
- const cmd = command.trim();
9536
- if (/(?:^|\s|;|&&|\|\|)sed\b[^|]*\s-i(?=\b|['"])/.test(cmd)) {
9537
- return { example: cmd };
9538
- }
9539
- if (/(?:^|\s|;|&&|\|\|)awk\b[^|]*\s>\s*\S+/.test(cmd) && !/\|/.test(cmd)) {
9540
- return { example: cmd };
9541
- }
9542
- return null;
9543
- }
9544
- };
9545
- });
9546
-
9547
- // src/audit/detectors/prefer-write-over-heredoc.ts
9548
- var preferWriteOverHeredoc;
9549
- var init_prefer_write_over_heredoc = __esm(() => {
9550
- preferWriteOverHeredoc = {
9551
- name: "prefer-write-over-heredoc",
9552
- description: "Bash heredoc / `echo > file` writing multi-line content — use Write.",
9553
- category: "Wasteful",
9554
- severity: "info",
9555
- displayTitle: "Used heredoc / `echo > file` to write a multi-line file",
9556
- impact: "Write tool handles escaping and is verifiable.",
9557
- detect(event) {
9558
- if (event.toolName !== "Bash")
9559
- return null;
9560
- const command = event.toolInput.command;
9561
- if (typeof command !== "string")
9562
- return null;
9563
- const cmd = command;
9564
- if (/<<-?\s*['"]?[A-Za-z_][A-Za-z0-9_]*['"]?\s*>\s*\S/.test(cmd)) {
9565
- const summary = cmd.replace(/\s+/g, " ").trim().slice(0, 160);
9566
- return { example: summary };
9567
- }
9568
- if (/(?:^|\s|;|&&|\|\|)(?:echo|printf)\s+["'][^"']*\n[^"']*["']\s*>\s*\S/.test(cmd)) {
9569
- const summary = cmd.replace(/\s+/g, " ").trim().slice(0, 160);
9570
- return { example: summary };
9571
- }
9572
- return null;
9573
- }
9574
- };
9575
- });
9576
-
9577
- // src/audit/detectors/sleep-polling-loop.ts
9578
- var SLEEP_THRESHOLD_SECONDS = 30, sleepPollingLoop;
9579
- var init_sleep_polling_loop = __esm(() => {
9580
- sleepPollingLoop = {
9581
- name: "sleep-polling-loop",
9582
- description: "Bash long `sleep` or while-sleep polling loops.",
9583
- category: "Wasteful",
9584
- severity: "info",
9585
- displayTitle: "Used a long sleep or while-sleep polling loop",
9586
- impact: "Burns wall-clock; better to wait for an explicit signal.",
9587
- detect(event) {
9588
- if (event.toolName !== "Bash")
9589
- return null;
9590
- const command = event.toolInput.command;
9591
- if (typeof command !== "string")
9592
- return null;
9593
- const cmd = command;
9594
- if (/\bwhile\b[\s\S]*?\bsleep\b[\s\S]*?\bdone\b/.test(cmd)) {
9595
- return { example: cmd.replace(/\s+/g, " ").trim().slice(0, 160) };
9596
- }
9597
- const match = /\bsleep\s+(\d+(?:\.\d+)?)(m|h|d)?\b/.exec(cmd);
9598
- if (match) {
9599
- const n = parseFloat(match[1]);
9600
- const unit = match[2] ?? "s";
9601
- const seconds = unit === "m" ? n * 60 : unit === "h" ? n * 3600 : unit === "d" ? n * 86400 : n;
9602
- if (seconds >= SLEEP_THRESHOLD_SECONDS) {
9603
- return { example: cmd.replace(/\s+/g, " ").trim().slice(0, 160) };
9604
- }
9605
- }
9606
- return null;
9607
- }
9608
- };
9609
- });
9610
-
9611
- // src/audit/detectors/find-from-root.ts
9612
- var RISKY_ROOTS, findFromRoot;
9613
- var init_find_from_root = __esm(() => {
9614
- RISKY_ROOTS = ["/", "/home", "/usr", "/etc", "/var", "/opt", "/Users"];
9615
- findFromRoot = {
9616
- name: "find-from-root",
9617
- description: "Bash `find` against `/`, `/home`, `/usr`, etc. — scope to cwd instead.",
9618
- category: "Risky",
9619
- severity: "warn",
9620
- displayTitle: "Ran find from /, /home, /usr, etc.",
9621
- impact: "Filesystem-wide finds exhaust resources and rarely return useful results.",
9622
- detect(event) {
9623
- if (event.toolName !== "Bash")
9624
- return null;
9625
- const command = event.toolInput.command;
9626
- if (typeof command !== "string")
9627
- return null;
9628
- const cmd = command.trim();
9629
- const match = /(?:^|[\s;|&])find\s+(?:-\S+\s+)*("[^"]+"|'[^']+'|\S+)/.exec(cmd);
9630
- if (!match)
9631
- return null;
9632
- const raw = match[1].replace(/^["']|["']$/g, "");
9633
- const stripped = raw.replace(/\/+$/, "") || "/";
9634
- if (!RISKY_ROOTS.includes(stripped))
9635
- return null;
9636
- return { example: cmd.slice(0, 160) };
9637
- }
9638
- };
9639
- });
9640
-
9641
- // src/audit/detectors/git-commit-no-verify.ts
9642
- var gitCommitNoVerify;
9643
- var init_git_commit_no_verify = __esm(() => {
9644
- gitCommitNoVerify = {
9645
- name: "git-commit-no-verify",
9646
- description: "git commit invoked with --no-verify / -n, skipping hooks.",
9647
- category: "Risky",
9648
- severity: "warn",
9649
- displayTitle: "Committed with --no-verify",
9650
- impact: "Skips pre-commit hooks that exist to catch broken or unsafe code.",
9651
- detect(event) {
9652
- if (event.toolName !== "Bash")
9653
- return null;
9654
- const command = event.toolInput.command;
9655
- if (typeof command !== "string")
9656
- return null;
9657
- const cmd = command;
9658
- if (!/\bgit\s+commit\b/.test(cmd))
9659
- return null;
9660
- if (/\s--no-verify\b/.test(cmd) || /\s-n\b/.test(cmd)) {
9661
- return { example: cmd.replace(/\s+/g, " ").trim().slice(0, 160) };
9662
- }
9663
- return null;
9664
- }
9665
- };
9666
- });
9667
-
9668
- // src/audit/detectors/reread-after-edit.ts
9669
- function getState(state) {
9670
- let s = state[STATE_KEY];
9671
- if (!s) {
9672
- s = { countdown: new Map };
9673
- state[STATE_KEY] = s;
9674
- }
9675
- return s;
9676
- }
9677
- var STATE_KEY = "rereadAfterEdit", WINDOW = 5, rereadAfterEdit;
9678
- var init_reread_after_edit = __esm(() => {
9679
- rereadAfterEdit = {
9680
- name: "reread-after-edit",
9681
- description: "Read of a file that was just Edit'd or Write'n in the same session.",
9682
- category: "Wasteful",
9683
- severity: "info",
9684
- displayTitle: "Re-read a file it just edited",
9685
- impact: "Edit/Write already returned the updated content; the second Read is wasted tokens.",
9686
- detect(event, sessionState) {
9687
- const state = getState(sessionState);
9688
- const filePath = event.toolInput.file_path;
9689
- const pathStr = typeof filePath === "string" ? filePath : null;
9690
- for (const [key, n] of state.countdown) {
9691
- if (n <= 1)
9692
- state.countdown.delete(key);
9693
- else
9694
- state.countdown.set(key, n - 1);
9695
- }
9696
- if (!pathStr)
9697
- return null;
9698
- if (event.toolName === "Edit" || event.toolName === "Write") {
9699
- state.countdown.set(pathStr, WINDOW);
9700
- return null;
9701
- }
9702
- if (event.toolName === "Read") {
9703
- if (state.countdown.has(pathStr)) {
9704
- state.countdown.delete(pathStr);
9705
- return { example: `Read ${pathStr} immediately after Edit/Write` };
9706
- }
9707
- }
9708
- return null;
9709
- }
9710
- };
9711
- });
9712
-
9713
- // src/audit/detectors/index.ts
9714
- var AUDIT_DETECTORS;
9715
- var init_detectors = __esm(() => {
9716
- init_redundant_cd_cwd();
9717
- init_prefer_edit_over_read_cat();
9718
- init_prefer_edit_over_sed_awk();
9719
- init_prefer_write_over_heredoc();
9720
- init_sleep_polling_loop();
9721
- init_find_from_root();
9722
- init_git_commit_no_verify();
9723
- init_reread_after_edit();
9724
- AUDIT_DETECTORS = [
9725
- redundantCdCwd,
9726
- preferEditOverReadCat,
9727
- preferEditOverSedAwk,
9728
- preferWriteOverHeredoc,
9729
- sleepPollingLoop,
9730
- findFromRoot,
9731
- gitCommitNoVerify,
9732
- rereadAfterEdit
9733
- ];
9734
- });
9735
-
9736
- // src/audit/cache.ts
9737
- import { createHash } from "node:crypto";
9738
- import { existsSync as existsSync13, mkdirSync as mkdirSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync5, chmodSync } from "node:fs";
9739
- import { join as join19 } from "node:path";
9740
- import { homedir as homedir19 } from "node:os";
9741
- function getEngineVersion() {
9742
- if (cachedEngineVersion)
9743
- return cachedEngineVersion;
9744
- const blob = BUILTIN_POLICIES.map((p) => `${p.name}|${p.fn.toString()}`).sort().join(`
9745
- `);
9746
- cachedEngineVersion = createHash("sha1").update(blob).digest("hex").slice(0, 16);
9747
- return cachedEngineVersion;
9748
- }
9749
- function getDetectorVersion() {
9750
- if (cachedDetectorVersion)
9751
- return cachedDetectorVersion;
9752
- const blob = AUDIT_DETECTORS.map((d) => `${d.name}|${d.detect.toString()}`).sort().join(`
9170
+ async function runLogout() {
9171
+ const existing = readAuth();
9172
+ if (!existing) {
9173
+ trackHookEvent2(getInstanceId2(), "audit_cli_auth_logout_completed", {
9174
+ source: "cli",
9175
+ had_session: false,
9176
+ upstream: "noop"
9177
+ });
9178
+ process.stdout.write(`${DIM}not signed in. nothing to do.${RESET}
9753
9179
  `);
9754
- cachedDetectorVersion = createHash("sha1").update(blob).digest("hex").slice(0, 16);
9755
- return cachedDetectorVersion;
9756
- }
9757
- function getCachePathFor(transcriptPath) {
9758
- const root = join19(homedir19(), ".failproofai", "cache", "audit");
9759
- const key = createHash("sha1").update(transcriptPath).digest("hex");
9760
- return join19(root, `${key}.json`);
9761
- }
9762
- function readCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes) {
9763
- if (sizeBytes === 0)
9764
- return null;
9765
- const cachePath = getCachePathFor(transcriptPath);
9766
- if (!existsSync13(cachePath))
9767
- return null;
9768
- try {
9769
- const raw = readFileSync10(cachePath, "utf-8");
9770
- const entry = JSON.parse(raw);
9771
- if (entry.mtimeMs !== mtimeMs)
9772
- return null;
9773
- if (entry.sizeBytes !== sizeBytes)
9774
- return null;
9775
- if (entry.engineVersion !== getEngineVersion())
9776
- return null;
9777
- if (entry.detectorVersion !== getDetectorVersion())
9778
- return null;
9779
- return entry.result;
9780
- } catch {
9781
- return null;
9782
- }
9783
- }
9784
- function writeCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes, result) {
9785
- if (sizeBytes === 0)
9786
9180
  return;
9787
- const cachePath = getCachePathFor(transcriptPath);
9181
+ }
9182
+ let upstream = "revoked";
9788
9183
  try {
9789
- mkdirSync6(join19(homedir19(), ".failproofai", "cache", "audit"), { recursive: true });
9790
- const entry = {
9791
- mtimeMs,
9792
- sizeBytes,
9793
- engineVersion: getEngineVersion(),
9794
- detectorVersion: getDetectorVersion(),
9795
- result
9796
- };
9797
- writeFileSync5(cachePath, JSON.stringify(entry), { encoding: "utf-8", mode: 384 });
9798
- try {
9799
- chmodSync(cachePath, 384);
9800
- } catch {}
9801
- } catch {}
9802
- }
9803
- var cachedEngineVersion = null, cachedDetectorVersion = null;
9804
- var init_cache = __esm(() => {
9805
- init_builtin_policies();
9806
- init_detectors();
9807
- });
9808
-
9809
- // src/audit/replay.ts
9810
- function initReplay() {
9811
- if (initialized)
9812
- return;
9813
- clearPolicies();
9814
- const enabled = BUILTIN_POLICIES.map((p) => p.name).filter((n) => !SKIP_POLICIES.has(normalizePolicyName(n)));
9815
- registerBuiltinPolicies(enabled);
9816
- initialized = true;
9817
- }
9818
- async function replayEvent(event) {
9819
- if (!initialized)
9820
- initReplay();
9821
- const session = {
9822
- sessionId: event.sessionId,
9823
- transcriptPath: event.transcriptPath,
9824
- cwd: event.cwd,
9825
- cli: event.cli
9826
- };
9827
- const baseToolPayload = {
9828
- tool_name: event.toolName,
9829
- tool_input: event.toolInput,
9830
- session_id: event.sessionId,
9831
- cwd: event.cwd,
9832
- transcript_path: event.transcriptPath
9833
- };
9834
- const out = [];
9835
- const pre = await evaluatePolicies("PreToolUse", baseToolPayload, session);
9836
- collectHits(pre, "PreToolUse", out);
9837
- if (event.toolResultText !== undefined) {
9838
- const postPayload = { ...baseToolPayload, tool_response: event.toolResultText };
9839
- const post = await evaluatePolicies("PostToolUse", postPayload, session);
9840
- collectHits(post, "PostToolUse", out);
9184
+ await logoutSession(existing.access_token, existing.refresh_token);
9185
+ } catch (err) {
9186
+ if (err instanceof AuthApiError && err.status === 401) {} else {
9187
+ upstream = "failed";
9188
+ }
9841
9189
  }
9842
- return out;
9190
+ deleteAuth();
9191
+ trackHookEvent2(getInstanceId2(), "audit_cli_auth_logout_completed", {
9192
+ source: "cli",
9193
+ had_session: true,
9194
+ upstream,
9195
+ user_id: existing.user.id
9196
+ });
9197
+ process.stdout.write(`${GREEN}✓ signed out as ${existing.user.email}.${RESET}
9198
+ `);
9843
9199
  }
9844
- function collectHits(result, eventType, out) {
9845
- const names = result.policyNames && result.policyNames.length > 0 ? result.policyNames : result.policyName ? [result.policyName] : [];
9846
- for (const name of names) {
9847
- out.push({
9848
- policyName: name,
9849
- decision: result.decision,
9850
- reason: result.reason,
9851
- eventType
9200
+ function runWhoami() {
9201
+ const existing = readAuth();
9202
+ if (!existing) {
9203
+ trackHookEvent2(getInstanceId2(), "audit_cli_auth_whoami", {
9204
+ source: "cli",
9205
+ authenticated: false
9852
9206
  });
9207
+ process.stdout.write(`${DIM}not signed in — run \`failproofai auth login\` to sign in.${RESET}
9208
+ `);
9209
+ process.exitCode = 1;
9210
+ return;
9853
9211
  }
9854
- }
9855
- var SKIP_POLICIES, initialized = false;
9856
- var init_replay = __esm(() => {
9857
- init_policy_evaluator();
9858
- init_builtin_policies();
9859
- SKIP_POLICIES = new Set(["warn-repeated-tool-calls"].map((n) => normalizePolicyName(n)));
9860
- });
9861
-
9862
- // src/audit/telemetry.ts
9863
- function ageBucketDays(iso) {
9864
- if (!iso)
9865
- return null;
9866
- const ms = Date.now() - new Date(iso).getTime();
9867
- if (Number.isNaN(ms) || ms < 0)
9868
- return null;
9869
- const days = Math.floor(ms / 86400000);
9870
- if (days <= 0)
9871
- return 0;
9872
- if (days <= 1)
9873
- return 1;
9874
- if (days <= 7)
9875
- return 7;
9876
- if (days <= 30)
9877
- return 30;
9878
- if (days <= 90)
9879
- return 90;
9880
- if (days <= 365)
9881
- return 365;
9882
- return 366;
9883
- }
9884
- function shortName(name) {
9885
- const slash = name.indexOf("/");
9886
- return slash >= 0 ? name.slice(slash + 1) : name;
9887
- }
9888
- function trackAuditStarted(opts, outputMode) {
9889
- trackHookEvent2(getInstanceId2(), "audit_started", {
9890
- clis_requested: opts.clis ?? "all",
9891
- since_window: opts.since ?? null,
9892
- has_project_filter: !!opts.projects?.length,
9893
- has_policy_filter: !!opts.policies?.length,
9894
- no_cache: !!opts.noCache,
9895
- output_mode: outputMode
9896
- });
9897
- }
9898
- function trackAuditPatternDetected(count) {
9899
- trackHookEvent2(getInstanceId2(), "audit_pattern_detected", {
9900
- pattern_name: shortName(count.name),
9901
- pattern_source: count.source,
9902
- pattern_category: count.category,
9903
- hits: count.hits,
9904
- projects: count.projects,
9905
- enabled_in_config: count.enabledInConfig,
9906
- severity: count.severity,
9907
- first_seen_age_days: ageBucketDays(count.firstSeen),
9908
- last_seen_age_days: ageBucketDays(count.lastSeen)
9212
+ trackHookEvent2(getInstanceId2(), "audit_cli_auth_whoami", {
9213
+ source: "cli",
9214
+ authenticated: true,
9215
+ user_id: existing.user.id
9909
9216
  });
9217
+ process.stdout.write(`${GREEN}✓${RESET} ${existing.user.email} ${DIM}(${existing.user.id})${RESET}
9218
+ `);
9910
9219
  }
9911
- function trackAuditInstallCtaShown(unenabledNames) {
9912
- if (unenabledNames.length === 0)
9220
+ async function runAuthCli(args) {
9221
+ const opts = parseAuthArgs(args);
9222
+ if (opts.mode === "help") {
9223
+ process.stdout.write(HELP);
9913
9224
  return;
9914
- trackHookEvent2(getInstanceId2(), "audit_install_cta_shown", {
9915
- unenabled_count: unenabledNames.length,
9916
- unenabled_pattern_names: unenabledNames.map(shortName)
9917
- });
9918
- }
9919
- function trackAuditCompleted(result, outputMode) {
9920
- const enabledHits = result.results.filter((r) => r.source === "builtin" && r.enabledInConfig).reduce((acc, r) => acc + r.hits, 0);
9921
- const unenabledHits = result.results.filter((r) => r.source === "builtin" && !r.enabledInConfig).reduce((acc, r) => acc + r.hits, 0);
9922
- const detectorHits = result.results.filter((r) => r.source === "audit-detector").reduce((acc, r) => acc + r.hits, 0);
9923
- trackHookEvent2(getInstanceId2(), "audit_completed", {
9924
- duration_ms: result.transcripts.durationMs,
9925
- transcripts_scanned: result.transcripts.scanned,
9926
- transcripts_skipped: result.transcripts.skipped,
9927
- transcripts_errors: result.transcripts.errors,
9928
- total_hits: result.totals.hits,
9929
- projects_with_hits: result.totals.projectsWithHits,
9930
- enabled_builtin_hits: enabledHits,
9931
- unenabled_builtin_hits: unenabledHits,
9932
- audit_detector_hits: detectorHits,
9933
- result_count: result.results.length,
9934
- clis_scanned: result.scope.cli,
9935
- since_window: result.scope.since,
9936
- has_project_filter: result.scope.projects !== "all",
9937
- output_mode: outputMode
9938
- });
9225
+ }
9226
+ if (opts.mode === "login")
9227
+ return runLogin();
9228
+ if (opts.mode === "logout")
9229
+ return runLogout();
9230
+ return runWhoami();
9939
9231
  }
9940
- var init_telemetry = __esm(() => {
9232
+ var HELP, LEGACY_FLAG_TO_SUB, SUBCOMMANDS, DIM = "\x1B[2m", RESET = "\x1B[0m", PINK = "\x1B[38;5;204m", GREEN = "\x1B[38;5;120m", RED = "\x1B[38;5;197m";
9233
+ var init_cli = __esm(() => {
9234
+ init_api_server_client();
9235
+ init_auth_store();
9236
+ init_cli_error();
9941
9237
  init_hook_telemetry2();
9942
9238
  init_telemetry_id2();
9943
- });
9239
+ HELP = `
9240
+ failproofai auth — sign in to FailproofAI from the CLI
9944
9241
 
9945
- // src/audit/index.ts
9946
- var exports_audit = {};
9947
- __export(exports_audit, {
9948
- runAudit: () => runAudit
9949
- });
9950
- function shortPolicyName(name) {
9951
- const slash = name.indexOf("/");
9952
- return slash >= 0 ? name.slice(slash + 1) : name;
9953
- }
9954
- function findBuiltin(name) {
9955
- const short = shortPolicyName(name);
9956
- for (const p of BUILTIN_POLICIES) {
9957
- if (p.name === name || shortPolicyName(p.name) === short)
9958
- return p;
9959
- }
9960
- return null;
9961
- }
9962
- function buildInstallHint(name, source, enabled) {
9963
- if (source === "audit-detector") {
9964
- return "Audit-only — `failproofai audit` will keep tracking these.";
9965
- }
9966
- if (enabled) {
9967
- return "Already enforced — failproofai is blocking these in real time.";
9968
- }
9969
- return `Enable in one command: failproofai policies --install ${shortPolicyName(name)}`;
9970
- }
9971
- function truncateExample(s) {
9972
- if (s.length <= AUDIT_EXAMPLE_MAX_CHARS)
9973
- return s;
9974
- return s.slice(0, AUDIT_EXAMPLE_MAX_CHARS - 1) + "…";
9975
- }
9976
- function parseSinceOpt(since) {
9977
- if (!since)
9978
- return;
9979
- const m = /^(\d+)\s*([dhm])$/i.exec(since.trim());
9980
- if (m) {
9981
- const n = parseInt(m[1], 10);
9982
- const unit = m[2].toLowerCase();
9983
- const ms = unit === "d" ? 86400000 : unit === "h" ? 3600000 : 60000;
9984
- return Date.now() - n * ms;
9985
- }
9986
- const t = Date.parse(since);
9987
- if (!Number.isNaN(t))
9988
- return t;
9989
- throw new Error(`Invalid --since value: "${since}" (expected e.g. "7d", "30d", or "2026-04-01")`);
9990
- }
9991
- async function scanOneTranscript(meta) {
9992
- const empty = {
9993
- transcriptPath: meta.transcriptPath,
9994
- cli: meta.cli,
9995
- projectName: meta.projectName,
9996
- sessionId: meta.sessionId,
9997
- mtimeMs: meta.mtimeMs,
9998
- sizeBytes: meta.sizeBytes,
9999
- hitsByName: {},
10000
- examplesByName: {},
10001
- rangeByName: {}
10002
- };
10003
- const events = await ADAPTERS[meta.cli].streamEvents(meta);
10004
- if (events.length === 0)
10005
- return empty;
10006
- const result = empty;
10007
- const sessionState = {};
10008
- for (const event of events) {
10009
- for (const detector of AUDIT_DETECTORS) {
10010
- const hit = detector.detect(event, sessionState);
10011
- if (!hit)
10012
- continue;
10013
- recordHit(result, detector.name, event.timestamp, event.cwd, truncateExample(hit.example));
10014
- }
10015
- let replayHits;
10016
- try {
10017
- replayHits = await replayEvent(event);
10018
- } catch {
10019
- continue;
10020
- }
10021
- for (const hit of replayHits) {
10022
- const example = formatPolicyExample(hit.policyName, event);
10023
- recordHit(result, hit.policyName, event.timestamp, event.cwd, truncateExample(example));
10024
- }
10025
- }
10026
- return result;
10027
- }
10028
- function formatPolicyExample(_policyName, event) {
10029
- if (event.toolName === "Bash") {
10030
- const command = event.toolInput.command;
10031
- if (typeof command === "string")
10032
- return command.replace(/\s+/g, " ");
10033
- }
10034
- const filePath = event.toolInput.file_path;
10035
- if (typeof filePath === "string")
10036
- return `${event.toolName} ${filePath}`;
10037
- return `${event.toolName}`;
10038
- }
10039
- function recordHit(result, name, timestamp, cwd, example) {
10040
- result.hitsByName[name] = (result.hitsByName[name] ?? 0) + 1;
10041
- const exs = result.examplesByName[name] ?? [];
10042
- if (exs.length < AUDIT_MAX_EXAMPLES_PER_NAME) {
10043
- exs.push({ timestamp, cwd, example });
10044
- result.examplesByName[name] = exs;
10045
- }
10046
- const range = result.rangeByName[name];
10047
- if (!range) {
10048
- result.rangeByName[name] = { first: timestamp, last: timestamp };
10049
- } else {
10050
- if (timestamp < range.first)
10051
- range.first = timestamp;
10052
- if (timestamp > range.last)
10053
- range.last = timestamp;
10054
- }
10055
- }
10056
- function aggregateResults(perTranscript, enabledBuiltins) {
10057
- const byName = new Map;
10058
- for (const t of perTranscript) {
10059
- for (const [name, count] of Object.entries(t.hitsByName)) {
10060
- const bucket = byName.get(name) ?? {
10061
- hits: 0,
10062
- projects: new Set,
10063
- examples: []
10064
- };
10065
- bucket.hits += count;
10066
- bucket.projects.add(t.projectName);
10067
- const tExs = t.examplesByName[name] ?? [];
10068
- for (const e of tExs) {
10069
- if (bucket.examples.length < AUDIT_MAX_EXAMPLES_PER_NAME) {
10070
- bucket.examples.push({ ...e, sessionId: t.sessionId });
10071
- }
10072
- }
10073
- const range = t.rangeByName[name];
10074
- if (range) {
10075
- if (!bucket.first || range.first < bucket.first)
10076
- bucket.first = range.first;
10077
- if (!bucket.last || range.last > bucket.last)
10078
- bucket.last = range.last;
10079
- }
10080
- byName.set(name, bucket);
10081
- }
10082
- }
10083
- const detectorByName = new Map(AUDIT_DETECTORS.map((d) => [d.name, d]));
10084
- const out = [];
10085
- for (const [name, bucket] of byName) {
10086
- const detector = detectorByName.get(name);
10087
- const isDetector = !!detector;
10088
- const builtin = isDetector ? null : findBuiltin(name);
10089
- const source = isDetector ? "audit-detector" : "builtin";
10090
- const enabled = isDetector ? false : enabledBuiltins.has(normalizePolicyName(name));
10091
- const displayTitle = detector?.displayTitle ?? builtin?.displayTitle ?? detector?.description ?? builtin?.description ?? shortPolicyName(name);
10092
- const impact = detector?.impact ?? builtin?.impact ?? "";
10093
- out.push({
10094
- name,
10095
- source,
10096
- category: detector?.category ?? builtin?.category ?? "Custom",
10097
- severity: isDetector ? detector?.severity ?? "info" : "deny",
10098
- hits: bucket.hits,
10099
- projects: bucket.projects.size,
10100
- firstSeen: bucket.first,
10101
- lastSeen: bucket.last,
10102
- examples: bucket.examples,
10103
- displayTitle,
10104
- impact,
10105
- enabledInConfig: enabled,
10106
- installHint: buildInstallHint(name, source, enabled)
10107
- });
10108
- }
10109
- out.sort((a, b) => b.hits - a.hits);
10110
- return out;
10111
- }
10112
- async function runAudit(opts = {}) {
10113
- const startedAt = Date.now();
10114
- initReplay();
10115
- const outputMode = opts.json ? "json" : opts.noReport ? "text" : "text+markdown";
10116
- trackAuditStarted(opts, outputMode);
10117
- const clis = opts.clis ?? Array.from(INTEGRATION_TYPES);
10118
- const sinceMs = parseSinceOpt(opts.since);
10119
- const userConfig = readMergedHooksConfig();
10120
- const enabledBuiltins = new Set((userConfig.enabledPolicies ?? []).map((n) => normalizePolicyName(n)));
10121
- const allTranscripts = [];
10122
- for (const cli of clis) {
10123
- const adapter = ADAPTERS[cli];
10124
- let list;
10125
- try {
10126
- list = await adapter.listTranscripts({ projects: opts.projects, sinceMs });
10127
- } catch {
10128
- continue;
10129
- }
10130
- allTranscripts.push(...list);
10131
- }
10132
- let skipped = 0;
10133
- let errors = 0;
10134
- const tasks = allTranscripts.map((meta) => async () => {
10135
- if (!opts.noCache) {
10136
- const cached = readCachedTranscriptResult(meta.transcriptPath, meta.mtimeMs, meta.sizeBytes);
10137
- if (cached)
10138
- return cached;
10139
- }
10140
- try {
10141
- const fresh = await scanOneTranscript(meta);
10142
- if (!opts.noCache) {
10143
- writeCachedTranscriptResult(meta.transcriptPath, meta.mtimeMs, meta.sizeBytes, fresh);
10144
- }
10145
- return fresh;
10146
- } catch {
10147
- errors++;
10148
- return {
10149
- transcriptPath: meta.transcriptPath,
10150
- cli: meta.cli,
10151
- projectName: meta.projectName,
10152
- sessionId: meta.sessionId,
10153
- mtimeMs: meta.mtimeMs,
10154
- sizeBytes: meta.sizeBytes,
10155
- hitsByName: {},
10156
- examplesByName: {},
10157
- rangeByName: {}
10158
- };
10159
- }
10160
- });
10161
- const settled = await batchAll(tasks, TRANSCRIPT_CONCURRENCY);
10162
- const perTranscript = [];
10163
- for (const s of settled) {
10164
- if (s.status === "fulfilled")
10165
- perTranscript.push(s.value);
10166
- else
10167
- skipped++;
10168
- }
10169
- let results = aggregateResults(perTranscript, enabledBuiltins);
10170
- if (opts.policies?.length) {
10171
- const wanted = new Set(opts.policies.map(shortPolicyName));
10172
- results = results.filter((r) => wanted.has(shortPolicyName(r.name)));
10173
- }
10174
- const totalsHits = results.reduce((sum, r) => sum + r.hits, 0);
10175
- const projectsWithHits = new Set;
10176
- for (const t of perTranscript) {
10177
- if (Object.keys(t.hitsByName).length > 0)
10178
- projectsWithHits.add(t.projectName);
10179
- }
10180
- const auditResult = {
10181
- version: 1,
10182
- scannedAt: new Date(startedAt).toISOString(),
10183
- scope: {
10184
- cli: clis,
10185
- projects: opts.projects ?? "all",
10186
- since: opts.since ?? null
10187
- },
10188
- transcripts: {
10189
- scanned: allTranscripts.length,
10190
- skipped,
10191
- errors,
10192
- durationMs: Date.now() - startedAt
10193
- },
10194
- results,
10195
- totals: {
10196
- hits: totalsHits,
10197
- projectsWithHits: projectsWithHits.size
10198
- }
10199
- };
10200
- for (const count of results)
10201
- trackAuditPatternDetected(count);
10202
- const unenabledBuiltinNames = results.filter((r) => r.source === "builtin" && !r.enabledInConfig).map((r) => r.name);
10203
- trackAuditInstallCtaShown(unenabledBuiltinNames);
10204
- trackAuditCompleted(auditResult, outputMode);
10205
- return auditResult;
10206
- }
10207
- var TRANSCRIPT_CONCURRENCY = 8;
10208
- var init_audit = __esm(() => {
10209
- init_builtin_policies();
10210
- init_hooks_config();
10211
- init_types();
10212
- init_cli_adapters();
10213
- init_detectors();
10214
- init_cache();
10215
- init_replay();
10216
- init_telemetry();
10217
- init_types2();
10218
- });
9242
+ USAGE
9243
+ failproofai auth login Start the email + OTP login flow
9244
+ failproofai auth logout Remove ~/.failproofai/auth.json
9245
+ failproofai auth whoami Print the currently signed-in identity
9246
+ failproofai auth help Show this help (also: --help, -h)
10219
9247
 
10220
- // src/audit/report.ts
10221
- var exports_report = {};
10222
- __export(exports_report, {
10223
- formatText: () => formatText,
10224
- formatMarkdown: () => formatMarkdown,
10225
- formatJson: () => formatJson
10226
- });
10227
- function noColorEnabled() {
10228
- if (process.env.NO_COLOR && process.env.NO_COLOR !== "")
10229
- return true;
10230
- if (process.env.FORCE_COLOR === "0")
10231
- return true;
10232
- return false;
10233
- }
10234
- function stripAnsi(s) {
10235
- return s.replace(/\x1B\[[0-9;]*m/g, "");
10236
- }
10237
- function formatTimeAgo(iso) {
10238
- if (!iso)
10239
- return "—";
10240
- const ms = Date.now() - new Date(iso).getTime();
10241
- if (Number.isNaN(ms) || ms < 0)
10242
- return "—";
10243
- const m = Math.floor(ms / 60000);
10244
- if (m < 1)
10245
- return "just now";
10246
- if (m < 60)
10247
- return `${m}m ago`;
10248
- const h = Math.floor(m / 60);
10249
- if (h < 24)
10250
- return `${h}h ago`;
10251
- const d = Math.floor(h / 24);
10252
- if (d < 14)
10253
- return `${d}d ago`;
10254
- const w = Math.floor(d / 7);
10255
- if (w < 8)
10256
- return `${w}w ago`;
10257
- return `${Math.floor(d / 30)}mo ago`;
10258
- }
10259
- function getWidth() {
10260
- const cols = process.stdout.columns ?? 80;
10261
- return Math.max(60, Math.min(78, cols));
10262
- }
10263
- function topBorder(w) {
10264
- return `╭${"─".repeat(w - 2)}╮`;
10265
- }
10266
- function bottomBorder(w) {
10267
- return `╰${"─".repeat(w - 2)}╯`;
10268
- }
10269
- function boxLine(text, w) {
10270
- const inner = w - 4;
10271
- const visible = stripAnsi(text);
10272
- const pad = Math.max(0, inner - visible.length);
10273
- return `│ ${text}${" ".repeat(pad)} │`;
10274
- }
10275
- function divider(w) {
10276
- return "─".repeat(w);
10277
- }
10278
- function shortName2(name) {
10279
- const slash = name.indexOf("/");
10280
- return slash >= 0 ? name.slice(slash + 1) : name;
10281
- }
10282
- function sumHits(rows) {
10283
- return rows.reduce((acc, r) => acc + r.hits, 0);
10284
- }
10285
- function renderRow(r, opts) {
10286
- const out = [];
10287
- const sev = r.severity;
10288
- const titleColor = sev === "deny" ? ANSI.red : sev === "warn" ? ANSI.red : sev === "info" || sev === "instruct" ? ANSI.yellow : ANSI.cyan;
10289
- const countStr = String(r.hits).padStart(4);
10290
- out.push(` ${titleColor}${ANSI.bold}${countStr}×${ANSI.reset} ${r.displayTitle}`);
10291
- if (r.impact) {
10292
- out.push(` ${ANSI.dim}${r.impact}${ANSI.reset}`);
10293
- }
10294
- out.push(` ${ANSI.dim}Last seen ${formatTimeAgo(r.lastSeen)} · ${r.projects} project${r.projects === 1 ? "" : "s"}${ANSI.reset}`);
10295
- if (opts.showExamples && r.examples[0]) {
10296
- out.push(` ${ANSI.dim}Example: ${r.examples[0].example}${ANSI.reset}`);
10297
- }
10298
- if (r.installHint) {
10299
- const arrowColor = r.enabledInConfig ? ANSI.green : ANSI.cyan;
10300
- out.push(` ${arrowColor}›${ANSI.reset} ${r.installHint}`);
10301
- }
10302
- out.push("");
10303
- return out;
10304
- }
10305
- function formatText(result, opts = {}) {
10306
- const w = getWidth();
10307
- const limit = opts.limit ?? 20;
10308
- const showExamples = !!opts.showExamples;
10309
- const enabledRows = result.results.filter((r) => r.source === "builtin" && r.enabledInConfig);
10310
- const unenabledBuiltinRows = result.results.filter((r) => r.source === "builtin" && !r.enabledInConfig);
10311
- const detectorRows = result.results.filter((r) => r.source === "audit-detector");
10312
- const slippingRows = [...unenabledBuiltinRows, ...detectorRows].sort((a, b) => b.hits - a.hits);
10313
- const totalProtected = sumHits(enabledRows);
10314
- const totalSlipping = sumHits(slippingRows);
10315
- const totalHits = totalProtected + totalSlipping;
10316
- const sinceLabel = result.scope.since ? `the last ${result.scope.since}` : "all time";
10317
- const lines = [];
10318
- lines.push(`${ANSI.cyan}\uD83D\uDEE1 failproofai audit${ANSI.reset} ${ANSI.dim}[beta]${ANSI.reset} · ${sinceLabel}`);
10319
- lines.push(` ${ANSI.dim}${result.transcripts.scanned} sessions · ${result.totals.projectsWithHits} project${result.totals.projectsWithHits === 1 ? "" : "s"} with hits · scanned in ${(result.transcripts.durationMs / 1000).toFixed(1)}s${ANSI.reset}`);
10320
- lines.push("");
10321
- if (totalHits === 0) {
10322
- lines.push(topBorder(w));
10323
- lines.push(boxLine(`${ANSI.green}\uD83C\uDF89 Clean run!${ANSI.reset} Nothing matched your policies in this window.`, w));
10324
- lines.push(bottomBorder(w));
10325
- lines.push("");
10326
- return noColorEnabled() ? stripAnsi(lines.join(`
10327
- `)) : lines.join(`
10328
- `);
10329
- }
10330
- lines.push(topBorder(w));
10331
- lines.push(boxLine(`${ANSI.bold}Your agent did ${totalHits} wasteful or risky things in ${sinceLabel}.${ANSI.reset}`, w));
10332
- if (totalSlipping > 0) {
10333
- lines.push(boxLine(`${totalSlipping} of those would've been caught if more policies were on.`, w));
10334
- }
10335
- lines.push(bottomBorder(w));
10336
- lines.push("");
10337
- if (enabledRows.length > 0) {
10338
- lines.push(`${ANSI.green}✓ ALREADY PROTECTED${ANSI.reset} ${ANSI.dim}(${totalProtected} action${totalProtected === 1 ? "" : "s"} stopped by your current policies)${ANSI.reset}`);
10339
- lines.push("");
10340
- for (const row of enabledRows.slice(0, limit)) {
10341
- lines.push(...renderRow(row, { showExamples }));
10342
- }
10343
- if (enabledRows.length > limit) {
10344
- lines.push(` ${ANSI.dim}… ${enabledRows.length - limit} more (use --limit ${enabledRows.length})${ANSI.reset}`);
10345
- lines.push("");
10346
- }
10347
- }
10348
- if (slippingRows.length > 0) {
10349
- lines.push(`${ANSI.yellow}○ SLIPPING THROUGH${ANSI.reset} ${ANSI.dim}(${totalSlipping} action${totalSlipping === 1 ? "" : "s"} caught by audit, not blocked in real time)${ANSI.reset}`);
10350
- lines.push("");
10351
- for (const row of slippingRows.slice(0, limit)) {
10352
- lines.push(...renderRow(row, { showExamples }));
10353
- }
10354
- if (slippingRows.length > limit) {
10355
- lines.push(` ${ANSI.dim}… ${slippingRows.length - limit} more (use --limit ${slippingRows.length})${ANSI.reset}`);
10356
- lines.push("");
10357
- }
10358
- }
10359
- lines.push(divider(w));
10360
- if (unenabledBuiltinRows.length > 0) {
10361
- const installNames = unenabledBuiltinRows.map((r) => shortName2(r.name));
10362
- lines.push(`${ANSI.bold}NEXT${ANSI.reset} Enable the ${installNames.length} unenabled real-time polic${installNames.length === 1 ? "y" : "ies"} in one command:`);
10363
- lines.push("");
10364
- lines.push(` ${ANSI.cyan}failproofai policies --install ${installNames.join(" ")}${ANSI.reset}`);
10365
- lines.push("");
10366
- } else if (slippingRows.length > 0) {
10367
- lines.push(`${ANSI.bold}NEXT${ANSI.reset} Everything blockable is already enabled. Audit-only findings will show up in your next ${ANSI.cyan}failproofai audit${ANSI.reset}.`);
10368
- lines.push("");
10369
- } else {
10370
- lines.push(`${ANSI.bold}NEXT${ANSI.reset} ${ANSI.green}You have the relevant policies enabled. failproofai is blocking these in real time.${ANSI.reset}`);
10371
- lines.push("");
10372
- }
10373
- if (!opts.noReport) {
10374
- const reportPath = opts.reportPath ?? "./failproofai-audit.md";
10375
- lines.push(` \uD83D\uDCC4 Shareable report: ${ANSI.cyan}${reportPath}${ANSI.reset}`);
10376
- }
10377
- lines.push(` ⭐ Star us: ${ANSI.cyan}https://github.com/FailproofAI/failproofai${ANSI.reset}`);
10378
- lines.push("");
10379
- return noColorEnabled() ? stripAnsi(lines.join(`
10380
- `)) : lines.join(`
10381
- `);
10382
- }
10383
- function formatJson(result) {
10384
- return JSON.stringify(result, null, 2);
10385
- }
10386
- function escapeTableCell(s) {
10387
- return s.replace(/\\/g, "\\\\").replace(/\|/g, "\\|").replace(/[\r\n]+/g, " ");
10388
- }
10389
- function escapeBackticks(s) {
10390
- return s.replace(/`/g, "\\`");
10391
- }
10392
- function formatMarkdown(result) {
10393
- const out = [];
10394
- const enabledRows = result.results.filter((r) => r.source === "builtin" && r.enabledInConfig);
10395
- const unenabledBuiltinRows = result.results.filter((r) => r.source === "builtin" && !r.enabledInConfig);
10396
- const detectorRows = result.results.filter((r) => r.source === "audit-detector");
10397
- const slippingRows = [...unenabledBuiltinRows, ...detectorRows].sort((a, b) => b.hits - a.hits);
10398
- const totalProtected = sumHits(enabledRows);
10399
- const totalSlipping = sumHits(slippingRows);
10400
- const totalHits = totalProtected + totalSlipping;
10401
- const sinceLabel = result.scope.since ? `last ${result.scope.since}` : "all time";
10402
- out.push(`# Agent behavior audit · ${sinceLabel}`);
10403
- out.push("");
10404
- out.push("> _Generated by `failproofai audit` (**beta**) — flags and output may change between releases. Going live shortly._");
10405
- out.push("");
10406
- out.push(`*Generated ${result.scannedAt} — scanned ${result.transcripts.scanned} sessions across ${result.totals.projectsWithHits} project(s) in ${(result.transcripts.durationMs / 1000).toFixed(1)}s.*`);
10407
- out.push("");
10408
- out.push("## TL;DR");
10409
- out.push("");
10410
- if (totalHits === 0) {
10411
- out.push("Clean run — the AI coding agent didn't do anything `failproofai` catches in this window.");
10412
- } else {
10413
- out.push(`Over ${result.transcripts.scanned} sessions, my AI coding agent did **${totalHits} things \`failproofai\` would have stopped**: ` + `${totalProtected} were already blocked in real time by my current config; ` + `**${totalSlipping} slipped through** (would've been caught if more policies were on).`);
10414
- }
10415
- out.push("");
10416
- out.push("> [failproofai](https://github.com/FailproofAI/failproofai) is a hook-based policy engine for Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, and Gemini CLI. The `audit` command replays past agent sessions through every builtin policy to surface patterns that were (or could've been) stopped.");
10417
- out.push("");
10418
- if (totalHits === 0)
10419
- return out.join(`
10420
- `);
10421
- if (enabledRows.length > 0) {
10422
- out.push(`## ✓ Already protected (${totalProtected} action${totalProtected === 1 ? "" : "s"} stopped)`);
10423
- out.push("");
10424
- out.push("These are real-time policies you have on — `failproofai` blocked the agent before each action took effect.");
10425
- out.push("");
10426
- out.push("| Issue | Hits | Projects | Last seen | Policy |");
10427
- out.push("|---|---:|---:|---|---|");
10428
- for (const r of enabledRows) {
10429
- out.push(`| ${escapeTableCell(r.displayTitle)} | ${r.hits} | ${r.projects} | ${formatTimeAgo(r.lastSeen)} | \`${escapeTableCell(shortName2(r.name))}\` |`);
10430
- }
10431
- out.push("");
10432
- }
10433
- if (slippingRows.length > 0) {
10434
- out.push(`## ○ Slipping through (${totalSlipping} action${totalSlipping === 1 ? "" : "s"} caught by audit, not yet blocked)`);
10435
- out.push("");
10436
- out.push("Patterns the audit detected but real-time enforcement isn't on for. The CTA column shows how to fix each.");
10437
- out.push("");
10438
- out.push("| Issue | Hits | Projects | Last seen | Fix |");
10439
- out.push("|---|---:|---:|---|---|");
10440
- for (const r of slippingRows) {
10441
- const fix = r.source === "builtin" ? `\`failproofai policies --install ${shortName2(r.name)}\`` : "_audit-only_";
10442
- out.push(`| ${escapeTableCell(r.displayTitle)} | ${r.hits} | ${r.projects} | ${formatTimeAgo(r.lastSeen)} | ${fix} |`);
10443
- }
10444
- out.push("");
10445
- if (unenabledBuiltinRows.length > 0) {
10446
- out.push(`### Enable everything in one command`);
10447
- out.push("");
10448
- out.push("```bash");
10449
- out.push(`failproofai policies --install ${unenabledBuiltinRows.map((r) => shortName2(r.name)).join(" ")}`);
10450
- out.push("```");
10451
- out.push("");
10452
- }
10453
- }
10454
- const rowsWithExamples = [...enabledRows, ...slippingRows].filter((r) => r.examples.length > 0);
10455
- if (rowsWithExamples.length > 0) {
10456
- out.push("## Examples");
10457
- out.push("");
10458
- for (const r of rowsWithExamples) {
10459
- out.push(`### ${escapeBackticks(r.displayTitle)} (\`${escapeBackticks(shortName2(r.name))}\`)`);
10460
- out.push("");
10461
- if (r.impact) {
10462
- out.push(`> ${r.impact}`);
10463
- out.push("");
10464
- }
10465
- for (const e of r.examples) {
10466
- out.push(`- \`${escapeBackticks(e.example)}\` _(${e.cwd || "?"}, ${formatTimeAgo(e.timestamp)})_`);
10467
- }
10468
- out.push("");
10469
- }
10470
- }
10471
- out.push("---");
10472
- out.push("");
10473
- out.push("⭐ Star failproofai on GitHub: <https://github.com/FailproofAI/failproofai>");
10474
- out.push("");
10475
- return out.join(`
10476
- `);
10477
- }
10478
- var ANSI;
10479
- var init_report = __esm(() => {
10480
- ANSI = {
10481
- reset: "\x1B[0m",
10482
- dim: "\x1B[2m",
10483
- bold: "\x1B[1m",
10484
- red: "\x1B[31m",
10485
- yellow: "\x1B[33m",
10486
- green: "\x1B[32m",
10487
- cyan: "\x1B[36m",
10488
- magenta: "\x1B[35m"
9248
+ ENVIRONMENT
9249
+ FAILPROOF_API_URL Override the api-server base URL
9250
+ (default: https://api.befailproof.ai)
9251
+ FAILPROOFAI_AUTH_DIR Override where auth.json is stored
9252
+ (default: ~/.failproofai)
9253
+
9254
+ EXAMPLES
9255
+ failproofai auth login
9256
+ failproofai auth whoami
9257
+ failproofai auth logout
9258
+ `.trimStart();
9259
+ LEGACY_FLAG_TO_SUB = {
9260
+ "--login": "login",
9261
+ "--logout": "logout",
9262
+ "--whoami": "whoami"
10489
9263
  };
9264
+ SUBCOMMANDS = new Set(["login", "logout", "whoami", "help"]);
10490
9265
  });
10491
9266
 
10492
9267
  // src/hooks/manager.ts
10493
9268
  import { execSync as execSync6 } from "node:child_process";
10494
- import { resolve as resolve12, basename as basename5 } from "node:path";
9269
+ import { resolve as resolve12, basename as basename4 } from "node:path";
10495
9270
  import { homedir as homedir20, platform as platform2, arch as arch2, release as release2, hostname as hostname2 } from "node:os";
10496
9271
  function getSettingsPath2(scope, cwd) {
10497
9272
  return claudeCode.getSettingsPath(scope, cwd);
@@ -10729,7 +9504,7 @@ var exports_first_run_nudge = {};
10729
9504
  __export(exports_first_run_nudge, {
10730
9505
  maybeRunFirstRunNudge: () => maybeRunFirstRunNudge
10731
9506
  });
10732
- import * as readline3 from "node:readline";
9507
+ import * as readline4 from "node:readline";
10733
9508
  async function emit(event, props) {
10734
9509
  try {
10735
9510
  await trackHookEvent2(getInstanceId2(), event, props);
@@ -10752,7 +9527,7 @@ function clisLabel(detected) {
10752
9527
  }
10753
9528
  async function promptYesNo(stdin, stdout) {
10754
9529
  return new Promise((resolve13) => {
10755
- const rl = readline3.createInterface({ input: stdin, output: stdout });
9530
+ const rl = readline4.createInterface({ input: stdin, output: stdout });
10756
9531
  let settled = false;
10757
9532
  const finish = (answer) => {
10758
9533
  if (settled)
@@ -10888,14 +9663,14 @@ var init_parse_script_args = () => {};
10888
9663
 
10889
9664
  // scripts/install-diagnosis.mjs
10890
9665
  import { existsSync as existsSync14, readFileSync as readFileSync11, realpathSync } from "node:fs";
10891
- import { dirname as dirname5, resolve as resolve14 } from "node:path";
9666
+ import { dirname as dirname6, resolve as resolve14 } from "node:path";
10892
9667
  import { homedir as homedir21, platform as platform3 } from "node:os";
10893
9668
  import { spawnSync } from "node:child_process";
10894
9669
  function findPackageRoot(start) {
10895
9670
  try {
10896
9671
  let dir = realpathSync(start);
10897
9672
  if (existsSync14(dir) && !existsSync14(resolve14(dir, "package.json"))) {
10898
- dir = dirname5(dir);
9673
+ dir = dirname6(dir);
10899
9674
  }
10900
9675
  while (true) {
10901
9676
  const pkgPath = resolve14(dir, "package.json");
@@ -10906,7 +9681,7 @@ function findPackageRoot(start) {
10906
9681
  return dir;
10907
9682
  } catch {}
10908
9683
  }
10909
- const parent = dirname5(dir);
9684
+ const parent = dirname6(dir);
10910
9685
  if (parent === dir)
10911
9686
  return null;
10912
9687
  dir = parent;
@@ -11025,7 +9800,7 @@ __export(exports_launch, {
11025
9800
  });
11026
9801
  import { spawn } from "child_process";
11027
9802
  import { realpathSync as realpathSync2, existsSync as existsSync15 } from "node:fs";
11028
- import { resolve as resolve15, dirname as dirname6 } from "node:path";
9803
+ import { resolve as resolve15, dirname as dirname7 } from "node:path";
11029
9804
  import { fileURLToPath as fileURLToPath2 } from "node:url";
11030
9805
  function launch(mode) {
11031
9806
  const { loggingLevel, disableTelemetry, allowedDevOrigins, remainingArgs } = parseScriptArgs(process.argv.slice(2));
@@ -11045,7 +9820,7 @@ function launch(mode) {
11045
9820
  process.env.PORT = port;
11046
9821
  process.env.HOSTNAME = "0.0.0.0";
11047
9822
  cmd = "node";
11048
- const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve15(dirname6(realpathSync2(fileURLToPath2(import.meta.url))), "..");
9823
+ const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve15(dirname7(realpathSync2(fileURLToPath2(import.meta.url))), "..");
11049
9824
  const serverJsPath = resolve15(packageRoot, ".next/standalone/server.js");
11050
9825
  if (!existsSync15(serverJsPath)) {
11051
9826
  let shadowMessage = null;
@@ -11122,23 +9897,24 @@ var init_cli_error2 = __esm(() => {
11122
9897
 
11123
9898
  // bin/failproofai.mjs
11124
9899
  import { realpathSync as realpathSync3 } from "fs";
11125
- import { dirname as dirname7, resolve as resolve16 } from "path";
9900
+ import { dirname as dirname8, resolve as resolve16 } from "path";
11126
9901
  import { fileURLToPath as fileURLToPath3 } from "url";
11127
9902
  // package.json
11128
- var version = "0.0.11-beta.2";
9903
+ var version = "0.0.11-beta.4";
11129
9904
 
11130
9905
  // bin/failproofai.mjs
11131
9906
  if (!process.env.FAILPROOFAI_PACKAGE_ROOT) {
11132
- process.env.FAILPROOFAI_PACKAGE_ROOT = resolve16(dirname7(realpathSync3(fileURLToPath3(import.meta.url))), "..");
9907
+ process.env.FAILPROOFAI_PACKAGE_ROOT = resolve16(dirname8(realpathSync3(fileURLToPath3(import.meta.url))), "..");
11133
9908
  }
11134
9909
  if (!process.env.FAILPROOFAI_DIST_PATH) {
11135
- process.env.FAILPROOFAI_DIST_PATH = resolve16(dirname7(realpathSync3(fileURLToPath3(import.meta.url))), "..", "dist");
9910
+ process.env.FAILPROOFAI_DIST_PATH = resolve16(dirname8(realpathSync3(fileURLToPath3(import.meta.url))), "..", "dist");
11136
9911
  }
11137
9912
  var args = process.argv.slice(2);
11138
9913
  if (args[0] === "p")
11139
9914
  args[0] = "policies";
11140
9915
  var _telemetry;
11141
9916
  var lastSubcommand = null;
9917
+ var lastPolicyAction = null;
11142
9918
  async function track(name, props) {
11143
9919
  try {
11144
9920
  if (!_telemetry) {
@@ -11178,8 +9954,8 @@ if (hookIdx >= 0) {
11178
9954
  }
11179
9955
  }
11180
9956
  async function runCli() {
11181
- const SUBCOMMANDS = ["policies", "audit"];
11182
- if ((args.includes("--help") || args.includes("-h")) && !SUBCOMMANDS.includes(args[0])) {
9957
+ const SUBCOMMANDS2 = ["policies", "policy", "auth"];
9958
+ if ((args.includes("--help") || args.includes("-h")) && !SUBCOMMANDS2.includes(args[0])) {
11183
9959
  const extraArgs = args.filter((a) => a !== "--help" && a !== "-h");
11184
9960
  if (extraArgs.length > 0) {
11185
9961
  throw new CliError3(`Unexpected argument: ${extraArgs[0]}
@@ -11194,6 +9970,9 @@ USAGE
11194
9970
  COMMANDS
11195
9971
  (no args) Launch the policy dashboard
11196
9972
 
9973
+ policy add <name> Enable a single policy (see \`policy --help\`)
9974
+ policy remove <name> Disable a single policy
9975
+
11197
9976
  policies, p List all available policies and their status
11198
9977
  policies --install, -i Enable policies in agent CLI settings
11199
9978
  [names...] Specific policy names to enable
@@ -11216,24 +9995,11 @@ COMMANDS
11216
9995
 
11217
9996
  policies --help, -h Show this help for the policies command
11218
9997
 
11219
- audit (beta) Scan past agent CLI transcripts and count
11220
- "stupid behaviors" (env-var checks, force
11221
- pushes, redundant cd <cwd>, sleep loops,
11222
- etc.) per policy / audit detector.
11223
- Going live shortly \u2014 flags + output may
11224
- still change between beta releases.
11225
- --cli claude|codex|copilot|cursor|opencode|pi|gemini
11226
- Restrict to one or more CLIs (default: all).
11227
- --project <path> Restrict to one cwd (repeatable).
11228
- --since 7d|2026-04-01 Only sessions whose mtime is within window.
11229
- --policy <name> Restrict to one policy/detector (repeatable).
11230
- --limit N Top-N rows in the table (default 20).
11231
- --show-examples Include one example per row.
11232
- --report <path> Markdown report path (default ./failproofai-audit.md).
11233
- --no-report Skip writing the markdown file.
11234
- --json Print JSON to stdout instead of the table.
11235
- --no-cache Bypass the per-transcript cache.
11236
- audit --help, -h Show this help for the audit command
9998
+ auth Sign in / out of FailproofAI from the CLI.
9999
+ login Email + OTP flow; writes ~/.failproofai/auth.json
10000
+ logout Revoke this session and remove auth.json
10001
+ whoami Print the currently authenticated identity
10002
+ auth --help, -h Show this help for the auth command
11237
10003
 
11238
10004
  --version, -v Print version and exit
11239
10005
  --help, -h Show this help message
@@ -11272,7 +10038,7 @@ LINKS
11272
10038
  `.trimStart());
11273
10039
  process.exit(0);
11274
10040
  }
11275
- if ((args.includes("--version") || args.includes("-v")) && !SUBCOMMANDS.includes(args[0])) {
10041
+ if ((args.includes("--version") || args.includes("-v")) && !SUBCOMMANDS2.includes(args[0])) {
11276
10042
  const extraArgs = args.filter((a) => a !== "--version" && a !== "-v");
11277
10043
  if (extraArgs.length > 0) {
11278
10044
  throw new CliError3(`Unexpected argument: ${extraArgs[0]}
@@ -11481,148 +10247,122 @@ Run \`failproofai policies --help\` for usage.`);
11481
10247
  await track("cli_list_invoked", {});
11482
10248
  process.exit(0);
11483
10249
  }
11484
- if (args[0] === "audit") {
11485
- let collectMulti = function(flag, allowSet) {
11486
- const out = [];
11487
- const consumed = new Set;
11488
- for (let i = 0;i < subArgs.length; i++) {
11489
- if (subArgs[i] !== flag)
11490
- continue;
11491
- let seenForThisFlag = 0;
11492
- for (let j = i + 1;j < subArgs.length; j++) {
11493
- const v = subArgs[j];
11494
- if (v.startsWith("-"))
11495
- break;
11496
- if (allowSet && !allowSet.has(v))
11497
- break;
11498
- out.push(v);
11499
- consumed.add(j);
11500
- seenForThisFlag++;
11501
- }
11502
- consumed.add(i);
11503
- if (seenForThisFlag === 0) {
11504
- throw new CliError3(`Missing value(s) for ${flag}`);
11505
- }
11506
- }
11507
- return { values: out, consumed };
11508
- }, takeOne = function(flag) {
11509
- const i = subArgs.indexOf(flag);
11510
- if (i < 0)
11511
- return { value: undefined, consumed: new Set };
11512
- const v = subArgs[i + 1];
11513
- if (v === undefined || v.startsWith("-")) {
11514
- throw new CliError3(`Missing value for ${flag}`);
11515
- }
11516
- return { value: v, consumed: new Set([i, i + 1]) };
11517
- };
10250
+ if (args[0] === "auth") {
10251
+ lastSubcommand = "auth";
10252
+ const { runAuthCli: runAuthCli2 } = await Promise.resolve().then(() => (init_cli(), exports_cli));
10253
+ await runAuthCli2(args.slice(1));
10254
+ await track("cli_auth_invoked", { args_count: args.length - 1 });
10255
+ process.exit(process.exitCode ?? 0);
10256
+ }
10257
+ if (args[0] === "policy") {
10258
+ lastSubcommand = "policy";
11518
10259
  const subArgs = args.slice(1);
11519
- if (subArgs.includes("--help") || subArgs.includes("-h")) {
10260
+ if (subArgs.length === 0 || subArgs.includes("--help") || subArgs.includes("-h")) {
11520
10261
  console.log(`
11521
- failproofai audit (beta) \u2014 scan past agent transcripts for stupid behaviors
11522
-
11523
- NOTE: This command is in beta. Flags, output format, and the audit-only
11524
- detector catalog may change before the next stable cut. Going live shortly.
10262
+ failproofai policy \u2014 manage a single FailproofAI policy
11525
10263
 
11526
10264
  USAGE
11527
- failproofai audit [options]
10265
+ failproofai policy add <name> Enable one policy
10266
+ failproofai policy remove <name> Disable one policy
11528
10267
 
11529
10268
  OPTIONS
11530
10269
  --cli claude|codex|copilot|cursor|opencode|pi|gemini
11531
- Restrict to one or more CLIs (space-separated or repeated).
11532
- Default: scan all 7.
11533
- --project <path> Restrict to sessions whose cwd matches this path. Repeatable.
11534
- --since 7d|30d|2026-04-01 Only sessions whose mtime is within window.
11535
- --policy <name> Restrict to one policy/detector name. Repeatable.
11536
- --limit N Top-N rows in the table (default 20).
11537
- --show-examples Include one example command per row in the table.
11538
- --report <path> Markdown report path (default: ./failproofai-audit.md).
11539
- --no-report Skip writing the markdown report.
11540
- --json Print JSON to stdout instead of the table.
11541
- --no-cache Bypass the per-transcript result cache.
11542
- --help, -h Show this help
10270
+ Agent CLI(s) to apply to; space-separated or repeated.
10271
+ Omit to detect installed CLIs and prompt.
10272
+ --scope user|project|local Config scope (default: user)
10273
+ --beta Allow beta policies
11543
10274
 
11544
10275
  EXAMPLES
11545
- failproofai audit
11546
- failproofai audit --cli claude --since 30d
11547
- failproofai audit --policy protect-env-vars --policy block-force-push
11548
- failproofai audit --json > audit.json
11549
- failproofai audit --project /home/me/myrepo --show-examples
10276
+ failproofai policy add block-sudo
10277
+ failproofai policy add sanitize-api-keys --scope project
10278
+ failproofai policy add block-force-push --cli claude codex
10279
+ failproofai policy remove block-sudo
11550
10280
  `.trimStart());
11551
10281
  process.exit(0);
11552
10282
  }
10283
+ const action = subArgs[0];
10284
+ if (action !== "add" && action !== "remove") {
10285
+ throw new CliError3(`Unknown policy subcommand: ${action}
10286
+ Run \`failproofai policy --help\` for usage.`);
10287
+ }
10288
+ const rest = subArgs.slice(1);
10289
+ const scopeIdx = rest.indexOf("--scope");
10290
+ const scope = scopeIdx >= 0 ? rest[scopeIdx + 1] : "user";
10291
+ if (scopeIdx >= 0 && (!scope || scope.startsWith("-"))) {
10292
+ throw new CliError3("Missing value for --scope. Valid values: user, project, local");
10293
+ }
10294
+ const validScopes = action === "remove" ? ["user", "project", "local", "all"] : ["user", "project", "local"];
10295
+ if (scopeIdx >= 0 && !validScopes.includes(scope)) {
10296
+ throw new CliError3(`Invalid scope: ${scope}. Valid values: ${validScopes.join(", ")}`);
10297
+ }
11553
10298
  const VALID_CLIS = new Set(["claude", "codex", "copilot", "cursor", "opencode", "pi", "gemini"]);
11554
- const allConsumed = new Set;
11555
- const cliRes = collectMulti("--cli", VALID_CLIS);
11556
- cliRes.consumed.forEach((i) => allConsumed.add(i));
11557
- const projectRes = collectMulti("--project", null);
11558
- projectRes.consumed.forEach((i) => allConsumed.add(i));
11559
- const policyRes = collectMulti("--policy", null);
11560
- policyRes.consumed.forEach((i) => allConsumed.add(i));
11561
- const sinceRes = takeOne("--since");
11562
- sinceRes.consumed.forEach((i) => allConsumed.add(i));
11563
- const limitRes = takeOne("--limit");
11564
- limitRes.consumed.forEach((i) => allConsumed.add(i));
11565
- const reportRes = takeOne("--report");
11566
- reportRes.consumed.forEach((i) => allConsumed.add(i));
11567
- const showExamples = subArgs.includes("--show-examples");
11568
- if (showExamples)
11569
- allConsumed.add(subArgs.indexOf("--show-examples"));
11570
- const noReport = subArgs.includes("--no-report");
11571
- if (noReport)
11572
- allConsumed.add(subArgs.indexOf("--no-report"));
11573
- const jsonOut = subArgs.includes("--json");
11574
- if (jsonOut)
11575
- allConsumed.add(subArgs.indexOf("--json"));
11576
- const noCache = subArgs.includes("--no-cache");
11577
- if (noCache)
11578
- allConsumed.add(subArgs.indexOf("--no-cache"));
11579
- for (let i = 0;i < subArgs.length; i++) {
11580
- if (allConsumed.has(i))
11581
- continue;
11582
- const arg = subArgs[i];
11583
- throw new CliError3(`Unexpected argument: ${arg}
11584
- Run \`failproofai audit --help\` for usage.`);
11585
- }
11586
- let parsedLimit;
11587
- if (limitRes.value !== undefined) {
11588
- parsedLimit = parseInt(limitRes.value, 10);
11589
- if (!Number.isInteger(parsedLimit) || parsedLimit <= 0) {
11590
- throw new CliError3(`Invalid value for --limit: "${limitRes.value}". Use a positive integer.`);
11591
- }
11592
- }
11593
- const opts = {
11594
- clis: cliRes.values.length > 0 ? cliRes.values : undefined,
11595
- projects: projectRes.values.length > 0 ? projectRes.values : undefined,
11596
- policies: policyRes.values.length > 0 ? policyRes.values : undefined,
11597
- since: sinceRes.value,
11598
- limit: parsedLimit,
11599
- showExamples,
11600
- reportPath: reportRes.value ?? "./failproofai-audit.md",
11601
- noReport: noReport || jsonOut,
11602
- json: jsonOut,
11603
- noCache
11604
- };
11605
- if (jsonOut && reportRes.value)
11606
- opts.noReport = false;
11607
- const { runAudit: runAudit2 } = await Promise.resolve().then(() => (init_audit(), exports_audit));
11608
- const { formatText: formatText2, formatJson: formatJson2, formatMarkdown: formatMarkdown2 } = await Promise.resolve().then(() => (init_report(), exports_report));
11609
- const result = await runAudit2(opts);
11610
- if (jsonOut) {
11611
- process.stdout.write(formatJson2(result) + `
11612
- `);
10299
+ const cliFlagValues = [];
10300
+ const cliConsumedIdxs = new Set;
10301
+ const cliFlagIdxs = rest.map((a, i) => a === "--cli" ? i : -1).filter((i) => i >= 0);
10302
+ for (const idx of cliFlagIdxs) {
10303
+ let consumed = 0;
10304
+ for (let j = idx + 1;j < rest.length; j++) {
10305
+ const v = rest[j];
10306
+ if (v.startsWith("-"))
10307
+ break;
10308
+ if (!VALID_CLIS.has(v))
10309
+ break;
10310
+ cliFlagValues.push(v);
10311
+ cliConsumedIdxs.add(j);
10312
+ consumed++;
10313
+ }
10314
+ if (consumed === 0) {
10315
+ throw new CliError3("Missing value(s) for --cli. Usage: --cli claude codex copilot cursor opencode pi gemini (or any subset)");
10316
+ }
10317
+ }
10318
+ const includeBeta = rest.includes("--beta");
10319
+ const knownFlags2 = new Set(["--scope", "--cli", "--beta"]);
10320
+ const unknownFlag2 = rest.find((a) => a.startsWith("-") && !knownFlags2.has(a));
10321
+ if (unknownFlag2) {
10322
+ throw new CliError3(`Unknown flag: ${unknownFlag2}
10323
+ Run \`failproofai policy --help\` for usage.`);
10324
+ }
10325
+ const consumedIdxs = new Set;
10326
+ if (scopeIdx >= 0)
10327
+ consumedIdxs.add(scopeIdx + 1);
10328
+ for (const i of cliConsumedIdxs)
10329
+ consumedIdxs.add(i);
10330
+ const positional = rest.filter((a, idx) => !a.startsWith("-") && !consumedIdxs.has(idx));
10331
+ if (positional.length === 0) {
10332
+ throw new CliError3(`Missing policy name.
10333
+ Usage: failproofai policy ${action} <name>
10334
+ Run \`failproofai policies\` to see available names.`);
10335
+ }
10336
+ if (positional.length > 1) {
10337
+ throw new CliError3(`\`policy ${action}\` takes exactly one policy name (got ${positional.length}).
10338
+ For multiple policies use \`failproofai policies --${action === "add" ? "install" : "uninstall"} ${positional.join(" ")}\`.`);
10339
+ }
10340
+ const policyName = positional[0];
10341
+ const { resolveTargetClis: resolveTargetClis2 } = await Promise.resolve().then(() => (init_install_prompt2(), exports_install_prompt));
10342
+ const cli = await resolveTargetClis2(cliFlagValues.length > 0 ? cliFlagValues : undefined, action === "add" ? "install" : "uninstall");
10343
+ lastPolicyAction = action;
10344
+ if (action === "add") {
10345
+ const { installHooks: installHooks3 } = await Promise.resolve().then(() => (init_manager(), exports_manager));
10346
+ await installHooks3([policyName], scope, undefined, includeBeta, undefined, undefined, false, cli);
10347
+ await track("cli_policy_add_success", {
10348
+ scope,
10349
+ cli,
10350
+ cli_count: cli.length,
10351
+ policy_name: policyName,
10352
+ include_beta: includeBeta
10353
+ });
11613
10354
  } else {
11614
- process.stdout.write(formatText2(result, opts));
11615
- }
11616
- if (!opts.noReport) {
11617
- const { writeFileSync: writeFileSync6 } = await import("fs");
11618
- const { resolve: resolve17 } = await import("path");
11619
- const reportPath = resolve17(opts.reportPath);
11620
- writeFileSync6(reportPath, formatMarkdown2(result), "utf-8");
11621
- if (!jsonOut)
11622
- process.stdout.write(`
11623
- Report written: ${reportPath}
11624
- `);
10355
+ const { removeHooks: removeHooks2 } = await Promise.resolve().then(() => (init_manager(), exports_manager));
10356
+ await removeHooks2([policyName], scope, undefined, { betaOnly: false, removeCustomHooks: false, cli });
10357
+ await track("cli_policy_remove_success", {
10358
+ scope,
10359
+ cli,
10360
+ cli_count: cli.length,
10361
+ policy_name: policyName,
10362
+ beta_only: false
10363
+ });
11625
10364
  }
10365
+ lastPolicyAction = null;
11626
10366
  process.exit(0);
11627
10367
  }
11628
10368
  const knownFlags = ["--version", "-v", "--help", "-h", "--hook"];
@@ -11636,7 +10376,7 @@ Report written: ${reportPath}
11636
10376
  dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
11637
10377
  return dp[m][n];
11638
10378
  };
11639
- const primary = ["--version", "--help", "--hook", "policies", "audit"];
10379
+ const primary = ["--version", "--help", "--hook", "policies", "policy", "auth"];
11640
10380
  const closest = primary.reduce((best, flag) => {
11641
10381
  const dist = levenshtein(unknownFlag, flag);
11642
10382
  return dist < best.dist ? { flag, dist } : best;
@@ -11645,7 +10385,7 @@ Report written: ${reportPath}
11645
10385
  Did you mean: ${closest.flag}?
11646
10386
  Run \`failproofai --help\` for usage details.`);
11647
10387
  }
11648
- const unknownSubcommand = args.find((a) => !a.startsWith("-") && !SUBCOMMANDS.includes(a));
10388
+ const unknownSubcommand = args.find((a) => !a.startsWith("-") && !SUBCOMMANDS2.includes(a));
11649
10389
  if (unknownSubcommand) {
11650
10390
  throw new CliError3(`Unknown command: ${unknownSubcommand}
11651
10391
  Did you mean: failproofai policies?
@@ -11669,6 +10409,11 @@ try {
11669
10409
  await track("cli_install_failure", { error_type: "cli_error", exit_code: err.exitCode });
11670
10410
  } else if (lastSubcommand === "uninstall") {
11671
10411
  await track("cli_uninstall_failure", { error_type: "cli_error", exit_code: err.exitCode });
10412
+ } else if (lastSubcommand === "policy" && lastPolicyAction) {
10413
+ await track(`cli_policy_${lastPolicyAction}_failure`, {
10414
+ error_type: "cli_error",
10415
+ exit_code: err.exitCode
10416
+ });
11672
10417
  } else {
11673
10418
  await track("cli_parse_error", {
11674
10419
  subcommand: lastSubcommand ?? (args[0] ?? null),
@@ -11683,6 +10428,10 @@ try {
11683
10428
  await track("cli_install_failure", { error_type: err instanceof Error ? err.name : "unknown" });
11684
10429
  } else if (lastSubcommand === "uninstall") {
11685
10430
  await track("cli_uninstall_failure", { error_type: err instanceof Error ? err.name : "unknown" });
10431
+ } else if (lastSubcommand === "policy" && lastPolicyAction) {
10432
+ await track(`cli_policy_${lastPolicyAction}_failure`, {
10433
+ error_type: err instanceof Error ? err.name : "unknown"
10434
+ });
11686
10435
  } else {
11687
10436
  await track("cli_unexpected_error", {
11688
10437
  subcommand: lastSubcommand ?? (args[0] ?? null),