failproofai 0.0.11-beta.1 → 0.0.11-beta.3
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} +2 -2
- 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]__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]__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]__0ywoypf._.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]__100hdar._.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_1kp6l3x._.js +3 -0
- 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_05gja40.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} +2 -2
- 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/0ehe4dh0grngk.js +41 -0
- package/.next/standalone/.next/static/chunks/{13-bt.3~irg00.js → 0gdm-xaez4l7t.js} +1 -1
- package/.next/standalone/.next/static/chunks/{07kfzzinhsl7e.js → 0kdglk0vtzymo.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/1fmco3pvq_twz.js +1 -0
- package/.next/standalone/.next/static/chunks/2b1fzuhuk-42n.js +1 -0
- package/.next/standalone/.next/static/chunks/{0_vk1wsgf~q3o.js → 2dtip-mvmihiu.js} +1 -1
- package/.next/standalone/.next/static/chunks/2srzafd1_ha5y.js +1 -0
- package/.next/standalone/.next/static/chunks/{0d3shmwh5_nmn.js → 33u59vf_8xpd-.js} +1 -1
- package/.next/standalone/.next/static/chunks/3gti1qdk5epqn.js +1 -0
- package/.next/standalone/.next/static/chunks/{0wtiofzdt-l2u.js → 3krzy-lhwfrmz.js} +1 -1
- package/.next/standalone/.next/static/chunks/{17mubwtqwijpu.js → 3w8d8k_dca5rp.js} +1 -1
- package/.next/standalone/.next/static/chunks/43lnq0c1rnflb.js +6 -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 +325 -142
- 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/claude-sessions.ts +181 -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 +120 -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 +4 -3
- package/bin/failproofai.mjs +248 -70
- package/dist/cli.mjs +1709 -1385
- 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/claude-sessions.ts +181 -0
- package/lib/client-telemetry.ts +2 -0
- package/lib/fetch-with-timeout.ts +42 -0
- package/lib/share-card.ts +120 -0
- package/lib/telemetry.ts +12 -7
- package/package.json +8 -3
- package/scripts/install-telemetry.mjs +4 -0
- package/scripts/postinstall.mjs +89 -1
- package/src/audit/archetypes.ts +924 -0
- package/src/audit/cache.ts +132 -0
- package/src/audit/cli-adapters/claude.ts +97 -0
- package/src/audit/cli-adapters/codex.ts +56 -0
- package/src/audit/cli-adapters/copilot.ts +51 -0
- package/src/audit/cli-adapters/cursor.ts +51 -0
- package/src/audit/cli-adapters/gemini.ts +51 -0
- package/src/audit/cli-adapters/index.ts +70 -0
- package/src/audit/cli-adapters/opencode.ts +52 -0
- package/src/audit/cli-adapters/pi.ts +51 -0
- package/src/audit/cli-adapters/shared.ts +85 -0
- package/src/audit/dashboard-cache.ts +111 -0
- package/src/audit/detectors/find-from-root.ts +27 -0
- package/src/audit/detectors/git-commit-no-verify.ts +22 -0
- package/src/audit/detectors/index.ts +33 -0
- package/src/audit/detectors/prefer-edit-over-read-cat.ts +31 -0
- package/src/audit/detectors/prefer-edit-over-sed-awk.ts +27 -0
- package/src/audit/detectors/prefer-write-over-heredoc.ts +36 -0
- package/src/audit/detectors/redundant-cd-cwd.ts +28 -0
- package/src/audit/detectors/reread-after-edit.ts +58 -0
- package/src/audit/detectors/sleep-polling-loop.ts +34 -0
- package/src/audit/features.ts +268 -0
- package/src/audit/findings.ts +298 -0
- package/src/audit/index.ts +387 -0
- package/src/audit/replay.ts +147 -0
- package/src/audit/report.ts +349 -0
- package/src/audit/scoring.ts +174 -0
- package/src/audit/strengths.ts +138 -0
- package/src/audit/types.ts +216 -0
- package/src/auth/cli.ts +359 -0
- package/src/hooks/builtin-policies.ts +80 -1
- package/src/hooks/custom-hooks-loader.ts +19 -3
- package/src/hooks/first-run-nudge.ts +146 -0
- package/src/hooks/handler.ts +21 -102
- package/src/hooks/hook-telemetry.ts +2 -2
- package/src/hooks/install-prompt.ts +34 -4
- package/src/hooks/manager.ts +72 -5
- package/src/hooks/policy-evaluator.ts +16 -1
- package/src/hooks/policy-registry.ts +20 -0
- package/src/hooks/policy-types.ts +9 -0
- package/src/hooks/tool-name-canonicalize.ts +65 -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]__0370~qj._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__09i-rsi._.js +0 -4
- 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]__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/[root-of-the-server]__101v4_7._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12y7xmt._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/app_0cdqd9w._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_0xerkr6._.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/03xhjwk6zhi8f.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/0wq808vlc8l04.js +0 -6
- package/.next/standalone/.next/static/chunks/0zg~cpc5ysg6d.js +0 -1
- package/.next/standalone/.next/static/chunks/12pt~2f.c1sha.js +0 -1
- package/.next/standalone/.next/static/chunks/16vev.do1oho7.js +0 -4
- 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/auth/login.ts +0 -104
- package/src/auth/logout.ts +0 -50
- package/src/auth/token-store.ts +0 -64
- package/src/relay/daemon.ts +0 -362
- package/src/relay/pid.ts +0 -76
- package/src/relay/queue.ts +0 -225
- /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/{s5Nn6KwDdLpPhjG3l2WNf → wU3ot-EKa5ApKoh785wp8}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{s5Nn6KwDdLpPhjG3l2WNf → wU3ot-EKa5ApKoh785wp8}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{s5Nn6KwDdLpPhjG3l2WNf → wU3ot-EKa5ApKoh785wp8}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Low-level HTTP client for the FailproofAI api-server's /v0/auth/* endpoints.
|
|
3
|
+
*
|
|
4
|
+
* Shared by both the CLI (failproofai auth ...) and the dashboard's Next.js
|
|
5
|
+
* API route proxies. Has no filesystem access — token persistence lives in
|
|
6
|
+
* `./auth-store.ts`.
|
|
7
|
+
*
|
|
8
|
+
* The base URL is resolved from FAILPROOF_API_URL (preferred) or the legacy
|
|
9
|
+
* FAILPROOFAI_API_URL, falling back to the hosted api-server. Local-dev
|
|
10
|
+
* contributors should set FAILPROOF_API_URL=http://localhost:8080 (or
|
|
11
|
+
* whatever port their local api-server uses) in `.env.local`.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { trackEvent } from "../telemetry";
|
|
15
|
+
import { isAbortError } from "../fetch-with-timeout";
|
|
16
|
+
|
|
17
|
+
export const DEFAULT_API_BASE = "https://api.befailproof.ai";
|
|
18
|
+
|
|
19
|
+
export function getApiBase(): string {
|
|
20
|
+
const raw =
|
|
21
|
+
process.env.FAILPROOF_API_URL ??
|
|
22
|
+
process.env.FAILPROOFAI_API_URL ??
|
|
23
|
+
DEFAULT_API_BASE;
|
|
24
|
+
return raw.replace(/\/+$/, "");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class AuthApiError extends Error {
|
|
28
|
+
readonly status: number;
|
|
29
|
+
readonly code: string;
|
|
30
|
+
readonly retryAfterSecs?: number;
|
|
31
|
+
constructor(status: number, code: string, message: string, retryAfterSecs?: number) {
|
|
32
|
+
super(message);
|
|
33
|
+
this.status = status;
|
|
34
|
+
this.code = code;
|
|
35
|
+
this.retryAfterSecs = retryAfterSecs;
|
|
36
|
+
this.name = "AuthApiError";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface LoginRequestResponse {
|
|
41
|
+
status: "code_sent";
|
|
42
|
+
expires_in: number;
|
|
43
|
+
resend_available_in: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface UserView {
|
|
47
|
+
id: string;
|
|
48
|
+
email: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface TokenResponse {
|
|
52
|
+
token_type: "Bearer";
|
|
53
|
+
access_token: string;
|
|
54
|
+
access_expires_in: number;
|
|
55
|
+
refresh_token: string;
|
|
56
|
+
refresh_expires_in: number;
|
|
57
|
+
user: UserView;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface RefreshResponse {
|
|
61
|
+
token_type: "Bearer";
|
|
62
|
+
access_token: string;
|
|
63
|
+
access_expires_in: number;
|
|
64
|
+
refresh_token: string;
|
|
65
|
+
refresh_expires_in: number;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface MeResponse {
|
|
69
|
+
id: string;
|
|
70
|
+
email: string;
|
|
71
|
+
status: string;
|
|
72
|
+
created_at: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
interface ServerErrorBody {
|
|
76
|
+
// The docs describe `{ code, message }`; the live Rust server returns
|
|
77
|
+
// `{ success: false, code, detail }`. We tolerate either.
|
|
78
|
+
code?: string;
|
|
79
|
+
message?: string;
|
|
80
|
+
detail?: string;
|
|
81
|
+
retry_after_secs?: number;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function parseError(res: Response): Promise<AuthApiError> {
|
|
85
|
+
let body: ServerErrorBody = {};
|
|
86
|
+
try {
|
|
87
|
+
body = (await res.json()) as ServerErrorBody;
|
|
88
|
+
} catch {
|
|
89
|
+
// body might be empty or non-JSON
|
|
90
|
+
}
|
|
91
|
+
const code = body.code ?? `http_${res.status}`;
|
|
92
|
+
const message = body.message ?? body.detail ?? res.statusText ?? "request failed";
|
|
93
|
+
let retryAfterSecs = body.retry_after_secs;
|
|
94
|
+
if (retryAfterSecs === undefined) {
|
|
95
|
+
const h = res.headers.get("retry-after");
|
|
96
|
+
if (h) {
|
|
97
|
+
const n = Number(h);
|
|
98
|
+
if (Number.isFinite(n)) retryAfterSecs = n;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Clamp to a sane range: a misbehaving (or hostile) api-server could
|
|
102
|
+
// return `-3600` or `1e20` and our UI would render "wait 1e20s" or
|
|
103
|
+
// backoff loops would fire immediately on negatives. 24h is the longest
|
|
104
|
+
// wait the dashboard/CLI is willing to surface as a literal duration.
|
|
105
|
+
if (retryAfterSecs !== undefined) {
|
|
106
|
+
retryAfterSecs = Math.max(0, Math.min(86400, retryAfterSecs));
|
|
107
|
+
}
|
|
108
|
+
return new AuthApiError(res.status, code, message, retryAfterSecs);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Hard cap on every auth/reminder HTTP call. Without this, a wedged DNS
|
|
112
|
+
* resolver or a hung server keeps the CLI / dashboard route stuck forever. */
|
|
113
|
+
const REQUEST_TIMEOUT_MS = 10_000;
|
|
114
|
+
|
|
115
|
+
function timeoutSignal(extra?: AbortSignal): AbortSignal {
|
|
116
|
+
const t = AbortSignal.timeout(REQUEST_TIMEOUT_MS);
|
|
117
|
+
if (!extra) return t;
|
|
118
|
+
// Compose so an externally-cancelled caller still aborts. Prefer the
|
|
119
|
+
// native `AbortSignal.any` (Node 20.3+, Bun 1.0.27+); fall back to a
|
|
120
|
+
// hand-rolled controller for older runtimes — without this fallback
|
|
121
|
+
// an `extra` signal would be silently dropped.
|
|
122
|
+
const anyFn = (AbortSignal as unknown as { any?: (s: AbortSignal[]) => AbortSignal }).any;
|
|
123
|
+
if (anyFn) return anyFn([t, extra]);
|
|
124
|
+
const composed = new AbortController();
|
|
125
|
+
const onAbort = (s: AbortSignal) => composed.abort(s.reason);
|
|
126
|
+
if (t.aborted) onAbort(t);
|
|
127
|
+
else t.addEventListener("abort", () => onAbort(t), { once: true });
|
|
128
|
+
if (extra.aborted) onAbort(extra);
|
|
129
|
+
else extra.addEventListener("abort", () => onAbort(extra), { once: true });
|
|
130
|
+
return composed.signal;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function pathFromUrl(url: string): string {
|
|
134
|
+
try {
|
|
135
|
+
return new URL(url).pathname;
|
|
136
|
+
} catch {
|
|
137
|
+
return url;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async function fetchWithTimeout(url: string, init: RequestInit): Promise<Response> {
|
|
142
|
+
try {
|
|
143
|
+
return await fetch(url, { ...init, signal: timeoutSignal(init.signal ?? undefined) });
|
|
144
|
+
} catch (err) {
|
|
145
|
+
const isTimeout = isAbortError(err);
|
|
146
|
+
// Low-cardinality "api-server is down" counter. We only attach the
|
|
147
|
+
// request path (not the full URL) and a coarse kind so it stays a
|
|
148
|
+
// cheap signal in PostHog. No-ops on the CLI side when telemetry
|
|
149
|
+
// has not been initialised.
|
|
150
|
+
trackEvent("api_server_unreachable", {
|
|
151
|
+
kind: isTimeout ? "timeout" : "network",
|
|
152
|
+
path: pathFromUrl(url),
|
|
153
|
+
method: typeof init.method === "string" ? init.method : "GET",
|
|
154
|
+
});
|
|
155
|
+
if (isTimeout) {
|
|
156
|
+
throw new AuthApiError(
|
|
157
|
+
0,
|
|
158
|
+
"timeout",
|
|
159
|
+
`request to ${url} timed out after ${REQUEST_TIMEOUT_MS}ms`,
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
throw err;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function postJson<T>(path: string, body: unknown, init?: { accessToken?: string }): Promise<T> {
|
|
167
|
+
const headers: Record<string, string> = { "content-type": "application/json" };
|
|
168
|
+
if (init?.accessToken) headers["authorization"] = `Bearer ${init.accessToken}`;
|
|
169
|
+
const res = await fetchWithTimeout(`${getApiBase()}${path}`, {
|
|
170
|
+
method: "POST",
|
|
171
|
+
headers,
|
|
172
|
+
body: JSON.stringify(body),
|
|
173
|
+
});
|
|
174
|
+
if (res.status === 204) return undefined as T;
|
|
175
|
+
if (!res.ok) throw await parseError(res);
|
|
176
|
+
return (await res.json()) as T;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async function getJson<T>(path: string, accessToken: string): Promise<T> {
|
|
180
|
+
const res = await fetchWithTimeout(`${getApiBase()}${path}`, {
|
|
181
|
+
method: "GET",
|
|
182
|
+
headers: { authorization: `Bearer ${accessToken}` },
|
|
183
|
+
});
|
|
184
|
+
if (!res.ok) throw await parseError(res);
|
|
185
|
+
return (await res.json()) as T;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export async function requestLoginCode(email: string): Promise<LoginRequestResponse> {
|
|
189
|
+
return postJson<LoginRequestResponse>("/v0/auth/login/request", { email });
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export async function verifyLoginCode(email: string, code: string): Promise<TokenResponse> {
|
|
193
|
+
return postJson<TokenResponse>("/v0/auth/login/verify", { email, code });
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export async function refreshAccessToken(refreshToken: string): Promise<RefreshResponse> {
|
|
197
|
+
return postJson<RefreshResponse>("/v0/auth/token/refresh", {
|
|
198
|
+
refresh_token: refreshToken,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export async function logoutSession(accessToken: string, refreshToken: string): Promise<void> {
|
|
203
|
+
await postJson<void>(
|
|
204
|
+
"/v0/auth/logout",
|
|
205
|
+
{ refresh_token: refreshToken },
|
|
206
|
+
{ accessToken },
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export async function fetchMe(accessToken: string): Promise<MeResponse> {
|
|
211
|
+
return getJson<MeResponse>("/v0/auth/me", accessToken);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export interface ServerReminder {
|
|
215
|
+
user_id: string;
|
|
216
|
+
email: string;
|
|
217
|
+
fire_at: number; // unix seconds
|
|
218
|
+
set_at: number; // unix seconds
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export async function scheduleReminder(
|
|
222
|
+
accessToken: string,
|
|
223
|
+
body: { in_days?: number; at?: number },
|
|
224
|
+
): Promise<ServerReminder> {
|
|
225
|
+
const res = await postJson<{ reminder: ServerReminder }>(
|
|
226
|
+
"/v0/reminders",
|
|
227
|
+
body,
|
|
228
|
+
{ accessToken },
|
|
229
|
+
);
|
|
230
|
+
return res.reminder;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export async function cancelReminder(accessToken: string): Promise<void> {
|
|
234
|
+
const res = await fetchWithTimeout(`${getApiBase()}/v0/reminders`, {
|
|
235
|
+
method: "DELETE",
|
|
236
|
+
headers: { authorization: `Bearer ${accessToken}` },
|
|
237
|
+
});
|
|
238
|
+
if (res.status === 204 || res.ok) return;
|
|
239
|
+
throw await parseError(res);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
interface JwtClaims {
|
|
243
|
+
sub: string;
|
|
244
|
+
email: string;
|
|
245
|
+
iss?: string;
|
|
246
|
+
aud?: string;
|
|
247
|
+
iat?: number;
|
|
248
|
+
exp: number;
|
|
249
|
+
token_type?: string;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Decode the JWT payload without verifying the signature. Safe for client-side
|
|
254
|
+
* reading (sub, email, exp). Returns null if the token is malformed.
|
|
255
|
+
*
|
|
256
|
+
* Strictly validates base64url before decoding: `Buffer.from(s, 'base64url')`
|
|
257
|
+
* silently truncates on illegal characters (`+`, `/`, whitespace, embedded
|
|
258
|
+
* NULs) rather than throwing, and the truncated bytes can happen to parse as
|
|
259
|
+
* JSON with a numeric `exp` field, producing synthetic "valid" claims from a
|
|
260
|
+
* corrupted token.
|
|
261
|
+
*/
|
|
262
|
+
const BASE64URL_RE = /^[A-Za-z0-9_-]+={0,2}$/;
|
|
263
|
+
|
|
264
|
+
export function decodeJwt(token: string): JwtClaims | null {
|
|
265
|
+
try {
|
|
266
|
+
const parts = token.split(".");
|
|
267
|
+
if (parts.length !== 3) return null;
|
|
268
|
+
// Header and payload must both be syntactically valid base64url. Empty
|
|
269
|
+
// segments are also rejected (Buffer.from("","base64url") would return
|
|
270
|
+
// an empty buffer that JSON.parse correctly throws on, but rejecting
|
|
271
|
+
// upfront is cheaper and clearer).
|
|
272
|
+
if (!BASE64URL_RE.test(parts[0])) return null;
|
|
273
|
+
if (!BASE64URL_RE.test(parts[1])) return null;
|
|
274
|
+
const json = Buffer.from(parts[1], "base64url").toString("utf8");
|
|
275
|
+
const parsed = JSON.parse(json) as JwtClaims;
|
|
276
|
+
if (typeof parsed.exp !== "number") return null;
|
|
277
|
+
return parsed;
|
|
278
|
+
} catch {
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistence layer for the FailproofAI auth.json file.
|
|
3
|
+
*
|
|
4
|
+
* Tokens live at ~/.failproofai/auth.json with mode 0600. The dashboard's
|
|
5
|
+
* Next.js API routes and the CLI both read/write through here so the user's
|
|
6
|
+
* session survives across `failproofai` (dashboard) and `failproofai auth`
|
|
7
|
+
* (CLI) invocations.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { existsSync, readFileSync, rmSync } from "node:fs";
|
|
11
|
+
import { homedir } from "node:os";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
|
|
14
|
+
import { writeJsonAtomically } from "../atomic-write";
|
|
15
|
+
import {
|
|
16
|
+
AuthApiError,
|
|
17
|
+
decodeJwt,
|
|
18
|
+
fetchMe,
|
|
19
|
+
refreshAccessToken,
|
|
20
|
+
type MeResponse,
|
|
21
|
+
} from "./api-server-client";
|
|
22
|
+
|
|
23
|
+
export interface StoredAuth {
|
|
24
|
+
access_token: string;
|
|
25
|
+
refresh_token: string;
|
|
26
|
+
access_expires_at: number; // unix seconds
|
|
27
|
+
refresh_expires_at: number; // unix seconds (best-effort; not strictly verified server-side)
|
|
28
|
+
user: { id: string; email: string };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function getAuthDir(): string {
|
|
32
|
+
const override = process.env.FAILPROOFAI_AUTH_DIR;
|
|
33
|
+
if (override) return override;
|
|
34
|
+
return join(homedir(), ".failproofai");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function getAuthFilePath(): string {
|
|
38
|
+
return join(getAuthDir(), "auth.json");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Location of the persisted re-audit reminder (separate from auth.json so
|
|
42
|
+
* the reminder survives unrelated session refreshes). */
|
|
43
|
+
export function getReminderFilePath(): string {
|
|
44
|
+
return join(getAuthDir(), "next-audit.json");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface StoredReminder {
|
|
48
|
+
/** Unix seconds. */
|
|
49
|
+
next_audit_at: number;
|
|
50
|
+
/** Email the reminder was set for. Used to invalidate the reminder if the
|
|
51
|
+
* active session belongs to a different user. */
|
|
52
|
+
user_email: string;
|
|
53
|
+
/** Unix seconds. */
|
|
54
|
+
set_at: number;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function readReminder(): StoredReminder | null {
|
|
58
|
+
const p = getReminderFilePath();
|
|
59
|
+
if (!existsSync(p)) return null;
|
|
60
|
+
try {
|
|
61
|
+
const raw = readFileSync(p, "utf-8");
|
|
62
|
+
const parsed = JSON.parse(raw) as Partial<StoredReminder>;
|
|
63
|
+
if (
|
|
64
|
+
typeof parsed.next_audit_at !== "number" ||
|
|
65
|
+
typeof parsed.user_email !== "string" ||
|
|
66
|
+
typeof parsed.set_at !== "number"
|
|
67
|
+
) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
next_audit_at: parsed.next_audit_at,
|
|
72
|
+
user_email: parsed.user_email,
|
|
73
|
+
set_at: parsed.set_at,
|
|
74
|
+
};
|
|
75
|
+
} catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function writeReminder(reminder: StoredReminder): void {
|
|
81
|
+
writeJsonAtomically(getReminderFilePath(), reminder);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function deleteReminder(): void {
|
|
85
|
+
const p = getReminderFilePath();
|
|
86
|
+
if (existsSync(p)) rmSync(p, { force: true });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function readAuth(): StoredAuth | null {
|
|
90
|
+
const p = getAuthFilePath();
|
|
91
|
+
if (!existsSync(p)) return null;
|
|
92
|
+
try {
|
|
93
|
+
const raw = readFileSync(p, "utf-8");
|
|
94
|
+
const parsed = JSON.parse(raw) as Partial<StoredAuth>;
|
|
95
|
+
if (
|
|
96
|
+
typeof parsed.access_token !== "string" ||
|
|
97
|
+
typeof parsed.refresh_token !== "string" ||
|
|
98
|
+
typeof parsed.access_expires_at !== "number" ||
|
|
99
|
+
typeof parsed.user !== "object" ||
|
|
100
|
+
!parsed.user ||
|
|
101
|
+
typeof (parsed.user as { id?: unknown }).id !== "string" ||
|
|
102
|
+
typeof (parsed.user as { email?: unknown }).email !== "string"
|
|
103
|
+
) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
access_token: parsed.access_token,
|
|
108
|
+
refresh_token: parsed.refresh_token,
|
|
109
|
+
access_expires_at: parsed.access_expires_at,
|
|
110
|
+
refresh_expires_at:
|
|
111
|
+
typeof parsed.refresh_expires_at === "number"
|
|
112
|
+
? parsed.refresh_expires_at
|
|
113
|
+
: parsed.access_expires_at,
|
|
114
|
+
user: {
|
|
115
|
+
id: (parsed.user as { id: string }).id,
|
|
116
|
+
email: (parsed.user as { email: string }).email,
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
} catch {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function writeAuth(auth: StoredAuth): void {
|
|
125
|
+
writeJsonAtomically(getAuthFilePath(), auth);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function deleteAuth(): void {
|
|
129
|
+
const p = getAuthFilePath();
|
|
130
|
+
if (existsSync(p)) rmSync(p, { force: true });
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Convert verify/refresh response into the on-disk shape. */
|
|
134
|
+
export function authFromTokenResponse(token: {
|
|
135
|
+
access_token: string;
|
|
136
|
+
refresh_token: string;
|
|
137
|
+
access_expires_in: number;
|
|
138
|
+
refresh_expires_in: number;
|
|
139
|
+
user?: { id: string; email: string };
|
|
140
|
+
}, existingUser?: { id: string; email: string }): StoredAuth {
|
|
141
|
+
const now = Math.floor(Date.now() / 1000);
|
|
142
|
+
const user = token.user ?? existingUser;
|
|
143
|
+
if (!user) {
|
|
144
|
+
throw new Error("authFromTokenResponse: missing user identity");
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
access_token: token.access_token,
|
|
148
|
+
refresh_token: token.refresh_token,
|
|
149
|
+
access_expires_at: now + token.access_expires_in,
|
|
150
|
+
refresh_expires_at: now + token.refresh_expires_in,
|
|
151
|
+
user,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Return a fresh access token, refreshing in-place if the current one is
|
|
157
|
+
* within the leeway window of expiry. Mutates auth.json on disk on success.
|
|
158
|
+
* Returns null if the stored session is gone or the refresh failed (caller
|
|
159
|
+
* should treat that as "logged out").
|
|
160
|
+
*/
|
|
161
|
+
const REFRESH_LEEWAY_SECS = 60;
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* In-flight refresh dedup. Without this, two concurrent callers (e.g.
|
|
165
|
+
* the dashboard's `/api/auth/status` poll and a `/api/auth/reminder`
|
|
166
|
+
* POST in flight) both observe the same expired access token, both call
|
|
167
|
+
* `refreshAccessToken(auth.refresh_token)` with the same refresh token,
|
|
168
|
+
* and the api-server treats the second call as token-replay and revokes
|
|
169
|
+
* every session for that user — a silent logout. Keying on the refresh
|
|
170
|
+
* token avoids accidentally sharing a refresh across logins/logouts in
|
|
171
|
+
* the same process.
|
|
172
|
+
*/
|
|
173
|
+
const inFlightRefreshes = new Map<string, Promise<StoredAuth>>();
|
|
174
|
+
|
|
175
|
+
async function dedupedRefresh(auth: StoredAuth): Promise<StoredAuth> {
|
|
176
|
+
const existing = inFlightRefreshes.get(auth.refresh_token);
|
|
177
|
+
if (existing) return existing;
|
|
178
|
+
const p = (async () => {
|
|
179
|
+
const refreshed = await refreshAccessToken(auth.refresh_token);
|
|
180
|
+
const next = authFromTokenResponse(refreshed, auth.user);
|
|
181
|
+
writeAuth(next);
|
|
182
|
+
return next;
|
|
183
|
+
})();
|
|
184
|
+
inFlightRefreshes.set(auth.refresh_token, p);
|
|
185
|
+
try {
|
|
186
|
+
return await p;
|
|
187
|
+
} finally {
|
|
188
|
+
inFlightRefreshes.delete(auth.refresh_token);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export async function getValidAccessToken(): Promise<StoredAuth | null> {
|
|
193
|
+
const auth = readAuth();
|
|
194
|
+
if (!auth) return null;
|
|
195
|
+
const now = Math.floor(Date.now() / 1000);
|
|
196
|
+
if (auth.access_expires_at - now > REFRESH_LEEWAY_SECS) return auth;
|
|
197
|
+
// Either expired or close to expiring — try to refresh.
|
|
198
|
+
try {
|
|
199
|
+
return await dedupedRefresh(auth);
|
|
200
|
+
} catch (err) {
|
|
201
|
+
if (err instanceof AuthApiError && err.status === 401) {
|
|
202
|
+
// Session unrecoverable — wipe.
|
|
203
|
+
deleteAuth();
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
// Network errors etc — surface to caller as null so the UI can recover.
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Verify with the server that the stored access token is still valid.
|
|
213
|
+
* Refreshes once on 401. Returns the live /me response and the (possibly
|
|
214
|
+
* refreshed) stored auth, or null if the session can't be recovered.
|
|
215
|
+
*/
|
|
216
|
+
export async function whoAmI(): Promise<{ me: MeResponse; auth: StoredAuth } | null> {
|
|
217
|
+
const fresh = await getValidAccessToken();
|
|
218
|
+
if (!fresh) return null;
|
|
219
|
+
try {
|
|
220
|
+
const me = await fetchMe(fresh.access_token);
|
|
221
|
+
return { me, auth: fresh };
|
|
222
|
+
} catch (err) {
|
|
223
|
+
if (err instanceof AuthApiError && err.status === 401) {
|
|
224
|
+
// Maybe the leeway wasn't enough — try one more refresh and retry.
|
|
225
|
+
const reread = readAuth();
|
|
226
|
+
if (!reread) return null;
|
|
227
|
+
try {
|
|
228
|
+
const next = await dedupedRefresh(reread);
|
|
229
|
+
const me = await fetchMe(next.access_token);
|
|
230
|
+
return { me, auth: next };
|
|
231
|
+
} catch (retryErr) {
|
|
232
|
+
// Symmetry with `getValidAccessToken`: wipe the session only on an
|
|
233
|
+
// unambiguous 401. A transient timeout/5xx during the retry-fetchMe
|
|
234
|
+
// must NOT throw away the freshly-written valid tokens, otherwise a
|
|
235
|
+
// brief api-server hiccup silently logs the user out.
|
|
236
|
+
if (retryErr instanceof AuthApiError && retryErr.status === 401) {
|
|
237
|
+
deleteAuth();
|
|
238
|
+
}
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** Reads the JWT exp claim for diagnostics. */
|
|
247
|
+
export function readAccessExpiry(auth: StoredAuth): number | null {
|
|
248
|
+
const claims = decodeJwt(auth.access_token);
|
|
249
|
+
return claims?.exp ?? null;
|
|
250
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code session transcript discovery helpers.
|
|
3
|
+
*
|
|
4
|
+
* Claude stores transcripts at:
|
|
5
|
+
* <CLAUDE_PROJECTS_PATH>/<encoded-cwd>/<sessionId>.jsonl
|
|
6
|
+
*
|
|
7
|
+
* Subagent transcripts (when a session spawned subagents) live alongside:
|
|
8
|
+
* <CLAUDE_PROJECTS_PATH>/<encoded-cwd>/<sessionId>/subagents/<agentId>.jsonl
|
|
9
|
+
*
|
|
10
|
+
* The parser for these files lives in `lib/log-entries.ts` (`parseLogContent`,
|
|
11
|
+
* `parseSessionLog`). This module exposes discovery only — the audit pipeline
|
|
12
|
+
* and any future Claude-specific tool walk the directory layout via these
|
|
13
|
+
* helpers instead of re-implementing the path conventions.
|
|
14
|
+
*
|
|
15
|
+
* Mirrors the shape of `lib/cursor-sessions.ts` for parity across CLIs.
|
|
16
|
+
*/
|
|
17
|
+
import { readdirSync, statSync, existsSync } from "node:fs";
|
|
18
|
+
import { join, basename } from "node:path";
|
|
19
|
+
import { getClaudeProjectsPath, decodeFolderName } from "./paths";
|
|
20
|
+
|
|
21
|
+
const UUID_RE = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i;
|
|
22
|
+
|
|
23
|
+
export interface ClaudeProjectFolder {
|
|
24
|
+
/** Encoded folder name on disk (e.g. "-home-user-project"). */
|
|
25
|
+
name: string;
|
|
26
|
+
/** Decoded filesystem path (e.g. "/home/user/project"). */
|
|
27
|
+
cwd: string;
|
|
28
|
+
/** Absolute path of the encoded folder. */
|
|
29
|
+
path: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface ClaudeTranscriptFile {
|
|
33
|
+
projectName: string;
|
|
34
|
+
/** Decoded cwd of the project. */
|
|
35
|
+
cwd: string;
|
|
36
|
+
sessionId: string;
|
|
37
|
+
/** Absolute path of `<sessionId>.jsonl`. */
|
|
38
|
+
transcriptPath: string;
|
|
39
|
+
mtimeMs: number;
|
|
40
|
+
sizeBytes: number;
|
|
41
|
+
/** True when this is a subagent transcript spawned from a parent session. */
|
|
42
|
+
isSubagent: boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Returns the Claude projects root, honoring the CLAUDE_PROJECTS_PATH env var. */
|
|
46
|
+
export function getClaudeProjectsRoot(): string {
|
|
47
|
+
return getClaudeProjectsPath();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Lists all Claude project folders (one per encoded cwd). Returns [] if the
|
|
51
|
+
* projects root doesn't exist. Filenames that don't look like Claude project
|
|
52
|
+
* encodings are still included — encoding is permissive. */
|
|
53
|
+
export function listClaudeProjects(): ClaudeProjectFolder[] {
|
|
54
|
+
const root = getClaudeProjectsRoot();
|
|
55
|
+
let entries: import("node:fs").Dirent[];
|
|
56
|
+
try {
|
|
57
|
+
entries = readdirSync(root, { withFileTypes: true });
|
|
58
|
+
} catch {
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
return entries
|
|
62
|
+
.filter((e) => e.isDirectory())
|
|
63
|
+
.map((e) => ({
|
|
64
|
+
name: e.name,
|
|
65
|
+
cwd: decodeFolderName(e.name),
|
|
66
|
+
path: join(root, e.name),
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Lists every JSONL transcript under one Claude project folder, including
|
|
71
|
+
* subagent transcripts under `<sessionId>/subagents/`. Returns [] on missing
|
|
72
|
+
* or unreadable paths. */
|
|
73
|
+
export function listClaudeTranscripts(project: ClaudeProjectFolder): ClaudeTranscriptFile[] {
|
|
74
|
+
const out: ClaudeTranscriptFile[] = [];
|
|
75
|
+
let entries: import("node:fs").Dirent[];
|
|
76
|
+
try {
|
|
77
|
+
entries = readdirSync(project.path, { withFileTypes: true });
|
|
78
|
+
} catch {
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
for (const entry of entries) {
|
|
83
|
+
if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
84
|
+
const sessionId = entry.name.slice(0, -".jsonl".length);
|
|
85
|
+
if (!UUID_RE.test(sessionId)) continue;
|
|
86
|
+
const transcriptPath = join(project.path, entry.name);
|
|
87
|
+
try {
|
|
88
|
+
const s = statSync(transcriptPath);
|
|
89
|
+
out.push({
|
|
90
|
+
projectName: project.name,
|
|
91
|
+
cwd: project.cwd,
|
|
92
|
+
sessionId,
|
|
93
|
+
transcriptPath,
|
|
94
|
+
mtimeMs: s.mtimeMs,
|
|
95
|
+
sizeBytes: s.size,
|
|
96
|
+
isSubagent: false,
|
|
97
|
+
});
|
|
98
|
+
} catch {
|
|
99
|
+
// unreadable — skip
|
|
100
|
+
}
|
|
101
|
+
} else if (entry.isDirectory() && UUID_RE.test(entry.name)) {
|
|
102
|
+
// Subagent transcripts at <sessionId>/subagents/<agentId>.jsonl
|
|
103
|
+
const subDir = join(project.path, entry.name, "subagents");
|
|
104
|
+
if (!existsSync(subDir)) continue;
|
|
105
|
+
let subEntries: import("node:fs").Dirent[];
|
|
106
|
+
try {
|
|
107
|
+
subEntries = readdirSync(subDir, { withFileTypes: true });
|
|
108
|
+
} catch {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
for (const sub of subEntries) {
|
|
112
|
+
if (!sub.isFile() || !sub.name.endsWith(".jsonl")) continue;
|
|
113
|
+
const agentId = sub.name.slice(0, -".jsonl".length);
|
|
114
|
+
const transcriptPath = join(subDir, sub.name);
|
|
115
|
+
try {
|
|
116
|
+
const s = statSync(transcriptPath);
|
|
117
|
+
out.push({
|
|
118
|
+
projectName: project.name,
|
|
119
|
+
cwd: project.cwd,
|
|
120
|
+
sessionId: agentId,
|
|
121
|
+
transcriptPath,
|
|
122
|
+
mtimeMs: s.mtimeMs,
|
|
123
|
+
sizeBytes: s.size,
|
|
124
|
+
isSubagent: true,
|
|
125
|
+
});
|
|
126
|
+
} catch {
|
|
127
|
+
// unreadable — skip
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Convenience: locate one Claude transcript file by session ID across all
|
|
137
|
+
* project folders. Returns null if not found. */
|
|
138
|
+
export function findClaudeTranscript(sessionId: string): string | null {
|
|
139
|
+
if (!UUID_RE.test(sessionId)) return null;
|
|
140
|
+
for (const project of listClaudeProjects()) {
|
|
141
|
+
const candidate = join(project.path, `${sessionId}.jsonl`);
|
|
142
|
+
if (existsSync(candidate)) return candidate;
|
|
143
|
+
// Subagent fallback
|
|
144
|
+
let entries: import("node:fs").Dirent[];
|
|
145
|
+
try {
|
|
146
|
+
entries = readdirSync(project.path, { withFileTypes: true });
|
|
147
|
+
} catch {
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
for (const entry of entries) {
|
|
151
|
+
if (!entry.isDirectory() || !UUID_RE.test(entry.name)) continue;
|
|
152
|
+
const subCandidate = join(project.path, entry.name, "subagents", `${sessionId}.jsonl`);
|
|
153
|
+
if (existsSync(subCandidate)) return subCandidate;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** For tests: list all session IDs across all projects. */
|
|
160
|
+
export function _listAllSessionIds(): string[] {
|
|
161
|
+
const ids: string[] = [];
|
|
162
|
+
for (const project of listClaudeProjects()) {
|
|
163
|
+
for (const t of listClaudeTranscripts(project)) {
|
|
164
|
+
ids.push(t.sessionId);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return ids;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** For tests: stat one transcript file. */
|
|
171
|
+
export function _statTranscript(path: string): { mtimeMs: number; sizeBytes: number } | null {
|
|
172
|
+
try {
|
|
173
|
+
const s = statSync(path);
|
|
174
|
+
return { mtimeMs: s.mtimeMs, sizeBytes: s.size };
|
|
175
|
+
} catch {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** Re-export for callers that want to construct paths from a basename. */
|
|
181
|
+
export { basename };
|