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.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-path-routes-manifest.json +8 -1
- package/.next/standalone/.next/build-manifest.json +10 -10
- package/.next/standalone/.next/prerender-manifest.json +3 -32
- package/.next/standalone/.next/required-server-files.json +2 -1
- package/.next/standalone/.next/routes-manifest.json +45 -3
- package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +7 -7
- package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js +6 -6
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +7 -7
- package/.next/standalone/.next/server/app/_not-found/page/next-font-manifest.json +2 -6
- package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js +12 -13
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +16 -16
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +16 -16
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/audit/run/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/audit/run/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/audit/run/route.js +8 -0
- package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/audit/run/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/audit/status/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/audit/status/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/audit/status/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/audit/status/route.js +6 -0
- package/.next/standalone/.next/server/app/api/audit/status/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/audit/status/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/auth/login-request/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/auth/login-request/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/auth/login-request/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js +6 -0
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/auth/login-request/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/auth/login-verify/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/auth/login-verify/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/auth/login-verify/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +7 -0
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/auth/login-verify/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/auth/logout/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/auth/logout/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/auth/logout/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/auth/logout/route.js +7 -0
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/auth/logout/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/auth/reminder/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/auth/reminder/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/auth/reminder/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js +7 -0
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/auth/reminder/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/auth/status/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/auth/status/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/auth/status/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/auth/status/route.js +7 -0
- package/.next/standalone/.next/server/app/api/auth/status/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/auth/status/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js +3 -3
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/audit/page/build-manifest.json +18 -0
- package/.next/standalone/.next/server/app/audit/page/next-font-manifest.json +6 -0
- package/.next/standalone/.next/server/app/audit/page/react-loadable-manifest.json +1 -0
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +29 -0
- package/.next/standalone/.next/server/app/audit/page.js +17 -0
- package/.next/standalone/.next/server/app/audit/page.js.map +5 -0
- package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +16 -17
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +16 -17
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -3
- package/.next/standalone/.next/server/app/page/build-manifest.json +7 -7
- package/.next/standalone/.next/server/app/page/next-font-manifest.json +2 -6
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js +14 -15
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/policies/page/build-manifest.json +7 -7
- package/.next/standalone/.next/server/app/policies/page/next-font-manifest.json +2 -6
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
- package/.next/standalone/.next/server/app/policies/page.js +16 -16
- package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +7 -7
- package/.next/standalone/.next/server/app/project/[name]/page/next-font-manifest.json +2 -6
- package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js +16 -17
- package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +7 -7
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/next-font-manifest.json +2 -6
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +19 -20
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page/build-manifest.json +7 -7
- package/.next/standalone/.next/server/app/projects/page/next-font-manifest.json +2 -6
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js +15 -16
- package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app-paths-manifest.json +8 -1
- package/.next/standalone/.next/server/chunks/[externals]__14odj07._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[externals]__0z0j--b._.js → [externals]__1nl3dvw._.js} +1 -1
- package/.next/standalone/.next/server/chunks/{[externals]__0-p9.k~._.js → [externals]__1s61mel._.js} +1 -1
- package/.next/standalone/.next/server/chunks/{[externals]_node_os_06ur78j._.js → [externals]_node_os_0by37l-._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__07tgnzi._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0kjo7d_._.js → [root-of-the-server]__0_0xu5z._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cag8qd._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0z-180.._.js → [root-of-the-server]__0cycwg6._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__08px0ym._.js → [root-of-the-server]__0f7mikp._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0oeun7z._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q-v9z2._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0rv7m0k._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0g48iv.._.js → [root-of-the-server]__0sb_5m8._.js} +3 -3
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0j8-xkl._.js → [root-of-the-server]__0xuaoik._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__12pit4m._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__13h8pzr._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__13ra2jq._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0d_ob4n._.js → [root-of-the-server]__1_mqemn._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1b9z5-i._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0vlhtkc._.js → [root-of-the-server]__1hgv_75._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ixjiy8._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0wu7fr7._.js → [root-of-the-server]__1jm9fw6._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1legmza._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0fwb7ao._.js → [root-of-the-server]__1m2_4t0._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0yfq1yr._.js → [root-of-the-server]__1mhmdzs._.js} +1 -1
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0zso~62._.js → [root-of-the-server]__1ou2ehh._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1qxztj-._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1rhmvod._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0.~nmr9._.js → [root-of-the-server]__1w9zl9-._.js} +1 -1
- package/.next/standalone/.next/server/chunks/{_0ebx_lc._.js → _0p53ge1._.js} +2 -2
- package/.next/standalone/.next/server/chunks/_1-1804f._.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_audit_run_route_actions_1qgp9io.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_audit_status_route_actions_1f7pjof.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_auth_login-request_route_actions_1c49co0.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_auth_login-verify_route_actions_1r3slzk.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_auth_logout_route_actions_0regwyr.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_auth_reminder_route_actions_1kjgxf8.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_auth_status_route_actions_1aho9zu.js +3 -0
- 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
- package/.next/standalone/.next/server/chunks/{lib_logger_ts_047tt9f._.js → lib_logger_ts_07e65t5._.js} +1 -1
- package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +23 -0
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_01r25oi._.js +3 -0
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_09z9-p7._.js +3 -0
- package/.next/standalone/.next/server/chunks/{package_json_[json]_cjs_0z7w.hh._.js → package_json_[json]_cjs_1nxcc4v._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[externals]__12dv.x0._.js → [externals]__1_g_b3t._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[externals]_node_async_hooks_0v0ln8c._.js → [externals]_node_async_hooks_1gjz99j._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0ts150~._.js → [root-of-the-server]__0-wdurj._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__00jkjmt._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013du6r._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__06f-yix._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0989_dx._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e85wxv._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0gfxvb1._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h12me5._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0l13qf2._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1-scthx._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11rtg6s._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__14dd6h8._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1cd25c7._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0t5l7a5._.js → [root-of-the-server]__1d8omgc._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0tcyn68._.js → [root-of-the-server]__1dky4g0._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__098zro9._.js → [root-of-the-server]__1fax1sl._.js} +4 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1hlrq6y._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ihxdo5._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1mt35_w._.js +221 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0-wn51s._.js → [root-of-the-server]__1pcxxwg._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1usf8v2._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1vvfde2._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__212nf49._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{_03d7qyt._.js → _05whahf._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_11_p9y8._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{_0xb8ngh._.js → _1kje4fm._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_0zx~s__._.js → _1p0-leb._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{app_04qfs8z._.js → app_087bt9w._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{app_0uosk1e._.js → app_1fvisnp._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{app_13f0ohr._.js → app_209u41o._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +43 -0
- package/.next/standalone/.next/server/chunks/ssr/app_audit_loading_tsx_1j1kc6j._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{app_error_tsx_11t4ysq._.js → app_error_tsx_1zds1ns._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{app_global-error_tsx_0m9qisk._.js → app_global-error_tsx_113y3za._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{app_global-error_tsx_0xerkr6._.js → app_global-error_tsx_1kp6l3x._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +8 -0
- 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
- package/.next/standalone/.next/server/chunks/ssr/{app_project_[name]_loading_tsx_03g9xy0._.js → app_project_[name]_loading_tsx_05-l4uf._.js} +1 -1
- 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
- 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
- package/.next/standalone/.next/server/chunks/ssr/app_projects_loading_tsx_20-3u8b._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{lib_codex-projects_ts_0eosib~._.js → lib_codex-projects_ts_0pqlw37._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{lib_copilot-projects_ts_0r8xkn8._.js → lib_copilot-projects_ts_19wl7tp._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{lib_cursor-projects_ts_0qt1scg._.js → lib_cursor-projects_ts_18-iwyk._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{lib_gemini-projects_ts_0sl~yqr._.js → lib_gemini-projects_ts_1c7bgx-._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{lib_opencode-projects_ts_0op9gyp._.js → lib_opencode-projects_ts_15bjxkm._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{lib_pi-projects_ts_103tsh1._.js → lib_pi-projects_ts_1wikofb._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{lib_utils_ts_068jk73._.js → lib_utils_ts_0az0sfq._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_1ynf7el._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/node_modules_html2canvas_dist_html2canvas_esm_0hmsdod.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/node_modules_html2canvas_dist_html2canvas_esm_1n-0xws.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{node_modules_next_0rd0oc-._.js → node_modules_next_1a1kch7._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules_next_dist_0h9llsw._.js → node_modules_next_dist_0uboya6._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules_next_dist_11dij6w._.js → node_modules_next_dist_1d_onnt._.js} +3 -3
- 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
- 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
- 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
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0-uvagv.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_03c7gi5.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_09p-8om.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0v-kfiu.js +4 -0
- 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
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_1806lsc.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_1j6dd-e.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_1sa65r-.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_11bnuzn._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1ezd2jf._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1tnuifj._.js +5 -0
- package/.next/standalone/.next/server/functions-config-manifest.json +3 -0
- package/.next/standalone/.next/server/instrumentation.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +10 -10
- package/.next/standalone/.next/server/middleware.js +2 -2
- package/.next/standalone/.next/server/next-font-manifest.js +1 -1
- package/.next/standalone/.next/server/next-font-manifest.json +2 -21
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +27 -9
- package/.next/standalone/.next/static/chunks/{07uz2g0_38qia.js → 03fmihek9n986.js} +1 -1
- package/.next/standalone/.next/static/chunks/09ueq8s1as8xs.css +2 -0
- package/.next/standalone/.next/static/chunks/0fkntmojmibda.js +6 -0
- package/.next/standalone/.next/static/chunks/{11w14gnqzprir.js → 0nbmu4_n1j2-c.js} +1 -1
- package/.next/standalone/.next/static/chunks/0qassxjx1ef04.js +1 -0
- package/.next/standalone/.next/static/chunks/0zbxssxh53n-3.js +1 -0
- package/.next/standalone/.next/static/chunks/13f1kmjea-0md.js +2 -0
- package/.next/standalone/.next/static/chunks/1btx2c49fk9xt.css +1 -0
- package/.next/standalone/.next/static/chunks/1bxdpd036n3l9.js +41 -0
- package/.next/standalone/.next/static/chunks/{0bke.~atnsbeb.js → 1e0o-6kjfnwzh.js} +1 -1
- package/.next/standalone/.next/static/chunks/20b5bz43so-1k.js +1 -0
- package/.next/standalone/.next/static/chunks/2zjavpea8glet.js +1 -0
- package/.next/standalone/.next/static/chunks/{0d3shmwh5_nmn.js → 33u59vf_8xpd-.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0dvhi-prcsh3~.js → 36l507r2mbf5h.js} +1 -1
- package/.next/standalone/.next/static/chunks/3gti1qdk5epqn.js +1 -0
- package/.next/standalone/.next/static/chunks/{17mubwtqwijpu.js → 3w8d8k_dca5rp.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0bv1oyxspkpkb.js → 3y3l184vijlfg.js} +1 -1
- package/.next/standalone/.next/static/chunks/41jjdgqqpl7em.js +1 -0
- package/.next/standalone/.next/static/chunks/{turbopack-0nh.aopesgj~5.js → turbopack-00qy7zfa7m--m.js} +1 -1
- package/.next/standalone/SECURITY.md +73 -0
- package/.next/standalone/app/actions/get-audit-result.ts +24 -0
- package/.next/standalone/app/api/audit/_state.ts +72 -0
- package/.next/standalone/app/api/audit/run/route.ts +89 -0
- package/.next/standalone/app/api/audit/status/route.ts +23 -0
- package/.next/standalone/app/api/auth/login-request/route.ts +91 -0
- package/.next/standalone/app/api/auth/login-verify/route.ts +98 -0
- package/.next/standalone/app/api/auth/logout/route.ts +48 -0
- package/.next/standalone/app/api/auth/reminder/route.ts +213 -0
- package/.next/standalone/app/api/auth/status/route.ts +42 -0
- package/.next/standalone/app/audit/_components/audit-dashboard.tsx +364 -0
- package/.next/standalone/app/audit/_components/auth-dialog.tsx +401 -0
- package/.next/standalone/app/audit/_components/empty-state.tsx +146 -0
- package/.next/standalone/app/audit/_components/findings-section.tsx +135 -0
- package/.next/standalone/app/audit/_components/identity-section.tsx +126 -0
- package/.next/standalone/app/audit/_components/policies-section.tsx +194 -0
- package/.next/standalone/app/audit/_components/report-footer.tsx +35 -0
- package/.next/standalone/app/audit/_components/rerun-button.tsx +81 -0
- package/.next/standalone/app/audit/_components/return-section.tsx +428 -0
- package/.next/standalone/app/audit/_components/run-progress.tsx +120 -0
- package/.next/standalone/app/audit/_components/score-section.tsx +179 -0
- package/.next/standalone/app/audit/_components/share-dock.tsx +265 -0
- package/.next/standalone/app/audit/_components/share-templates.ts +67 -0
- package/.next/standalone/app/audit/_components/show-off-cta.tsx +135 -0
- package/.next/standalone/app/audit/_components/sigil.tsx +93 -0
- package/.next/standalone/app/audit/_components/strengths-section.tsx +57 -0
- package/.next/standalone/app/audit/audit-styles.css +2066 -0
- package/.next/standalone/app/audit/loading.tsx +24 -0
- package/.next/standalone/app/audit/page.tsx +53 -0
- package/.next/standalone/app/globals.css +570 -137
- package/.next/standalone/app/layout.tsx +16 -9
- package/.next/standalone/app/policies/hooks-client.tsx +223 -129
- package/.next/standalone/app/project/[name]/page.tsx +89 -39
- package/.next/standalone/app/projects/loading.tsx +30 -8
- package/.next/standalone/app/projects/page.tsx +76 -18
- package/.next/standalone/assets/audit/Audit Report.html +22 -0
- package/.next/standalone/assets/audit/Show Off Your Agent.html +22 -0
- package/.next/standalone/assets/audit/archetypes.jsx +277 -0
- package/.next/standalone/assets/audit/assets/fonts/bitcount-prop-single.woff2 +0 -0
- package/.next/standalone/assets/audit/audit.jsx +825 -0
- package/.next/standalone/assets/audit/poster-styles.css +424 -0
- package/.next/standalone/assets/audit/poster.jsx +247 -0
- package/.next/standalone/assets/audit/screenshots/poster-optimist.png +0 -0
- package/.next/standalone/assets/audit/screenshots/poster-scrolled.png +0 -0
- package/.next/standalone/assets/audit/styles.css +1225 -0
- package/.next/standalone/assets/audit/tweaks-panel.jsx +425 -0
- package/.next/standalone/assets/logos/company/icon.svg +1 -0
- package/.next/standalone/assets/logos/company/logo.svg +1 -0
- package/.next/standalone/components/navbar.tsx +154 -65
- package/.next/standalone/components/reach-developers.tsx +37 -9
- package/.next/standalone/lib/atomic-write.ts +67 -0
- package/.next/standalone/lib/auth/api-server-client.ts +281 -0
- package/.next/standalone/lib/auth/auth-store.ts +250 -0
- package/.next/standalone/lib/client-telemetry.ts +2 -0
- package/.next/standalone/lib/fetch-with-timeout.ts +42 -0
- package/.next/standalone/lib/share-card.ts +144 -0
- package/.next/standalone/lib/telemetry.ts +12 -7
- package/.next/standalone/node_modules/@next/env/package.json +1 -1
- package/.next/standalone/node_modules/next/dist/build/swc/index.js +1 -1
- package/.next/standalone/node_modules/next/dist/client/dev/debug-channel.js +102 -2
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js +11 -11
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js +13 -13
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-route-turbo.runtime.prod.js +2 -2
- package/.next/standalone/node_modules/next/dist/compiled/next-server/pages-turbo.runtime.prod.js +1 -1
- package/.next/standalone/node_modules/next/dist/lib/patch-incorrect-lockfile.js +3 -3
- package/.next/standalone/node_modules/next/dist/server/app-render/action-handler.js +18 -8
- package/.next/standalone/node_modules/next/dist/server/config-schema.js +1 -0
- package/.next/standalone/node_modules/next/dist/server/config.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-turbopack.js +2 -2
- package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-webpack.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/lib/app-info-log.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/lib/encode-cache-tag.js +45 -0
- package/.next/standalone/node_modules/next/dist/server/lib/implicit-tags.js +6 -3
- package/.next/standalone/node_modules/next/dist/server/lib/patch-fetch.js +5 -1
- package/.next/standalone/node_modules/next/dist/server/lib/start-server.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/web/spec-extension/revalidate.js +4 -3
- package/.next/standalone/node_modules/next/dist/server/web/spec-extension/unstable-cache.js +6 -2
- package/.next/standalone/node_modules/next/dist/shared/lib/errors/canary-only-config-error.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/anonymous-meta.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/events/swc-load-failure.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/events/version.js +2 -2
- package/.next/standalone/node_modules/next/package.json +15 -15
- package/.next/standalone/node_modules/react/cjs/react.development.js +1 -1
- package/.next/standalone/node_modules/react/cjs/react.production.js +1 -1
- package/.next/standalone/node_modules/react/package.json +1 -1
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.browser.production.js +1 -1
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.node.production.js +1 -1
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.browser.production.js +3 -3
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.edge.production.js +3 -3
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.node.production.js +3 -3
- package/.next/standalone/node_modules/react-dom/cjs/react-dom.production.js +1 -1
- package/.next/standalone/node_modules/react-dom/package.json +2 -2
- package/.next/standalone/osv-scanner.toml +17 -0
- package/.next/standalone/package.json +8 -3
- package/.next/standalone/public/audit/fonts/bitcount-prop-single.woff2 +0 -0
- package/.next/standalone/public/icon.svg +1 -0
- package/.next/standalone/public/logo.svg +1 -0
- package/.next/standalone/server.js +1 -1
- package/.next/standalone/templates/bitcount-font/README.md +42 -0
- package/.next/standalone/templates/bitcount-font/bitcount-prop-single.woff2 +0 -0
- package/.next/standalone/templates/bitcount-font/bitcount.css +49 -0
- package/.next/standalone/templates/bitcount-font/fonts.ts.example +23 -0
- package/README.md +2 -1
- package/bin/failproofai.mjs +165 -144
- package/dist/cli.mjs +607 -1858
- package/lib/atomic-write.ts +67 -0
- package/lib/auth/api-server-client.ts +281 -0
- package/lib/auth/auth-store.ts +250 -0
- package/lib/client-telemetry.ts +2 -0
- package/lib/fetch-with-timeout.ts +42 -0
- package/lib/share-card.ts +144 -0
- package/lib/telemetry.ts +12 -7
- package/package.json +8 -3
- package/scripts/install-telemetry.mjs +4 -0
- package/src/audit/archetypes.ts +924 -0
- package/src/audit/cache.ts +21 -2
- package/src/audit/dashboard-cache.ts +111 -0
- package/src/audit/features.ts +268 -0
- package/src/audit/findings.ts +298 -0
- package/src/audit/index.ts +39 -21
- package/src/audit/replay.ts +29 -3
- package/src/audit/scoring.ts +174 -0
- package/src/audit/strengths.ts +138 -0
- package/src/audit/types.ts +24 -1
- package/src/auth/cli.ts +359 -0
- package/src/hooks/builtin-policies.ts +2 -1
- package/src/hooks/hook-telemetry.ts +2 -2
- package/src/hooks/policy-registry.ts +20 -0
- package/src/posthog-key.ts +9 -0
- package/.next/standalone/.next/server/app/icon.png/route/app-paths-manifest.json +0 -3
- package/.next/standalone/.next/server/app/icon.png/route.js +0 -7
- package/.next/standalone/.next/server/app/icon.png/route.js.nft.json +0 -1
- package/.next/standalone/.next/server/app/icon.png.body +0 -0
- package/.next/standalone/.next/server/app/icon.png.meta +0 -1
- package/.next/standalone/.next/server/chunks/[externals]_next_dist_0sqmaqd._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__06.arfm._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0__i0h0._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0fe7_q_._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0fw.e.h._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0pxn0e1._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0xv0jh2._.js +0 -3
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_icon_png_route_actions_12.gv.r.js +0 -3
- package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0bdfoky.js +0 -3
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_05pz9._._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01as125._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0370~qj._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__09v.ljl._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0agrcb8._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0b7hkr~._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ehh6vp._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g8l0tu._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0j4l6hl._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0k5n2kz._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0lp08ll._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n0yaqw._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0o21f.o._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0t8juvy._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0uylufv._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ymlddl._.js +0 -223
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0~03grs._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/app_0cdqd9w._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_0q-m0y-._.js +0 -8
- package/.next/standalone/.next/server/chunks/ssr/app_projects_loading_tsx_13veom4._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/node_modules_0ttbz1~._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_06u0kr8._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0a_7sdg.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0ef3uwk.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0pbja1x.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0r6o0i2.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_11y81~_.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_12or2kf.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_0mebn66._.js +0 -3
- package/.next/standalone/.next/static/chunks/07kpqoo7kuckx.js +0 -6
- package/.next/standalone/.next/static/chunks/0azb~vy9ds_uy.js +0 -1
- package/.next/standalone/.next/static/chunks/0f5p9plm.aqlp.css +0 -2
- package/.next/standalone/.next/static/chunks/0ffvlbgzgnlw7.js +0 -2
- package/.next/standalone/.next/static/chunks/0spktq7xqab9h.js +0 -1
- package/.next/standalone/.next/static/chunks/118q3uljozd5z.js +0 -4
- package/.next/standalone/.next/static/chunks/12pt~2f.c1sha.js +0 -1
- package/.next/standalone/.next/static/media/4fa387ec64143e14-s.0.qu-9752pffj.woff2 +0 -0
- package/.next/standalone/.next/static/media/5ce348bf30bf5439-s.0ee55_hj9qcer.woff2 +0 -0
- package/.next/standalone/.next/static/media/6306c77e7c8268e4-s.0mao5jbfbduzp.woff2 +0 -0
- package/.next/standalone/.next/static/media/797e433ab948586e-s.p.09zddjkbdep5a.woff2 +0 -0
- package/.next/standalone/.next/static/media/7d817b4c03b0c5f1-s.0uzt.a6d44yda.woff2 +0 -0
- package/.next/standalone/.next/static/media/bbc41e54d2fcbd21-s.0mvwgmnhv29no.woff2 +0 -0
- package/.next/standalone/.next/static/media/icon.0a.gigb3_x5pd.png +0 -0
- package/.next/standalone/app/icon.png +0 -0
- package/src/audit/telemetry.ts +0 -113
- /package/.next/standalone/.next/server/app/{icon.png → api/audit/run}/route/build-manifest.json +0 -0
- /package/.next/standalone/.next/server/app/{icon.png → api/audit/run}/route.js.map +0 -0
- /package/.next/standalone/.next/static/chunks/{03~yq9q893hmn.js → 0cz1d0mv5g_q7.js} +0 -0
- /package/.next/standalone/.next/static/chunks/{0a40sy4tk8ioe.js → 0wwt5o04i4zwh.js} +0 -0
- /package/.next/standalone/.next/static/chunks/{0n1n67imq.udf.js → 1__i9af9g78vd.js} +0 -0
- /package/.next/standalone/.next/static/chunks/{0w6fzf.07a24u.js → 2so39wg7mjbi7.js} +0 -0
- /package/.next/standalone/.next/static/chunks/{0xbo5nl6w4lka.js → 2wbuxnsvux4di.js} +0 -0
- /package/.next/standalone/.next/static/chunks/{0_s0luks5tay-.js → 35fgpd_feci6x.js} +0 -0
- /package/.next/standalone/.next/static/chunks/{15fklyav5py5m.js → 3xpjn3cdgm-7m.js} +0 -0
- /package/.next/standalone/.next/static/chunks/{17.b3suj8zjjj.js → 4448_qq7bd963.js} +0 -0
- /package/.next/standalone/.next/static/{tGVQM5SE3NvbVu0gbAJm7 → t4nu8RTRp3Z2srol-9pVb}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{tGVQM5SE3NvbVu0gbAJm7 → t4nu8RTRp3Z2srol-9pVb}/_clientMiddlewareManifest.js +0 -0
- /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.
|
|
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/
|
|
8734
|
-
|
|
8735
|
-
|
|
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
|
|
8754
|
-
|
|
8755
|
-
|
|
8756
|
-
|
|
8757
|
-
|
|
8758
|
-
|
|
8759
|
-
|
|
8760
|
-
|
|
8761
|
-
|
|
8762
|
-
|
|
8763
|
-
|
|
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
|
|
8812
|
-
|
|
8813
|
-
|
|
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
|
-
//
|
|
8824
|
-
function
|
|
8825
|
-
|
|
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
|
-
//
|
|
8869
|
-
|
|
8870
|
-
|
|
8871
|
-
|
|
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
|
|
8899
|
-
let
|
|
8758
|
+
async function parseError(res) {
|
|
8759
|
+
let body = {};
|
|
8900
8760
|
try {
|
|
8901
|
-
|
|
8902
|
-
} catch {
|
|
8903
|
-
|
|
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
|
-
|
|
8906
|
-
|
|
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
|
-
|
|
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
|
-
|
|
8933
|
-
|
|
8934
|
-
|
|
8935
|
-
|
|
8936
|
-
|
|
8937
|
-
|
|
8938
|
-
|
|
8939
|
-
|
|
8940
|
-
|
|
8941
|
-
|
|
8942
|
-
|
|
8943
|
-
|
|
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
|
|
8973
|
-
const
|
|
8974
|
-
if (
|
|
8975
|
-
|
|
8976
|
-
|
|
8977
|
-
|
|
8978
|
-
|
|
8979
|
-
|
|
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
|
-
|
|
8984
|
-
|
|
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
|
-
|
|
9035
|
-
|
|
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
|
|
9075
|
-
|
|
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
|
|
9086
|
-
|
|
9087
|
-
|
|
9088
|
-
|
|
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/
|
|
9092
|
-
import {
|
|
9093
|
-
|
|
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
|
-
|
|
9096
|
-
|
|
9097
|
-
|
|
9098
|
-
|
|
9099
|
-
}
|
|
9100
|
-
|
|
9101
|
-
|
|
9102
|
-
|
|
9103
|
-
|
|
9104
|
-
|
|
9105
|
-
|
|
9106
|
-
|
|
9107
|
-
|
|
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
|
-
|
|
9111
|
-
|
|
9112
|
-
|
|
9113
|
-
|
|
9114
|
-
|
|
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
|
-
|
|
9119
|
-
|
|
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
|
-
|
|
9154
|
-
|
|
9155
|
-
|
|
9156
|
-
|
|
9157
|
-
|
|
9158
|
-
|
|
9159
|
-
id:
|
|
9160
|
-
|
|
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
|
-
|
|
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
|
-
|
|
9232
|
-
|
|
9233
|
-
|
|
9234
|
-
|
|
9235
|
-
|
|
9236
|
-
|
|
9237
|
-
|
|
9238
|
-
|
|
9239
|
-
|
|
9240
|
-
|
|
9241
|
-
|
|
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
|
-
|
|
9246
|
-
|
|
9247
|
-
|
|
9248
|
-
|
|
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
|
|
9252
|
-
var
|
|
9253
|
-
|
|
9254
|
-
|
|
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/
|
|
9258
|
-
|
|
9259
|
-
|
|
9260
|
-
|
|
9261
|
-
|
|
9262
|
-
|
|
9263
|
-
|
|
9264
|
-
|
|
9265
|
-
|
|
9266
|
-
|
|
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
|
|
9285
|
-
|
|
9286
|
-
|
|
9287
|
-
|
|
9288
|
-
|
|
9289
|
-
|
|
9290
|
-
|
|
9291
|
-
|
|
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
|
-
|
|
9298
|
-
|
|
9299
|
-
|
|
9300
|
-
|
|
9301
|
-
|
|
9302
|
-
|
|
9303
|
-
|
|
9304
|
-
|
|
9305
|
-
|
|
9306
|
-
|
|
9307
|
-
|
|
9308
|
-
|
|
9309
|
-
|
|
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
|
-
|
|
9336
|
-
|
|
9337
|
-
|
|
9338
|
-
|
|
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
|
-
|
|
9349
|
-
|
|
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
|
-
|
|
9355
|
-
|
|
9356
|
-
|
|
9357
|
-
|
|
9358
|
-
|
|
9359
|
-
|
|
9360
|
-
|
|
9361
|
-
|
|
9362
|
-
|
|
9363
|
-
|
|
9364
|
-
|
|
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
|
-
|
|
9367
|
-
|
|
9368
|
-
|
|
9369
|
-
|
|
9370
|
-
|
|
9371
|
-
|
|
9372
|
-
|
|
9373
|
-
|
|
9374
|
-
|
|
9375
|
-
|
|
9376
|
-
|
|
9377
|
-
|
|
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
|
-
|
|
9387
|
-
|
|
9388
|
-
|
|
9389
|
-
|
|
9390
|
-
|
|
9391
|
-
|
|
9392
|
-
|
|
9393
|
-
|
|
9394
|
-
|
|
9395
|
-
|
|
9396
|
-
|
|
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
|
-
|
|
9400
|
-
|
|
9401
|
-
|
|
9402
|
-
|
|
9403
|
-
|
|
9404
|
-
|
|
9405
|
-
|
|
9406
|
-
|
|
9407
|
-
|
|
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
|
-
|
|
9181
|
+
}
|
|
9182
|
+
let upstream = "revoked";
|
|
9788
9183
|
try {
|
|
9789
|
-
|
|
9790
|
-
|
|
9791
|
-
|
|
9792
|
-
|
|
9793
|
-
|
|
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
|
-
|
|
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
|
|
9845
|
-
const
|
|
9846
|
-
|
|
9847
|
-
|
|
9848
|
-
|
|
9849
|
-
|
|
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
|
-
|
|
9856
|
-
|
|
9857
|
-
|
|
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
|
|
9912
|
-
|
|
9220
|
+
async function runAuthCli(args) {
|
|
9221
|
+
const opts = parseAuthArgs(args);
|
|
9222
|
+
if (opts.mode === "help") {
|
|
9223
|
+
process.stdout.write(HELP);
|
|
9913
9224
|
return;
|
|
9914
|
-
|
|
9915
|
-
|
|
9916
|
-
|
|
9917
|
-
|
|
9918
|
-
|
|
9919
|
-
|
|
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
|
|
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
|
-
|
|
9946
|
-
|
|
9947
|
-
|
|
9948
|
-
|
|
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
|
-
|
|
10221
|
-
|
|
10222
|
-
|
|
10223
|
-
|
|
10224
|
-
|
|
10225
|
-
|
|
10226
|
-
|
|
10227
|
-
|
|
10228
|
-
|
|
10229
|
-
|
|
10230
|
-
|
|
10231
|
-
|
|
10232
|
-
|
|
10233
|
-
|
|
10234
|
-
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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(
|
|
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
|
|
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.
|
|
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(
|
|
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(
|
|
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
|
|
11182
|
-
if ((args.includes("--help") || args.includes("-h")) && !
|
|
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
|
-
|
|
11220
|
-
|
|
11221
|
-
|
|
11222
|
-
|
|
11223
|
-
|
|
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")) && !
|
|
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] === "
|
|
11485
|
-
|
|
11486
|
-
|
|
11487
|
-
|
|
11488
|
-
|
|
11489
|
-
|
|
11490
|
-
|
|
11491
|
-
|
|
11492
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
11532
|
-
|
|
11533
|
-
--project
|
|
11534
|
-
--
|
|
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
|
|
11546
|
-
failproofai
|
|
11547
|
-
failproofai
|
|
11548
|
-
failproofai
|
|
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
|
|
11555
|
-
const
|
|
11556
|
-
|
|
11557
|
-
const
|
|
11558
|
-
|
|
11559
|
-
|
|
11560
|
-
|
|
11561
|
-
|
|
11562
|
-
|
|
11563
|
-
|
|
11564
|
-
|
|
11565
|
-
|
|
11566
|
-
|
|
11567
|
-
|
|
11568
|
-
|
|
11569
|
-
|
|
11570
|
-
|
|
11571
|
-
|
|
11572
|
-
|
|
11573
|
-
const
|
|
11574
|
-
|
|
11575
|
-
|
|
11576
|
-
|
|
11577
|
-
|
|
11578
|
-
|
|
11579
|
-
|
|
11580
|
-
|
|
11581
|
-
|
|
11582
|
-
|
|
11583
|
-
|
|
11584
|
-
|
|
11585
|
-
|
|
11586
|
-
|
|
11587
|
-
|
|
11588
|
-
|
|
11589
|
-
|
|
11590
|
-
|
|
11591
|
-
|
|
11592
|
-
|
|
11593
|
-
|
|
11594
|
-
|
|
11595
|
-
|
|
11596
|
-
|
|
11597
|
-
|
|
11598
|
-
|
|
11599
|
-
|
|
11600
|
-
|
|
11601
|
-
|
|
11602
|
-
|
|
11603
|
-
|
|
11604
|
-
|
|
11605
|
-
|
|
11606
|
-
|
|
11607
|
-
|
|
11608
|
-
|
|
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
|
-
|
|
11615
|
-
|
|
11616
|
-
|
|
11617
|
-
|
|
11618
|
-
|
|
11619
|
-
|
|
11620
|
-
|
|
11621
|
-
|
|
11622
|
-
|
|
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", "
|
|
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("-") && !
|
|
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),
|