failproofai 1.0.10 → 1.0.11-beta.0
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/build-manifest.json +6 -6
- package/.next/standalone/.next/prerender-manifest.json +4 -4
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +3 -3
- 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 +4 -4
- 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.meta +8 -0
- package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- 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 +3 -3
- 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 +4 -4
- 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.meta +8 -0
- package/.next/standalone/.next/server/app/_not-found.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +13 -13
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/api/audit/invite/route.js +4 -4
- package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js +4 -4
- package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/status/route.js +1 -1
- package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js +2 -2
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +4 -4
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route.js +3 -3
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js +3 -3
- package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page.js +4 -4
- package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.meta +8 -0
- package/.next/standalone/.next/server/app/index.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +13 -13
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js +4 -4
- 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 +3 -3
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
- package/.next/standalone/.next/server/app/policies/page.js +8 -8
- 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 +3 -3
- 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 +5 -5
- 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 +3 -3
- 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 +5 -5
- 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 +3 -3
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js +5 -5
- 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/settings/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +8 -8
- package/.next/standalone/.next/server/app/settings/page.js +9 -9
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/{[externals]__0qxhecv._.js → [externals]__0d7i9ea._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[externals]__0sg9-3p._.js → [externals]__0hjaw70._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[externals]__1_9ze9b._.js +3 -0
- package/.next/standalone/.next/server/chunks/[externals]__1oenfmn._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__08dchfu._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ga9hs7._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0l3yhx4._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0moxohc._.js +22 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0z2ll-a._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1adacul._.js +11 -11
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1autwno._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1v25n-6._.js +3 -0
- package/.next/standalone/.next/server/chunks/_09dz7xv._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1ek68ln._.js +2 -2
- package/.next/standalone/.next/server/chunks/_1fz8m31._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1jrv3hg._.js +3 -0
- package/.next/standalone/.next/server/chunks/_1nx8fim._.js +3 -0
- package/.next/standalone/.next/server/chunks/_1ogwigf._.js +1 -1
- package/.next/standalone/.next/server/chunks/{_1q5i8mb._.js → _1q27azx._.js} +2 -2
- package/.next/standalone/.next/server/chunks/lib_telemetry_ts_0dctyyw._.js +1 -1
- package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_0el6rg8._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_0ol5pa3._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_04op_ou._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_1rqmk27._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_0dr20uz._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_1w7tiq4._.js} +2 -2
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04usis8._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1-bm5zf._.js → [root-of-the-server]__0502lat._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0_gn5iz._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0f765xr._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__01bmjsj._.js → [root-of-the-server]__0h38gzz._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0hoaz1g._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1ouobn4._.js → [root-of-the-server]__0mxmwtx._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__19evfi8._.js → [root-of-the-server]__0uescqv._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1484zv2._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1mf3zp6._.js → [root-of-the-server]__19dutr7._.js} +4 -4
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0oqrl71._.js → [root-of-the-server]__1_qv8oh._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1u6sn69._.js → [root-of-the-server]__1ab4ifb._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1fbrk56._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1pprgri._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1um4yxn._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1wb4yt2._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1y3n3cn._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0bqoto4._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_16pa9ht._.js → _0lnpwk8._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{_0yq5_3a._.js → _15y8myg._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1gb0ifp._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{_042cgl1._.js → _1o95rf0._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{_1zopuov._.js → _1thr5rf._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +12 -14
- package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9sni._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h4._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_1hl81y4._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_0nkkbfv._.js +6 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +6 -6
- package/.next/standalone/.next/server/middleware.js +1 -1
- 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 +23 -23
- package/.next/standalone/.next/static/chunks/{03h3b-uomi7_d.js → 0pra9i676pym1.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2kj826h1w9r47.js → 1-lpi0m-hc1kb.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3ob2161ap37ul.js → 17yvyyblr_eb5.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3nkc2jlgyygda.js → 1mylcr99gccyz.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2j92xul6y24_v.js → 1wozchtn2etvh.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3mjfvng11xnoo.js → 23thtelz1a-ur.js} +2 -2
- package/.next/standalone/.next/static/chunks/{1fqukzzowjflt.js → 2bc17tohgs4bs.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3u1s8dsqiean5.js → 2xq-ejo8kti18.js} +1 -1
- package/.next/standalone/.next/static/chunks/3-_pth_c9n938.js +1 -0
- package/.next/standalone/.next/static/chunks/{3i8rg2fv9nd6e.js → 3n46e45atic-m.js} +1 -1
- package/.next/standalone/.next/static/chunks/{078dofaxvjgpd.js → 3q7sndqftqhw9.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0542cuk_va8g1.js → 3sg07wnn969xq.js} +1 -1
- package/.next/standalone/.next/static/chunks/{turbopack-11dn2pegmg9_9.js → turbopack-1opxka4dtjbc5.js} +1 -1
- package/.next/standalone/app/actions/install-hooks-web.ts +10 -2
- package/.next/standalone/hermes-plugin/plugin.yaml +1 -1
- 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/compiled/hash.js/sha256/256.js +1 -0
- package/.next/standalone/node_modules/next/dist/compiled/hash.js/sha256/package.json +1 -0
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js +17 -17
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js +18 -18
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-route-turbo.runtime.prod.js +3 -3
- package/.next/standalone/node_modules/next/dist/compiled/next-server/pages-turbo.runtime.prod.js +13 -13
- package/.next/standalone/node_modules/next/dist/lib/patch-incorrect-lockfile.js +3 -3
- package/.next/standalone/node_modules/next/dist/server/base-server.js +1 -2
- 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/image-optimizer.js +265 -53
- package/.next/standalone/node_modules/next/dist/server/lib/app-info-log.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/lib/incremental-cache/file-system-cache.js +177 -19
- package/.next/standalone/node_modules/next/dist/server/lib/incremental-cache/index.js +36 -17
- package/.next/standalone/node_modules/next/dist/server/lib/incremental-cache/shared-cache-controls.external.js +14 -6
- package/.next/standalone/node_modules/next/dist/server/lib/match-next-data-pathname.js +3 -1
- package/.next/standalone/node_modules/next/dist/server/lib/node-fs-methods.js +14 -0
- package/.next/standalone/node_modules/next/dist/server/lib/route-cache-key.js +77 -0
- package/.next/standalone/node_modules/next/dist/server/lib/router-utils/block-cross-site-dev.js +9 -11
- package/.next/standalone/node_modules/next/dist/server/lib/start-server.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/mcp/get-mcp-middleware.js +4 -2
- package/.next/standalone/node_modules/next/dist/server/next-server.js +7 -3
- package/.next/standalone/node_modules/next/dist/server/response-cache/index.js +32 -16
- package/.next/standalone/node_modules/next/dist/server/route-matcher-providers/app-page-route-matcher-provider.js +2 -2
- package/.next/standalone/node_modules/next/dist/server/route-modules/pages/pages-handler.js +6 -1
- package/.next/standalone/node_modules/next/dist/server/route-modules/route-module.js +9 -2
- package/.next/standalone/node_modules/next/dist/server/use-cache/use-cache-wrapper.js +30 -29
- package/.next/standalone/node_modules/next/dist/shared/lib/router/utils/app-paths.js +18 -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 +10 -10
- package/.next/standalone/package.json +14 -11
- package/.next/standalone/sdk/python/README.md +41 -0
- package/.next/standalone/sdk/python/docs/README.md +1 -0
- package/.next/standalone/sdk/python/docs/otel/README.md +36 -0
- package/.next/standalone/sdk/python/docs/otel/examples/agent_trace.py +30 -0
- package/.next/standalone/sdk/python/docs/otel/examples/quickstart.py +22 -0
- package/.next/standalone/sdk/python/failproofai_sdk/__init__.py +8 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/__init__.py +3 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/otel.py +189 -0
- package/.next/standalone/sdk/python/pyproject.toml +2 -1
- package/.next/standalone/sdk/python/tests/test_docs.py +16 -3
- package/.next/standalone/sdk/python/tests/test_integrations.py +1 -1
- package/.next/standalone/sdk/python/tests/test_otel.py +147 -0
- package/.next/standalone/sdk/python/tests/test_zero_dependencies.py +4 -1
- package/.next/standalone/sdk/python/uv.lock +258 -147
- package/.next/standalone/sdk/typescript/README.md +43 -0
- package/.next/standalone/sdk/typescript/integration/ai.test.ts +9 -2
- package/.next/standalone/sdk/typescript/package-lock.json +57 -5
- package/.next/standalone/sdk/typescript/package.json +2 -0
- package/.next/standalone/sdk/typescript/src/edge/index.ts +9 -0
- package/.next/standalone/sdk/typescript/src/index.ts +2 -0
- package/.next/standalone/sdk/typescript/src/integrations/index.ts +4 -1
- package/.next/standalone/sdk/typescript/src/integrations/otel.ts +204 -0
- package/.next/standalone/sdk/typescript/test/integrations.test.ts +1 -1
- package/.next/standalone/sdk/typescript/test/otel.test.ts +125 -0
- package/.next/standalone/server.js +1 -1
- package/bin/failproofai.mjs +653 -1077
- package/dist/cli.mjs +8781 -4050
- package/dist/worker.mjs +170 -62
- package/hermes-plugin/plugin.yaml +1 -1
- package/package.json +14 -11
- package/scripts/launch-facts.ts +157 -0
- package/scripts/launch-ready.ts +228 -0
- package/scripts/launch-screen.ts +202 -0
- package/scripts/launch.ts +106 -49
- package/scripts/skew-log-filter.ts +38 -0
- package/src/audit/cli-login.ts +39 -59
- package/src/audit/cli.ts +308 -228
- package/src/audit/index.ts +45 -2
- package/src/audit/schedule-cli.ts +83 -120
- package/src/audit/types.ts +31 -0
- package/src/hooks/agent-selection.ts +155 -0
- package/src/hooks/backfill-cli.ts +151 -137
- package/src/hooks/backfill-request.ts +149 -0
- package/src/hooks/cloud-connection.ts +1 -1
- package/src/hooks/cloud-enrollment-cli.ts +78 -28
- package/src/hooks/cloud-introspect.ts +3 -0
- package/src/hooks/collector-config.ts +10 -1
- package/src/hooks/config-status.ts +717 -0
- package/src/hooks/configure-wizard.ts +967 -988
- package/src/hooks/daemon-service.ts +16 -6
- package/src/hooks/did-you-mean.ts +185 -0
- package/src/hooks/flush-cli.ts +33 -7
- package/src/hooks/fp-config.ts +96 -0
- package/src/hooks/fp-home.ts +11 -0
- package/src/hooks/fp-reset.ts +102 -95
- package/src/hooks/handler.ts +4 -0
- package/src/hooks/harness-cli.ts +87 -138
- package/src/hooks/install-prompt.ts +38 -477
- package/src/hooks/integrations.ts +1 -1
- package/src/hooks/jev-cli.ts +183 -196
- package/src/hooks/manager.ts +554 -358
- package/src/hooks/onboarding-attempt.ts +11 -9
- package/src/hooks/otel-cli.ts +350 -0
- package/src/hooks/otel-output.ts +24 -0
- package/src/hooks/otel-writers.ts +215 -0
- package/src/hooks/pack-cli.ts +219 -204
- package/src/hooks/report-body.ts +50 -0
- package/src/hooks/safe-config-write.ts +4 -2
- package/src/hooks/session-pause-cli.ts +93 -73
- package/src/hooks/tui.ts +849 -389
- package/src/hooks/uninstall-cli.ts +136 -149
- package/src/hooks/untraced-note.ts +52 -0
- package/.next/standalone/.next/server/chunks/[externals]__19_pzeq._.js +0 -3
- package/.next/standalone/.next/server/chunks/[externals]__20kzpkf._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__01eqny5._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__05ja_05._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0igxt32._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zyc_nm._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ttrwnd._.js +0 -22
- package/.next/standalone/.next/server/chunks/_0bs-v8p._.js +0 -3
- package/.next/standalone/.next/server/chunks/_185gyk9._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__056wjo4._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n0xg95._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rwtwpm._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0yrsbd_._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11mayhe._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__15578wp._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1m_svbe._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1q4p5b8._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_1n3w9lb._.js +0 -6
- package/.next/standalone/.next/static/chunks/1lyg_puttohbc.js +0 -1
- /package/.next/standalone/.next/static/{ECs8__hcNabYV58WfDh-3 → xtcpqBNBdjQVerPMkI2HI}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{ECs8__hcNabYV58WfDh-3 → xtcpqBNBdjQVerPMkI2HI}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{ECs8__hcNabYV58WfDh-3 → xtcpqBNBdjQVerPMkI2HI}/_ssgManifest.js +0 -0
package/scripts/launch.ts
CHANGED
|
@@ -1,47 +1,89 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared launch logic for dev.ts and start.ts
|
|
2
|
+
* Shared launch logic for dev.ts and start.ts, bare `failproofai`, and the
|
|
3
|
+
* dashboard hand-off at the end of `failproofai audit`.
|
|
3
4
|
*/
|
|
4
5
|
import { spawn } from "child_process";
|
|
5
6
|
import { realpathSync, existsSync } from "node:fs";
|
|
6
7
|
import { resolve, dirname } from "node:path";
|
|
7
8
|
import { fileURLToPath } from "node:url";
|
|
8
|
-
import { createInterface } from "node:readline";
|
|
9
9
|
import { parseScriptArgs } from "./parse-script-args";
|
|
10
10
|
import { diagnoseShadow } from "./install-diagnosis.mjs";
|
|
11
|
-
import {
|
|
12
|
-
import { renderLaunchBanner } from "../src/hooks/tui";
|
|
11
|
+
import { colorsEnabled, screenKit } from "../src/hooks/tui";
|
|
13
12
|
import { isLoopbackHostname, resolveDashboardHost } from "../lib/dashboard-host";
|
|
13
|
+
import { dashboardBrowseUrl, exposedBindWarning, launchFailureLines, launchScreenLines } from "./launch-screen";
|
|
14
|
+
import { gatherLaunchFacts } from "./launch-facts";
|
|
15
|
+
import { dashboardProbeHost, probeDashboardPort, watchDashboardStart } from "./launch-ready";
|
|
14
16
|
import { version } from "../package.json";
|
|
15
17
|
|
|
16
|
-
export
|
|
17
|
-
|
|
18
|
+
export interface LaunchOptions {
|
|
19
|
+
/**
|
|
20
|
+
* Print the launch screen. Off for `failproofai audit`, whose hand-off prints
|
|
21
|
+
* its own lines and the /audit address before the server starts.
|
|
22
|
+
*/
|
|
23
|
+
screen?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Draw the logomark above the screen, on a terminal. Off when the first-run
|
|
26
|
+
* setup wizard already drew it in this process.
|
|
27
|
+
*/
|
|
28
|
+
logo?: boolean;
|
|
29
|
+
}
|
|
18
30
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
31
|
+
export function launch(mode: "dev" | "start", options: LaunchOptions = {}): void {
|
|
32
|
+
const { loggingLevel, disableTelemetry, allowedDevOrigins, host, remainingArgs } = parseScriptArgs(process.argv.slice(2));
|
|
33
|
+
const showScreen = options.screen !== false;
|
|
22
34
|
|
|
23
35
|
// The dashboard has no authentication and can toggle policies and uninstall
|
|
24
36
|
// hooks from every agent CLI, so it binds loopback unless someone asks
|
|
25
37
|
// otherwise. It used to bind 0.0.0.0 unconditionally, which handed all of
|
|
26
38
|
// that to every peer on the network.
|
|
27
39
|
const bindHost = resolveDashboardHost(host, process.env.FAILPROOFAI_DASHBOARD_HOST);
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
` It has no authentication: anyone who can reach it can read your session\n` +
|
|
32
|
-
` transcripts, disable your policies, and uninstall failproofai's hooks.\n`,
|
|
33
|
-
);
|
|
34
|
-
}
|
|
40
|
+
const exposed = isLoopbackHostname(bindHost)
|
|
41
|
+
? undefined
|
|
42
|
+
: { host: bindHost, fix: host !== undefined ? "--host 127.0.0.1" : "unset FAILPROOFAI_DASHBOARD_HOST" };
|
|
35
43
|
// Read back by proxy.ts, which refuses any request whose Host is not one it
|
|
36
44
|
// should be answering to — the layer that stops DNS rebinding, which a
|
|
37
45
|
// loopback bind alone does not.
|
|
38
46
|
process.env.FAILPROOFAI_DASHBOARD_HOST = bindHost;
|
|
39
47
|
|
|
48
|
+
// A routable bind is allowed, and said out loud. The launch screen carries
|
|
49
|
+
// that warning as its attention line; audit's hand-off has no screen, so it
|
|
50
|
+
// is said here, before anything listens.
|
|
51
|
+
if (exposed && !showScreen) {
|
|
52
|
+
const k = screenKit({ color: colorsEnabled(process.stderr) });
|
|
53
|
+
process.stderr.write(`\n${k.caution(exposedBindWarning(exposed.host))}\n ${k.cmd(exposed.fix)}\n\n`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// `.next/standalone/server.js` does `process.chdir(__dirname)` on its first
|
|
57
|
+
// line, so by the time a server action runs, `process.cwd()` is the PACKAGE
|
|
58
|
+
// directory, not the directory the user launched from. Anything resolving
|
|
59
|
+
// project-scope paths from cwd would look inside the installed package and
|
|
60
|
+
// find nothing. So the real cwd is captured here, before the child starts,
|
|
61
|
+
// the same way FAILPROOFAI_PACKAGE_ROOT is threaded through, and the launch
|
|
62
|
+
// screen reads the project from the same place the dashboard will.
|
|
63
|
+
const launchCwd = process.env.FAILPROOFAI_LAUNCH_CWD ?? process.cwd();
|
|
64
|
+
|
|
65
|
+
const portIdx = remainingArgs.indexOf("--port");
|
|
66
|
+
const portFlag = portIdx >= 0 ? remainingArgs[portIdx + 1] : undefined;
|
|
67
|
+
// `next dev` serves on PORT, else 3000, unless --port is passed through.
|
|
68
|
+
const port = mode === "start" ? (portFlag ?? "8020") : (portFlag ?? process.env.PORT ?? "3000");
|
|
69
|
+
|
|
70
|
+
const printScreen = (live: boolean): void => {
|
|
71
|
+
const lines = launchScreenLines(
|
|
72
|
+
{ url: dashboardBrowseUrl(bindHost, port), live, exposed, ...gatherLaunchFacts(launchCwd) },
|
|
73
|
+
{
|
|
74
|
+
color: colorsEnabled(process.stdout),
|
|
75
|
+
// Some pseudo-terminals report 0 columns; that is "unknown", not narrow.
|
|
76
|
+
cols: process.stdout.columns || undefined,
|
|
77
|
+
// Piped output is a log: no art in it.
|
|
78
|
+
logo: options.logo !== false && Boolean(process.stdout.isTTY),
|
|
79
|
+
},
|
|
80
|
+
);
|
|
81
|
+
process.stdout.write(`${lines.join("\n")}\n`);
|
|
82
|
+
};
|
|
83
|
+
|
|
40
84
|
let cmd: string;
|
|
41
85
|
let cmdArgs: string[];
|
|
42
86
|
if (mode === "start") {
|
|
43
|
-
const portIdx = remainingArgs.indexOf("--port");
|
|
44
|
-
const port = portIdx >= 0 ? remainingArgs[portIdx + 1] : "8020";
|
|
45
87
|
process.env.PORT = port;
|
|
46
88
|
process.env.HOSTNAME = bindHost;
|
|
47
89
|
cmd = "node";
|
|
@@ -100,52 +142,67 @@ export function launch(mode: "dev" | "start"): void {
|
|
|
100
142
|
}
|
|
101
143
|
|
|
102
144
|
// In `start` (the shipped standalone server) we pipe + filter the child's
|
|
103
|
-
// output to drop the benign "Failed to find Server Action" deployment-skew
|
|
145
|
+
// output: to drop the benign "Failed to find Server Action" deployment-skew
|
|
104
146
|
// block — a stale browser tab POSTing an old action ID after a rebuild, which
|
|
105
|
-
// the client recovers from via Next's graceful 404 (see skew-log-filter.ts)
|
|
147
|
+
// the client recovers from via Next's graceful 404 (see skew-log-filter.ts) —
|
|
148
|
+
// and to learn when the server is listening, so the launch screen can say so.
|
|
106
149
|
// `dev` keeps "inherit" so Next's interactive compile output is untouched.
|
|
107
|
-
// FORCE_COLOR keeps the piped child's output colored despite the non-TTY pipe.
|
|
108
150
|
const filterLogs = mode === "start";
|
|
109
151
|
|
|
152
|
+
// Dev never learns when its server is up, so its screen goes first, as the
|
|
153
|
+
// banner always did, and says it is starting.
|
|
154
|
+
if (!filterLogs && showScreen) printScreen(false);
|
|
155
|
+
|
|
110
156
|
const nextProcess = spawn(cmd, cmdArgs, {
|
|
111
157
|
stdio: filterLogs ? ["inherit", "pipe", "pipe"] : "inherit",
|
|
112
158
|
env: {
|
|
113
159
|
...process.env,
|
|
114
|
-
|
|
115
|
-
//
|
|
116
|
-
//
|
|
117
|
-
//
|
|
118
|
-
|
|
119
|
-
// starts, the same way FAILPROOFAI_PACKAGE_ROOT is threaded through.
|
|
120
|
-
FAILPROOFAI_LAUNCH_CWD: process.env.FAILPROOFAI_LAUNCH_CWD ?? process.cwd(),
|
|
121
|
-
...(filterLogs ? { FORCE_COLOR: process.env.FORCE_COLOR ?? "1" } : {}),
|
|
160
|
+
FAILPROOFAI_LAUNCH_CWD: launchCwd,
|
|
161
|
+
// Keeps the piped child's output coloured despite the pipe, when this
|
|
162
|
+
// process is itself writing to a terminal. Not otherwise: piped output is
|
|
163
|
+
// a log file, and forced colour put escape codes in it.
|
|
164
|
+
...(filterLogs && process.stdout.isTTY ? { FORCE_COLOR: process.env.FORCE_COLOR ?? "1" } : {}),
|
|
122
165
|
...(loggingLevel ? { FAILPROOFAI_LOG_LEVEL: loggingLevel } : {}),
|
|
123
166
|
...(disableTelemetry ? { FAILPROOFAI_TELEMETRY_DISABLED: "1" } : {}),
|
|
124
167
|
...(allowedDevOrigins ? { FAILPROOFAI_ALLOWED_DEV_ORIGINS: allowedDevOrigins.join(",") } : {}),
|
|
125
168
|
},
|
|
126
169
|
});
|
|
127
170
|
|
|
128
|
-
if (filterLogs) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
const out = filter(line);
|
|
138
|
-
if (out !== null) dest.write(out + "\n");
|
|
139
|
-
});
|
|
140
|
-
}
|
|
171
|
+
if (!filterLogs) {
|
|
172
|
+
nextProcess.on("error", (error) => {
|
|
173
|
+
console.error("Error starting Next.js:", error);
|
|
174
|
+
process.exit(1);
|
|
175
|
+
});
|
|
176
|
+
nextProcess.on("exit", (code) => {
|
|
177
|
+
process.exit(code || 0);
|
|
178
|
+
});
|
|
179
|
+
return;
|
|
141
180
|
}
|
|
142
181
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
process.
|
|
182
|
+
const failLine = (text: string): void => {
|
|
183
|
+
process.stderr.write(`${screenKit({ color: colorsEnabled(process.stderr) }).fail(text)}\n`);
|
|
184
|
+
};
|
|
185
|
+
watchDashboardStart({
|
|
186
|
+
child: nextProcess,
|
|
187
|
+
stdout: process.stdout,
|
|
188
|
+
stderr: process.stderr,
|
|
189
|
+
probe: () => probeDashboardPort(dashboardProbeHost(bindHost), Number(port)),
|
|
190
|
+
onSettled: (outcome) => {
|
|
191
|
+
if (outcome.kind === "failed") {
|
|
192
|
+
const lines = launchFailureLines(outcome, {
|
|
193
|
+
port,
|
|
194
|
+
portFromFlag: portFlag !== undefined,
|
|
195
|
+
color: colorsEnabled(process.stderr),
|
|
196
|
+
});
|
|
197
|
+
process.stderr.write(`${lines.join("\n")}\n`);
|
|
198
|
+
process.exit(outcome.code ?? 1);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if (showScreen) printScreen(outcome.kind === "ready");
|
|
202
|
+
},
|
|
203
|
+
onExit: (code, error) => {
|
|
204
|
+
if (error) failLine(`The dashboard server failed: ${error.message}`);
|
|
205
|
+
process.exit(error ? 1 : code || 0);
|
|
206
|
+
},
|
|
150
207
|
});
|
|
151
208
|
}
|
|
@@ -44,3 +44,41 @@ export function makeSkewLogFilter(): (line: string) => string | null {
|
|
|
44
44
|
return line;
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Drops Next's own startup banner from the standalone server's stdout, and
|
|
50
|
+
* reports the moment the server is listening.
|
|
51
|
+
*
|
|
52
|
+
* The launch screen prints the dashboard's address itself once the server is
|
|
53
|
+
* up, so in `start` mode Next's banner would say it a second time, in another
|
|
54
|
+
* style:
|
|
55
|
+
*
|
|
56
|
+
* ▲ Next.js 16.3.6
|
|
57
|
+
* - Local: http://127.0.0.1:8020
|
|
58
|
+
* - Network: http://127.0.0.1:8020
|
|
59
|
+
* ✓ Ready in 0ms
|
|
60
|
+
*
|
|
61
|
+
* Next logs `Ready in` from its `listening` handler, straight after the banner,
|
|
62
|
+
* so that line doubles as the readiness signal (`onReady`). Only those four
|
|
63
|
+
* shapes are dropped, and only until the ready line; every other line, and
|
|
64
|
+
* every line after it, passes through verbatim. That is the skew filter's
|
|
65
|
+
* contract too, and the reason the two are separate: its test pins these exact
|
|
66
|
+
* lines passing through it.
|
|
67
|
+
*
|
|
68
|
+
* The child is coloured when failproofai runs on a terminal, so a line is
|
|
69
|
+
* matched with its SGR codes stripped and, when kept, emitted as it arrived.
|
|
70
|
+
*/
|
|
71
|
+
export function makeNextStartupFilter(onReady?: () => void): (line: string) => string | null {
|
|
72
|
+
let listening = false;
|
|
73
|
+
return (line: string): string | null => {
|
|
74
|
+
if (listening) return line;
|
|
75
|
+
const plain = line.replace(/\x1B\[[0-9;]*m/g, "").trim();
|
|
76
|
+
if (/^(?:✓\s*)?Ready in\b/.test(plain)) {
|
|
77
|
+
listening = true;
|
|
78
|
+
onReady?.();
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
if (/^▲ Next\.js\b/.test(plain) || /^- (?:Local|Network):/.test(plain)) return null;
|
|
82
|
+
return line;
|
|
83
|
+
};
|
|
84
|
+
}
|
package/src/audit/cli-login.ts
CHANGED
|
@@ -20,16 +20,7 @@ import {
|
|
|
20
20
|
writeAuth,
|
|
21
21
|
type StoredAuth,
|
|
22
22
|
} from "../../lib/auth/auth-store";
|
|
23
|
-
import {
|
|
24
|
-
ANSI_RESET,
|
|
25
|
-
BAR,
|
|
26
|
-
colorsEnabled,
|
|
27
|
-
intro,
|
|
28
|
-
outro,
|
|
29
|
-
promptText,
|
|
30
|
-
step,
|
|
31
|
-
stepOpen,
|
|
32
|
-
} from "../hooks/tui";
|
|
23
|
+
import { INDENT, optsFor, paint, promptText, screenKit } from "../hooks/tui";
|
|
33
24
|
|
|
34
25
|
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
35
26
|
|
|
@@ -43,18 +34,6 @@ const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
|
43
34
|
const CODE_MIN = 4;
|
|
44
35
|
const CODE_MAX = 12;
|
|
45
36
|
|
|
46
|
-
/**
|
|
47
|
-
* The spine a prompt hangs off, so the two questions sit inside the same frame
|
|
48
|
-
* `intro`/`outro` draw. Empty when colour is off or output is piped: the frame
|
|
49
|
-
* is decoration, and a log file should not collect box-drawing characters.
|
|
50
|
-
*/
|
|
51
|
-
function spine(): string {
|
|
52
|
-
return colorsEnabled(process.stdout)
|
|
53
|
-
? `${ANSI_DIM_BAR}${BAR}${ANSI_RESET} `
|
|
54
|
-
: "";
|
|
55
|
-
}
|
|
56
|
-
const ANSI_DIM_BAR = "\x1B[2m";
|
|
57
|
-
|
|
58
37
|
/**
|
|
59
38
|
* Codes are numeric (`auth/otp.rs` generates digits only), so anything else in
|
|
60
39
|
* the field is packaging: "Your failproof code is 123456", a copied "123 456",
|
|
@@ -93,10 +72,9 @@ export interface SignedIn {
|
|
|
93
72
|
/**
|
|
94
73
|
* Whether a sign-in flow actually ran.
|
|
95
74
|
*
|
|
96
|
-
* The caller uses it to decide whether its confirmation continues an open
|
|
97
|
-
* or
|
|
98
|
-
*
|
|
99
|
-
* frame with no beginning.
|
|
75
|
+
* The caller uses it to decide whether its confirmation continues an open
|
|
76
|
+
* screen or opens its own: a sign-in has already printed the `Audit` header, so
|
|
77
|
+
* a second one under it would read as a second command.
|
|
100
78
|
*/
|
|
101
79
|
export interface EnsureSignedIn {
|
|
102
80
|
user: SignedIn;
|
|
@@ -199,35 +177,40 @@ export function invalidEmail(address: string): string | null {
|
|
|
199
177
|
}
|
|
200
178
|
|
|
201
179
|
/**
|
|
202
|
-
* The
|
|
180
|
+
* The sign-in screen: `failproofai audit --schedule`'s two prompts.
|
|
203
181
|
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
182
|
+
* In the language every other screen speaks — the `Audit` header, an
|
|
183
|
+
* UPPERCASE heading, a field per question, and a `✓` or `✕` line for each
|
|
184
|
+
* outcome — so a sign-in reads as the same product asking. It used to open
|
|
185
|
+
* with the full logomark inside `config`'s step spine, on the argument that
|
|
186
|
+
* the one personal question deserved the frame; the redesign keeps the mark to
|
|
187
|
+
* bare `failproofai` and `config` (LAUNCH-10), and the wordmark in the header
|
|
188
|
+
* is what every screen shares.
|
|
209
189
|
*
|
|
210
190
|
* Exported so a test can drive it without the caller.
|
|
211
191
|
*/
|
|
212
192
|
export async function runLogin(preset?: string): Promise<SignedIn> {
|
|
213
|
-
|
|
193
|
+
const k = screenKit(optsFor(process.stdout));
|
|
194
|
+
const say = (...lines: string[]) => process.stdout.write(`${lines.join("\n")}\n`);
|
|
195
|
+
say("", k.header("Audit"), "", k.head("Sign in"));
|
|
214
196
|
|
|
215
197
|
let address: string;
|
|
216
198
|
if (preset) {
|
|
217
199
|
// Supplied on the command line, so the question is already answered — but
|
|
218
|
-
// it is still SHOWN, as
|
|
219
|
-
// about to be sent to and the flag is exactly
|
|
200
|
+
// it is still SHOWN, as the field it would have been typed into, because it
|
|
201
|
+
// is the address a code is about to be sent to and the flag is exactly
|
|
202
|
+
// where a typo hides.
|
|
220
203
|
address = preset.trim().toLowerCase();
|
|
221
|
-
|
|
204
|
+
say(`${INDENT}${"email".padEnd(10)}${paint(optsFor(process.stdout).color).pink("›")} ${address}`);
|
|
222
205
|
} else {
|
|
223
206
|
const email = await promptText({
|
|
224
|
-
|
|
225
|
-
message: "
|
|
207
|
+
field: true,
|
|
208
|
+
message: "email",
|
|
226
209
|
hint: "you@yourdomain.com",
|
|
227
|
-
validate: (v) => (EMAIL_RE.test(v.trim()) ? null : "
|
|
210
|
+
validate: (v) => (EMAIL_RE.test(v.trim()) ? null : "That doesn't look like an email address."),
|
|
228
211
|
});
|
|
229
212
|
if (email === null) {
|
|
230
|
-
|
|
213
|
+
say("Cancelled. Nothing was changed.");
|
|
231
214
|
throw new LoginError("Cancelled.");
|
|
232
215
|
}
|
|
233
216
|
address = email.trim().toLowerCase();
|
|
@@ -237,65 +220,62 @@ export async function runLogin(preset?: string): Promise<SignedIn> {
|
|
|
237
220
|
const sent = await requestLoginCode(address);
|
|
238
221
|
expiresInMin = Math.max(1, Math.ceil(sent.expires_in / 60));
|
|
239
222
|
} catch (err) {
|
|
240
|
-
|
|
223
|
+
say(k.fail("Could not send a login code."));
|
|
241
224
|
throw new LoginError(describeAuthError(err, "Could not send a login code"));
|
|
242
225
|
}
|
|
243
226
|
|
|
244
|
-
// The address is echoed back
|
|
245
|
-
//
|
|
246
|
-
//
|
|
247
|
-
|
|
227
|
+
// The address is echoed back rather than left to memory: a typo in it is the
|
|
228
|
+
// single most likely reason no code arrives, and this is the last place it
|
|
229
|
+
// can be noticed before somebody starts waiting.
|
|
230
|
+
say(k.ok(`Sent a code to ${address}, valid for ${expiresInMin} minute${expiresInMin === 1 ? "" : "s"}.`));
|
|
248
231
|
|
|
249
232
|
// Three attempts, matching the server's own per-code cap. Looping forever
|
|
250
233
|
// would keep a person typing at a code the server stopped accepting after
|
|
251
234
|
// the fifth try, and one attempt would punish a typo with a fresh email.
|
|
252
235
|
const ATTEMPTS = 3;
|
|
253
236
|
for (let attempt = 1; attempt <= ATTEMPTS; attempt += 1) {
|
|
254
|
-
stepOpen(attempt === 1 ? "the code from that email" : "try that code again");
|
|
255
237
|
const typed = await promptText({
|
|
256
|
-
|
|
238
|
+
field: true,
|
|
257
239
|
message: "code",
|
|
258
240
|
// Unmasked on purpose. A login code is single-use and expires in minutes,
|
|
259
241
|
// so hiding it protects nothing and costs the one thing that matters at
|
|
260
242
|
// this prompt: seeing your own typo before pressing enter.
|
|
261
243
|
hint:
|
|
262
244
|
attempt === 1
|
|
263
|
-
? "123456
|
|
245
|
+
? "123456 · paste the whole line if you like"
|
|
264
246
|
: `attempt ${attempt} of ${ATTEMPTS}`,
|
|
265
247
|
validate: (v) => {
|
|
266
248
|
// No digits at all is not a mistyped code, it is not a code — caught
|
|
267
249
|
// here rather than spent as one of the server's five attempts.
|
|
268
|
-
if (!/\d/.test(v)) return "
|
|
250
|
+
if (!/\d/.test(v)) return "A code is digits. Paste the line from the email.";
|
|
269
251
|
const code = extractCode(v);
|
|
270
|
-
if (code.length < CODE_MIN) return "
|
|
271
|
-
if (code.length > CODE_MAX) return "
|
|
252
|
+
if (code.length < CODE_MIN) return "That looks too short to be the code.";
|
|
253
|
+
if (code.length > CODE_MAX) return "That looks too long. Paste just the code.";
|
|
272
254
|
return null;
|
|
273
255
|
},
|
|
274
256
|
});
|
|
275
257
|
if (typed === null) {
|
|
276
|
-
|
|
258
|
+
say("Cancelled. Nothing was changed.");
|
|
277
259
|
throw new LoginError("Cancelled.");
|
|
278
260
|
}
|
|
279
261
|
|
|
280
262
|
try {
|
|
281
263
|
const tokens = await verifyLoginCode(address, extractCode(typed));
|
|
282
264
|
writeAuth(authFromTokenResponse(tokens));
|
|
283
|
-
|
|
265
|
+
say(k.ok(`Signed in as ${tokens.user.email}.`));
|
|
284
266
|
return { id: tokens.user.id, email: tokens.user.email };
|
|
285
267
|
} catch (err) {
|
|
286
268
|
const wrongCode = err instanceof AuthApiError && err.code === "invalid_code";
|
|
287
269
|
if (wrongCode && attempt < ATTEMPTS) {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
`${ATTEMPTS - attempt} more ${ATTEMPTS - attempt === 1 ? "try" : "tries"} before it asks for a new one`,
|
|
291
|
-
);
|
|
270
|
+
// The tries left are on the next field's hint, `attempt 2 of 3`.
|
|
271
|
+
say(k.fail("That code was wrong or has expired."));
|
|
292
272
|
continue;
|
|
293
273
|
}
|
|
294
|
-
|
|
274
|
+
say(k.fail("Could not verify that code."));
|
|
295
275
|
throw new LoginError(describeAuthError(err, "Could not verify that code"));
|
|
296
276
|
}
|
|
297
277
|
}
|
|
298
|
-
|
|
278
|
+
say(k.fail("Too many wrong codes."));
|
|
299
279
|
throw new LoginError("Too many wrong codes. Run the command again for a fresh one.");
|
|
300
280
|
}
|
|
301
281
|
|