failproofai 1.0.0-beta.4 → 1.0.0-beta.6
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 +2 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/routes-manifest.json +6 -0
- 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 +3 -1
- 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/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js +3 -1
- 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 +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
- 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/invite/route.js +3 -2
- 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 -3
- 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 -1
- 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 +3 -2
- 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 -2
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js +3 -2
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js +3 -2
- 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/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page.js +5 -3
- 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.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
- 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 -2
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js +3 -1
- 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/server-reference-manifest.json +10 -10
- package/.next/standalone/.next/server/app/policies/page.js +4 -2
- 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/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js +4 -2
- 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/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 +6 -4
- 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/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js +4 -2
- 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/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/settings/page/build-manifest.json +18 -0
- package/.next/standalone/.next/server/app/settings/page/next-font-manifest.json +6 -0
- package/.next/standalone/.next/server/app/settings/page/react-loadable-manifest.json +1 -0
- package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +53 -0
- package/.next/standalone/.next/server/app/settings/page.js +18 -0
- package/.next/standalone/.next/server/app/settings/page.js.map +5 -0
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app-paths-manifest.json +2 -1
- package/.next/standalone/.next/server/chunks/{[externals]__1nl3dvw._.js → [externals]__0r-zamh._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__06hexd0._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__094p1f1._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_0xu5z._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ed01_d._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0g0vcwt._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0h3lfmp._.js → [root-of-the-server]__0ky_n0r._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__18d-9oi._.js → [root-of-the-server]__0lk_935._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1p7s8-d._.js → [root-of-the-server]__0pbp9fe._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q-v9z2._.js +1 -1
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__10oa-v9._.js → [root-of-the-server]__0v2fpxe._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0sb_5m8._.js → [root-of-the-server]__131ebum._.js} +3 -3
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0-dh5jy._.js → [root-of-the-server]__1_ps0jw._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0l4vuqm._.js → [root-of-the-server]__1a7i2q4._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ibjy5x._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1iny24d._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tvn4wf._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tyedjt._.js +3 -0
- package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +5 -0
- package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +5 -0
- package/.next/standalone/.next/server/chunks/lib_telemetry_ts_0dctyyw._.js +5 -0
- package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +5 -5
- 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]__06bp_fg._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__074qmkp._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0spkm68._.js +10 -10
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1_a_gwn._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1a2hcb_._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1e7-pa7._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0rtdfof._.js → [root-of-the-server]__1rdruw4._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1rv-sc9._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1tyf0tc._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1u-wx42._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1v185mo._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0rag5dg._.js → [root-of-the-server]__1yw368c._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_0-yi74u._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_04mekdy._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0igtyj5._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0r-dsre._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0rjgfln._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0se484m._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0uz7o9y._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_11_p9y8._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1fahg9e._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1gmzkwj._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/_1w8sola._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1w_6p9g._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +2 -2
- 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 +2 -2
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0dwo94s.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +5 -0
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/middleware.js +2 -2
- 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 +54 -12
- package/.next/standalone/.next/static/chunks/{2c90h1g6x8z8y.js → 0_2n13i94rnw5.js} +1 -1
- package/.next/standalone/.next/static/chunks/1bm0q12hgs22l.css +2 -0
- package/.next/standalone/.next/static/chunks/1v1gqvpjk62jm.js +1 -0
- package/.next/standalone/.next/static/chunks/23557z4e6dtsr.js +1 -0
- package/.next/standalone/.next/static/chunks/28zkwzu50puki.js +1 -0
- package/.next/standalone/.next/static/chunks/2uvhw57mf9lg_.css +2 -0
- package/.next/standalone/.next/static/chunks/3081gykdubv8b.js +1 -0
- package/.next/standalone/.next/static/chunks/{06jakt_xhoolk.js → 34fa65k0cldkj.js} +1 -1
- package/.next/standalone/.next/static/chunks/35v07j9gc1pvr.js +6 -0
- package/.next/standalone/.next/static/chunks/{2zb3m1tzq6h98.js → 3f_939wi3kfnx.js} +22 -22
- package/.next/standalone/.next/static/chunks/{31cqiv_cpgj9m.js → 3p1vpm2_-tfwm.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0ue9ak_xexiqh.js → 3rbpw_waieafm.js} +1 -1
- package/.next/standalone/.next/static/chunks/40ffnfpkeyvb0.js +1 -0
- package/.next/standalone/app/actions/get-hooks-config.ts +2 -1
- package/.next/standalone/app/actions/get-scheduled-audit.ts +70 -0
- package/.next/standalone/app/actions/update-scheduled-audit.ts +44 -0
- package/.next/standalone/app/api/audit/run/route.ts +28 -0
- package/.next/standalone/app/api/audit/status/route.ts +13 -1
- package/.next/standalone/app/api/auth/status/route.ts +1 -1
- package/.next/standalone/app/audit/_components/auth-dialog.css +159 -0
- package/.next/standalone/app/audit/_components/auth-dialog.tsx +3 -0
- package/.next/standalone/app/audit/audit-styles.css +6 -149
- package/.next/standalone/app/settings/page.tsx +31 -0
- package/.next/standalone/app/settings/settings-client.tsx +488 -0
- package/.next/standalone/components/navbar.tsx +2 -0
- package/.next/standalone/lib/auth/api-server-client.ts +2 -3
- package/.next/standalone/lib/auth/auth-store.ts +4 -4
- package/.next/standalone/lib/codex-sessions.ts +2 -1
- package/.next/standalone/lib/dashboard-host.ts +101 -0
- package/.next/standalone/lib/install-check.ts +22 -7
- package/.next/standalone/lib/pi-sessions.ts +99 -14
- package/.next/standalone/lib/telemetry-enabled.ts +54 -0
- package/.next/standalone/lib/telemetry-id.ts +52 -1
- package/.next/standalone/lib/telemetry.ts +8 -4
- 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 +3 -3
- 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 +4 -4
- package/.next/standalone/package.json +7 -6
- package/.next/standalone/proxy.ts +89 -1
- package/.next/standalone/server.js +1 -1
- package/bin/failproofai.mjs +197 -80
- package/dist/cli.mjs +17699 -15345
- package/dist/worker.mjs +1620 -257
- package/lib/auth/api-server-client.ts +2 -3
- package/lib/auth/auth-store.ts +4 -4
- package/lib/codex-sessions.ts +2 -1
- package/lib/dashboard-host.ts +101 -0
- package/lib/install-check.ts +22 -7
- package/lib/pi-sessions.ts +99 -14
- package/lib/telemetry-enabled.ts +54 -0
- package/lib/telemetry-id.ts +52 -1
- package/lib/telemetry.ts +8 -4
- package/package.json +7 -6
- package/scripts/install-telemetry.mjs +8 -1
- package/scripts/launch.ts +25 -3
- package/scripts/parse-script-args.ts +17 -1
- package/scripts/prune-standalone.mjs +20 -0
- package/scripts/translate-docs/readme-translator.ts +163 -4
- package/scripts/validate-mdx.ts +153 -13
- package/src/audit/audit-lock.ts +285 -0
- package/src/audit/audit-schedule.ts +111 -0
- package/src/audit/cache.ts +18 -4
- package/src/audit/cli-adapters/goose.ts +2 -1
- package/src/audit/cli-adapters/hermes.ts +28 -10
- package/src/audit/cli.ts +191 -35
- package/src/audit/dashboard-cache.ts +2 -1
- package/src/hooks/builtin-policies.ts +100 -3
- package/src/hooks/cloud-connection.ts +163 -14
- package/src/hooks/cloud-enrollment-cli.ts +119 -21
- package/src/hooks/cloud-enrollment.ts +87 -17
- package/src/hooks/cloud-introspect.ts +147 -0
- package/src/hooks/cloud-managed-policies.ts +33 -2
- package/src/hooks/collector-config.ts +32 -40
- package/src/hooks/configure-wizard.ts +696 -318
- package/src/hooks/custom-hooks-loader.ts +125 -11
- package/src/hooks/daemon-client.ts +83 -17
- package/src/hooks/daemon-download.ts +54 -2
- package/src/hooks/daemon-service.ts +595 -27
- package/src/hooks/first-run-gate.ts +39 -0
- package/src/hooks/fp-config.ts +497 -0
- package/src/hooks/fp-home.ts +342 -0
- package/src/hooks/fp-reset.ts +332 -0
- package/src/hooks/handler.ts +42 -1
- package/src/hooks/hook-activity-store.ts +35 -20
- package/src/hooks/hook-logger.ts +2 -1
- package/src/hooks/hook-telemetry.ts +5 -1
- package/src/hooks/hooks-config.ts +4 -3
- package/src/hooks/loader-utils.ts +166 -5
- package/src/hooks/manager.ts +5 -4
- package/src/hooks/onboarding-lock.ts +119 -0
- package/src/hooks/policy-types.ts +0 -7
- package/src/hooks/session-pause-cli.ts +15 -13
- package/src/hooks/session-pause.ts +36 -4
- package/src/hooks/setup-state.ts +256 -0
- package/src/hooks/tui.ts +4 -4
- package/src/hooks/worker-server.ts +53 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0f8nu8d._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0szqzl8._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__19120tr._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1fwl2mz._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1myjm-d._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1rhmvod._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02r5bgf._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0cmdyn_._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e8sjqm._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0lkzqax._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ls0gsr._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n_uvv0._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qucxyj._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0sdrz-j._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0u02miy._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__14dd6h8._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1j4u3yd._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1zqz4v8._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/_1m_p7pi._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/node_modules_html-to-image_es_index_1q9xxca.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1ezd2jf._.js +0 -5
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1tnuifj._.js +0 -5
- package/.next/standalone/.next/static/chunks/0h7auy7hzjyhw.js +0 -1
- package/.next/standalone/.next/static/chunks/0oe2-hp0_2tzs.js +0 -6
- package/.next/standalone/.next/static/chunks/1fw3pxobk_otl.js +0 -1
- package/.next/standalone/.next/static/chunks/3h5_3u46gu9jx.js +0 -1
- package/.next/standalone/.next/static/chunks/3i27c3hcriawq.css +0 -1
- package/.next/standalone/.next/static/chunks/3zdwnnthucs_1.css +0 -2
- package/.next/standalone/.next/static/chunks/43a1ywqsg9bq9.js +0 -1
- package/.next/standalone/Cargo.lock +0 -2222
- package/.next/standalone/Cargo.toml +0 -9
- package/.next/standalone/crates/CLOUD_POLICIES.md +0 -136
- package/.next/standalone/crates/PROTOCOL.md +0 -122
- package/.next/standalone/crates/failproofaid/Cargo.toml +0 -25
- package/.next/standalone/crates/failproofaid/src/cloud_client.rs +0 -484
- package/.next/standalone/crates/failproofaid/src/cloud_policies.rs +0 -921
- package/.next/standalone/crates/failproofaid/src/lock.rs +0 -81
- package/.next/standalone/crates/failproofaid/src/main.rs +0 -532
- package/.next/standalone/crates/failproofaid/src/paths.rs +0 -201
- package/.next/standalone/crates/failproofaid/src/server.rs +0 -502
- package/.next/standalone/crates/failproofaid/src/worker.rs +0 -400
- package/.next/standalone/crates/failproofaid/tests/daemon_e2e.rs +0 -241
- package/.next/standalone/crates/fpai-collect/Cargo.toml +0 -43
- package/.next/standalone/crates/fpai-collect/src/config.rs +0 -412
- package/.next/standalone/crates/fpai-collect/src/cursor.rs +0 -520
- package/.next/standalone/crates/fpai-collect/src/delivery.rs +0 -472
- package/.next/standalone/crates/fpai-collect/src/filetail.rs +0 -484
- package/.next/standalone/crates/fpai-collect/src/health.rs +0 -369
- package/.next/standalone/crates/fpai-collect/src/lib.rs +0 -34
- package/.next/standalone/crates/fpai-collect/src/redact.rs +0 -516
- package/.next/standalone/crates/fpai-collect/src/sources/claude/mod.rs +0 -279
- package/.next/standalone/crates/fpai-collect/src/sources/claude/transform.rs +0 -619
- package/.next/standalone/crates/fpai-collect/src/sources/codex/mod.rs +0 -156
- package/.next/standalone/crates/fpai-collect/src/sources/codex/transform.rs +0 -715
- package/.next/standalone/crates/fpai-collect/src/sources/copilot/mod.rs +0 -158
- package/.next/standalone/crates/fpai-collect/src/sources/copilot/transform.rs +0 -512
- package/.next/standalone/crates/fpai-collect/src/sources/goose/mod.rs +0 -511
- package/.next/standalone/crates/fpai-collect/src/sources/goose/transform.rs +0 -586
- package/.next/standalone/crates/fpai-collect/src/sources/hermes/mod.rs +0 -318
- package/.next/standalone/crates/fpai-collect/src/sources/hermes/transform.rs +0 -579
- package/.next/standalone/crates/fpai-collect/src/sources/hooks/mod.rs +0 -310
- package/.next/standalone/crates/fpai-collect/src/sources/hooks/transform.rs +0 -448
- package/.next/standalone/crates/fpai-collect/src/sources/mod.rs +0 -23
- package/.next/standalone/crates/fpai-collect/src/sources/openclaw/mod.rs +0 -176
- package/.next/standalone/crates/fpai-collect/src/sources/openclaw/transform.rs +0 -500
- package/.next/standalone/crates/fpai-collect/src/sources/opencode/mod.rs +0 -315
- package/.next/standalone/crates/fpai-collect/src/sources/opencode/transform.rs +0 -493
- package/.next/standalone/crates/fpai-collect/src/sources/pi/mod.rs +0 -201
- package/.next/standalone/crates/fpai-collect/src/sources/pi/transform.rs +0 -533
- package/.next/standalone/crates/fpai-collect/src/spool.rs +0 -458
- package/.next/standalone/crates/fpai-collect/src/sqlitepoll.rs +0 -387
- package/.next/standalone/crates/fpai-collect/src/supervisor.rs +0 -423
- package/.next/standalone/crates/fpai-collect/src/uploader.rs +0 -600
- package/.next/standalone/crates/fpai-collect/tests/claude_source.rs +0 -738
- package/.next/standalone/crates/fpai-collect/tests/claude_subagents.rs +0 -393
- package/.next/standalone/crates/fpai-collect/tests/codex_source.rs +0 -975
- package/.next/standalone/crates/fpai-collect/tests/config.rs +0 -286
- package/.next/standalone/crates/fpai-collect/tests/copilot_source.rs +0 -1019
- package/.next/standalone/crates/fpai-collect/tests/delivery.rs +0 -281
- package/.next/standalone/crates/fpai-collect/tests/goose_source.rs +0 -1008
- package/.next/standalone/crates/fpai-collect/tests/hermes_source.rs +0 -1129
- package/.next/standalone/crates/fpai-collect/tests/hooks_source.rs +0 -621
- package/.next/standalone/crates/fpai-collect/tests/openclaw_source.rs +0 -854
- package/.next/standalone/crates/fpai-collect/tests/opencode_source.rs +0 -1478
- package/.next/standalone/crates/fpai-collect/tests/pi_source.rs +0 -1191
- package/.next/standalone/crates/fpai-collect/tests/supervisor.rs +0 -290
- package/.next/standalone/crates/fpai-collect/tests/uploader.rs +0 -506
- package/.next/standalone/crates/fpai-ipc/Cargo.toml +0 -16
- package/.next/standalone/crates/fpai-ipc/src/envelope.rs +0 -175
- package/.next/standalone/crates/fpai-ipc/src/framing.rs +0 -177
- package/.next/standalone/crates/fpai-ipc/src/lib.rs +0 -10
- package/.next/standalone/crates/fpai-ipc/src/peer.rs +0 -80
- package/.next/standalone/docker-hook-sync/Dockerfile +0 -79
- package/.next/standalone/docker-hook-sync/entrypoint.sh +0 -109
- package/.next/standalone/integration-suite/Dockerfile +0 -47
- package/.next/standalone/integration-suite/README.md +0 -129
- package/.next/standalone/integration-suite/canary-policies.mjs +0 -45
- package/.next/standalone/integration-suite/capture-tokens.sh +0 -48
- package/.next/standalone/integration-suite/ci-entrypoint.sh +0 -179
- package/.next/standalone/integration-suite/inject-tokens.sh +0 -44
- package/.next/standalone/integration-suite/install-clis.sh +0 -136
- package/.next/standalone/integration-suite/probe-cli.sh +0 -248
- package/.next/standalone/integration-suite/report.js +0 -120
- package/.next/standalone/integration-suite/run.sh +0 -159
- package/.next/standalone/openclaw-plugin/index.js +0 -223
- package/.next/standalone/openclaw-plugin/openclaw.plugin.json +0 -6
- package/.next/standalone/openclaw-plugin/package.json +0 -12
- package/.next/standalone/osv-scanner.toml +0 -17
- package/.next/standalone/pi-extension/index.ts +0 -524
- package/.next/standalone/pi-extension/package.json +0 -12
- package/.next/standalone/postcss.config.mjs +0 -8
- package/.next/standalone/readme-arch-hq.gif +0 -0
- package/.next/standalone/rust-toolchain.toml +0 -4
- package/src/auth/cli.ts +0 -371
- /package/.next/standalone/.next/static/{StV6Lay7Q1cU4ysYCFJmH → Ptn8aBQl_cnNgOd0ebyv0}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{StV6Lay7Q1cU4ysYCFJmH → Ptn8aBQl_cnNgOd0ebyv0}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{StV6Lay7Q1cU4ysYCFJmH → Ptn8aBQl_cnNgOd0ebyv0}/_ssgManifest.js +0 -0
|
@@ -30,10 +30,19 @@
|
|
|
30
30
|
*/
|
|
31
31
|
import {
|
|
32
32
|
cloudCredentialPath,
|
|
33
|
+
validateCloudUrl,
|
|
33
34
|
verifyCloudCredentials,
|
|
34
35
|
writeCloudCredentials,
|
|
35
36
|
type CloudCredentials,
|
|
36
37
|
} from "./cloud-enrollment";
|
|
38
|
+
import { updateConfig, readCredentials, writeCredentials } from "./fp-config";
|
|
39
|
+
import {
|
|
40
|
+
introspectKey,
|
|
41
|
+
hasPermission,
|
|
42
|
+
describeOrg,
|
|
43
|
+
PERMISSION_EVENTS,
|
|
44
|
+
PERMISSION_POLICIES,
|
|
45
|
+
} from "./cloud-introspect";
|
|
37
46
|
import {
|
|
38
47
|
ingestPath,
|
|
39
48
|
validateIngestKey,
|
|
@@ -42,8 +51,23 @@ import {
|
|
|
42
51
|
type CollectorSettings,
|
|
43
52
|
} from "./collector-config";
|
|
44
53
|
|
|
45
|
-
/**
|
|
46
|
-
|
|
54
|
+
/**
|
|
55
|
+
* The path ingest is served on, appended to the cloud base URL.
|
|
56
|
+
*
|
|
57
|
+
* `/v1/events` rather than `/events`, and the difference is load-bearing for
|
|
58
|
+
* the hosted deployment. The server mounts its route list TWICE — flat at `/`
|
|
59
|
+
* and nested under `/v1` — so both reach the same handler when you talk to the
|
|
60
|
+
* server directly. But on the dashboard hostname a reverse proxy routes only
|
|
61
|
+
* `/v1/*` and `/enforcement/v1/*` to the server and sends EVERYTHING ELSE to
|
|
62
|
+
* the Next.js app. So `https://app.befailproof.ai/events` does not reach ingest
|
|
63
|
+
* at all; it reaches a web app that will happily answer.
|
|
64
|
+
*
|
|
65
|
+
* `/v1/events` is therefore the only path that works on all three shapes: the
|
|
66
|
+
* dashboard hostname, the server hostname, and a Compose deployment with no
|
|
67
|
+
* proxy at all. That is what lets one `--connect <origin>` configure BOTH
|
|
68
|
+
* capabilities from a single URL.
|
|
69
|
+
*/
|
|
70
|
+
export const INGEST_PATH = "/v1/events";
|
|
47
71
|
|
|
48
72
|
/**
|
|
49
73
|
* The ingest endpoint for a cloud base URL.
|
|
@@ -66,20 +90,45 @@ export function ingestUrlFor(baseUrl: string): string {
|
|
|
66
90
|
*/
|
|
67
91
|
export function cloudBaseFor(url: string): string {
|
|
68
92
|
const trimmed = url.replace(/\/$/, "");
|
|
69
|
-
|
|
93
|
+
// Strip either ingest path. People paste what an older setup asked for, what
|
|
94
|
+
// is already in their config, or what a colleague sent them — and `/events`
|
|
95
|
+
// was the documented value for the whole life of the product before `/v1`.
|
|
96
|
+
// Refusing a URL we can read perfectly well is pedantry; silently treating
|
|
97
|
+
// `https://host/events` as an ORIGIN would be worse, because every derived
|
|
98
|
+
// URL would then carry a stray `/events` segment.
|
|
99
|
+
for (const suffix of [INGEST_PATH, "/events"]) {
|
|
100
|
+
if (trimmed.endsWith(suffix)) return trimmed.slice(0, -suffix.length);
|
|
101
|
+
}
|
|
102
|
+
return trimmed;
|
|
70
103
|
}
|
|
71
104
|
|
|
72
105
|
export interface ConnectInput {
|
|
73
|
-
/**
|
|
106
|
+
/**
|
|
107
|
+
* Cloud base URL. Re-validated with `validateCloudUrl` on entry rather than
|
|
108
|
+
* trusted — this used to say "already validated by `validateCloudUrl`", and
|
|
109
|
+
* the wizard did not.
|
|
110
|
+
*/
|
|
74
111
|
url: string;
|
|
75
112
|
token: string;
|
|
76
113
|
machineId: string;
|
|
77
|
-
/**
|
|
114
|
+
/** Human-facing display name for this machine. Defaults to the hostname. */
|
|
115
|
+
machineLabel?: string;
|
|
116
|
+
/**
|
|
117
|
+
* Send session transcripts.
|
|
118
|
+
*
|
|
119
|
+
* Both callers — the wizard and `--connect` — now pass `true` unless the
|
|
120
|
+
* user opts out, because transcripts are what makes a dashboard worth
|
|
121
|
+
* connecting to. This function itself still requires it EXPLICITLY and
|
|
122
|
+
* treats `undefined` as off: a library that silently opts a caller into
|
|
123
|
+
* shipping prompts and file contents is the wrong default at this layer,
|
|
124
|
+
* whatever the product default above it happens to be.
|
|
125
|
+
*/
|
|
78
126
|
sessions?: boolean;
|
|
79
127
|
environment?: string;
|
|
80
128
|
/** Injected by tests so nothing reaches the network. */
|
|
81
129
|
verifyPolicy?: typeof verifyCloudCredentials;
|
|
82
130
|
verifyIngest?: typeof validateIngestKey;
|
|
131
|
+
introspect?: typeof introspectKey;
|
|
83
132
|
}
|
|
84
133
|
|
|
85
134
|
export interface CapabilityOutcome {
|
|
@@ -90,6 +139,8 @@ export interface CapabilityOutcome {
|
|
|
90
139
|
export interface ConnectOutcome {
|
|
91
140
|
policy: CapabilityOutcome & { policyCount?: number; generation?: number };
|
|
92
141
|
ingest: CapabilityOutcome;
|
|
142
|
+
/** Which organisation the key belongs to. Absent on a pre-introspect server. */
|
|
143
|
+
org?: { id?: string; slug?: string; name?: string };
|
|
93
144
|
/** True when at least one capability was configured. */
|
|
94
145
|
anyConfigured: boolean;
|
|
95
146
|
}
|
|
@@ -102,22 +153,81 @@ export interface ConnectOutcome {
|
|
|
102
153
|
* connection the machine does not have.
|
|
103
154
|
*/
|
|
104
155
|
export async function connectToCloud(input: ConnectInput): Promise<ConnectOutcome> {
|
|
156
|
+
// Checked HERE, not only at the call sites. `ConnectInput.url` is documented
|
|
157
|
+
// as "already validated by `validateCloudUrl`", and that was true of exactly
|
|
158
|
+
// one of the two callers: `--connect` validated, and the interactive wizard —
|
|
159
|
+
// the documented primary path — matched `/^https?:\/\//` and handed the raw
|
|
160
|
+
// string straight to `validateIngestKey` and then to here. So the flow most
|
|
161
|
+
// people use sent the machine's bearer token to any `http://` host in clear.
|
|
162
|
+
// A precondition worth stating in a docstring is worth enforcing at the
|
|
163
|
+
// boundary that depends on it.
|
|
164
|
+
const checked = validateCloudUrl(input.url);
|
|
165
|
+
if (!checked.ok) {
|
|
166
|
+
return {
|
|
167
|
+
policy: { ok: false, reason: checked.reason },
|
|
168
|
+
ingest: { ok: false, reason: checked.reason },
|
|
169
|
+
anyConfigured: false,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
105
173
|
const creds: CloudCredentials = {
|
|
106
174
|
url: input.url,
|
|
107
175
|
machineId: input.machineId,
|
|
108
176
|
token: input.token,
|
|
177
|
+
machineLabel: input.machineLabel,
|
|
109
178
|
};
|
|
110
179
|
|
|
111
180
|
const verifyPolicy = input.verifyPolicy ?? verifyCloudCredentials;
|
|
112
181
|
const verifyIngest = input.verifyIngest ?? validateIngestKey;
|
|
182
|
+
const introspect = input.introspect ?? introspectKey;
|
|
113
183
|
const ingestUrl = ingestUrlFor(input.url);
|
|
114
184
|
|
|
185
|
+
// ── Ask the key what it is, before using it for anything ──────────────────
|
|
186
|
+
//
|
|
187
|
+
// One request answers three questions that are otherwise indistinguishable
|
|
188
|
+
// until much later: is the key accepted, which ORG does it report into, and
|
|
189
|
+
// does it carry the permissions this machine needs. Probing the endpoints
|
|
190
|
+
// (below) can only ever answer the first, and only by inference.
|
|
191
|
+
//
|
|
192
|
+
// A rejected key stops here — probing two more endpoints with a credential
|
|
193
|
+
// the server has already refused tells us nothing and costs two more
|
|
194
|
+
// unauthenticated database lookups on a surface with no rate limiting.
|
|
195
|
+
const identity = await introspect(input.url, input.token);
|
|
196
|
+
if (identity.kind === "rejected") {
|
|
197
|
+
return {
|
|
198
|
+
policy: { ok: false, reason: "the server did not accept that key" },
|
|
199
|
+
ingest: { ok: false, reason: "the server did not accept that key" },
|
|
200
|
+
anyConfigured: false,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// `unsupported` — an AgentEye older than the introspect endpoint. Fall
|
|
205
|
+
// through to probing, which is what every release before this one did. The
|
|
206
|
+
// CLI ships independently of whatever server a customer runs, so a good key
|
|
207
|
+
// on an older deployment must still connect.
|
|
208
|
+
const known = identity.kind === "ok" ? identity.identity : null;
|
|
209
|
+
|
|
210
|
+
// Skip a probe the key provably cannot pass. This is not an optimisation: a
|
|
211
|
+
// permission failure surfaces from `/events` as a 403 whose message reads
|
|
212
|
+
// like a server problem, where introspect can say exactly which permission is
|
|
213
|
+
// missing and for which org.
|
|
214
|
+
const canIngest = known ? hasPermission(known, PERMISSION_EVENTS) : true;
|
|
215
|
+
const canPolicy = known ? hasPermission(known, PERMISSION_POLICIES) : true;
|
|
216
|
+
|
|
217
|
+
const missing = (permission: string) =>
|
|
218
|
+
`that key does not carry \`${permission}\`` +
|
|
219
|
+
(known ? ` (it is valid for ${describeOrg(known)})` : "");
|
|
220
|
+
|
|
115
221
|
// Both checks run regardless of the other's result: reporting "cannot pull
|
|
116
222
|
// policy" while staying silent about ingest would send someone to fix one
|
|
117
223
|
// permission and hit the next one afterwards.
|
|
118
224
|
const [policyResult, ingestResult] = await Promise.all([
|
|
119
|
-
|
|
120
|
-
|
|
225
|
+
canPolicy
|
|
226
|
+
? verifyPolicy(creds)
|
|
227
|
+
: Promise.resolve({ ok: false as const, reason: missing(PERMISSION_POLICIES) }),
|
|
228
|
+
canIngest
|
|
229
|
+
? verifyIngest({ url: ingestUrl, key: input.token })
|
|
230
|
+
: Promise.resolve({ ok: false as const, reason: missing(PERMISSION_EVENTS) }),
|
|
121
231
|
]);
|
|
122
232
|
|
|
123
233
|
const outcome: ConnectOutcome = {
|
|
@@ -126,28 +236,52 @@ export async function connectToCloud(input: ConnectInput): Promise<ConnectOutcom
|
|
|
126
236
|
: { ok: false, reason: policyResult.reason },
|
|
127
237
|
ingest: ingestResult.ok ? { ok: true } : { ok: false, reason: ingestResult.reason },
|
|
128
238
|
anyConfigured: false,
|
|
239
|
+
org: known
|
|
240
|
+
? { id: known.orgId, slug: known.orgSlug, name: known.orgName }
|
|
241
|
+
: undefined,
|
|
129
242
|
};
|
|
130
243
|
|
|
131
244
|
if (policyResult.ok) {
|
|
132
|
-
|
|
245
|
+
writeCloudCredentials(creds);
|
|
133
246
|
outcome.anyConfigured = true;
|
|
134
247
|
}
|
|
135
248
|
|
|
249
|
+
// Mode is the hard gate, set only once a capability actually verified.
|
|
250
|
+
// "cloud" is never inferred from a token merely being present: a machine
|
|
251
|
+
// that has not proven it can reach the server must stay provably silent.
|
|
252
|
+
if (policyResult.ok || ingestResult.ok) {
|
|
253
|
+
updateConfig({ mode: "cloud" });
|
|
254
|
+
}
|
|
255
|
+
|
|
136
256
|
if (ingestResult.ok) {
|
|
137
257
|
writeIngestCredential({ url: ingestUrl, key: input.token });
|
|
138
258
|
const settings: CollectorSettings = {
|
|
139
259
|
// Hook activity is what makes the dashboard show anything at all, and it
|
|
140
260
|
// carries decisions and tool names — never file contents.
|
|
141
261
|
hooks: true,
|
|
142
|
-
//
|
|
143
|
-
//
|
|
262
|
+
// Explicit only — see the `sessions` doc on ConnectInput. Callers decide
|
|
263
|
+
// the product default; this layer never infers one.
|
|
144
264
|
sessions: input.sessions === true,
|
|
145
265
|
environment: input.environment,
|
|
266
|
+
// So the daemon stamps this machine's id on every collected event and the
|
|
267
|
+
// dashboard groups by machine, not by per-project agent_id.
|
|
268
|
+
machineId: input.machineId,
|
|
146
269
|
};
|
|
147
270
|
writeCollectorSettings(settings);
|
|
148
271
|
outcome.anyConfigured = true;
|
|
149
272
|
}
|
|
150
273
|
|
|
274
|
+
// Last, and only once something actually configured: recording an org for a
|
|
275
|
+
// machine that connected to nothing would be a claim about where data goes
|
|
276
|
+
// from a machine that sends none. Merged into whatever the two writers above
|
|
277
|
+
// just wrote, so it cannot race them.
|
|
278
|
+
if (outcome.anyConfigured && known && (known.orgId || known.orgSlug || known.orgName)) {
|
|
279
|
+
writeCredentials({
|
|
280
|
+
...readCredentials(),
|
|
281
|
+
org: { id: known.orgId, slug: known.orgSlug, name: known.orgName },
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
151
285
|
return outcome;
|
|
152
286
|
}
|
|
153
287
|
|
|
@@ -161,8 +295,19 @@ export async function connectToCloud(input: ConnectInput): Promise<ConnectOutcom
|
|
|
161
295
|
export function describeOutcome(outcome: ConnectOutcome, machineId: string, url: string): string[] {
|
|
162
296
|
const lines: string[] = [];
|
|
163
297
|
|
|
298
|
+
// Named on every branch that connected, including the partial ones. A key
|
|
299
|
+
// pasted from the wrong organisation authenticates perfectly and reports into
|
|
300
|
+
// somewhere the user is not looking; the org is the only thing on screen that
|
|
301
|
+
// makes that visible, and it is worth nothing if it only prints on success.
|
|
302
|
+
const org = outcome.org
|
|
303
|
+
? outcome.org.name && outcome.org.slug
|
|
304
|
+
? `${outcome.org.name} (${outcome.org.slug})`
|
|
305
|
+
: (outcome.org.name ?? outcome.org.slug ?? outcome.org.id)
|
|
306
|
+
: undefined;
|
|
307
|
+
const into = org ? ` into ${org}` : "";
|
|
308
|
+
|
|
164
309
|
if (outcome.policy.ok && outcome.ingest.ok) {
|
|
165
|
-
lines.push(`Connected to ${url} as ${machineId}.`);
|
|
310
|
+
lines.push(`Connected to ${url} as ${machineId}${into}.`);
|
|
166
311
|
const n = outcome.policy.policyCount ?? 0;
|
|
167
312
|
lines.push(` Policy ${n} polic${n === 1 ? "y" : "ies"} assigned (generation ${outcome.policy.generation ?? 0}).`);
|
|
168
313
|
lines.push(` Dashboard hook activity will be sent to ${ingestUrlFor(url)}.`);
|
|
@@ -171,7 +316,7 @@ export function describeOutcome(outcome: ConnectOutcome, machineId: string, url:
|
|
|
171
316
|
|
|
172
317
|
if (outcome.policy.ok && !outcome.ingest.ok) {
|
|
173
318
|
const n = outcome.policy.policyCount ?? 0;
|
|
174
|
-
lines.push(`Connected to ${url} as ${machineId} for policy only.`);
|
|
319
|
+
lines.push(`Connected to ${url} as ${machineId}${into}, for policy only.`);
|
|
175
320
|
lines.push(` Policy ${n} polic${n === 1 ? "y" : "ies"} assigned (generation ${outcome.policy.generation ?? 0}).`);
|
|
176
321
|
lines.push(` Dashboard NOT configured: ${outcome.ingest.reason}`);
|
|
177
322
|
lines.push("");
|
|
@@ -181,7 +326,7 @@ export function describeOutcome(outcome: ConnectOutcome, machineId: string, url:
|
|
|
181
326
|
}
|
|
182
327
|
|
|
183
328
|
if (!outcome.policy.ok && outcome.ingest.ok) {
|
|
184
|
-
lines.push(`Connected to ${url} as ${machineId} for dashboard reporting only.`);
|
|
329
|
+
lines.push(`Connected to ${url} as ${machineId}${into}, for dashboard reporting only.`);
|
|
185
330
|
lines.push(` Dashboard hook activity will be sent to ${ingestUrlFor(url)}.`);
|
|
186
331
|
lines.push(` Cloud policy NOT configured: ${outcome.policy.reason}`);
|
|
187
332
|
lines.push("");
|
|
@@ -201,5 +346,9 @@ export function configuredPaths(outcome: ConnectOutcome): string[] {
|
|
|
201
346
|
const paths: string[] = [];
|
|
202
347
|
if (outcome.policy.ok) paths.push(cloudCredentialPath());
|
|
203
348
|
if (outcome.ingest.ok) paths.push(ingestPath());
|
|
204
|
-
|
|
349
|
+
// Deduplicated because layout 2 consolidated both credentials into
|
|
350
|
+
// `credentials.toml`, so the two capabilities now name the SAME file and the
|
|
351
|
+
// closing note read "stored in <path> and <path>" — the same path, twice.
|
|
352
|
+
// They stay two entries above because the JSON override can still split them.
|
|
353
|
+
return [...new Set(paths)];
|
|
205
354
|
}
|
|
@@ -6,12 +6,17 @@ import {
|
|
|
6
6
|
clearCloudCredentials,
|
|
7
7
|
maskToken,
|
|
8
8
|
readCloudCredentials,
|
|
9
|
+
resolveMachineId,
|
|
10
|
+
resolveMachineLabel,
|
|
9
11
|
validateCloudUrl,
|
|
10
12
|
verifyCloudCredentials,
|
|
11
13
|
writeCloudCredentials,
|
|
12
14
|
cloudCredentialPath,
|
|
13
15
|
} from "./cloud-enrollment";
|
|
14
|
-
import { daemonServiceStatus } from "./daemon-service";
|
|
16
|
+
import { daemonRestartCommand, daemonServiceStatus, daemonVersionSkew } from "./daemon-service";
|
|
17
|
+
import { clearActiveCloudManagedPolicies } from "./cloud-managed-policies";
|
|
18
|
+
import { readVersionFile, readCredentials } from "./fp-config";
|
|
19
|
+
import { version as cliVersion } from "../../package.json";
|
|
15
20
|
import { daemonSocketPresent } from "./daemon-client";
|
|
16
21
|
import {
|
|
17
22
|
cloudBaseFor,
|
|
@@ -26,23 +31,45 @@ import {
|
|
|
26
31
|
readIngestCredential,
|
|
27
32
|
validateIngestKey,
|
|
28
33
|
} from "./collector-config";
|
|
34
|
+
import { updateConfig } from "./fp-config";
|
|
35
|
+
import type { introspectKey } from "./cloud-introspect";
|
|
29
36
|
|
|
30
37
|
export interface ConnectOptions {
|
|
31
38
|
url?: string;
|
|
32
39
|
token?: string;
|
|
33
40
|
machineId?: string;
|
|
34
|
-
/** Defaults to the hostname
|
|
41
|
+
/** Human-facing display name for this machine. Defaults to the hostname. */
|
|
42
|
+
machineLabel?: string;
|
|
43
|
+
/**
|
|
44
|
+
* The hostname, passed in by the caller (and injected by tests). Used as the
|
|
45
|
+
* default machine *label*, no longer as the machine id — the id now mints or
|
|
46
|
+
* reuses a stable key so two hosts with the same hostname never merge.
|
|
47
|
+
*/
|
|
35
48
|
defaultMachineId?: string;
|
|
36
49
|
/**
|
|
37
|
-
* Send full session transcripts as well as hook decisions.
|
|
38
|
-
*
|
|
39
|
-
*
|
|
50
|
+
* Send full session transcripts as well as hook decisions.
|
|
51
|
+
*
|
|
52
|
+
* DEFAULTS ON. A transcript carries prompts, file contents and whatever was
|
|
53
|
+
* pasted into a terminal — which is precisely what makes a dashboard worth
|
|
54
|
+
* connecting to, so hiding it behind an opt-in produced the empty-dashboard
|
|
55
|
+
* problem in a different costume. `false` is the explicit opt-out; the
|
|
56
|
+
* disclosure is printed either way.
|
|
40
57
|
*/
|
|
41
58
|
sessions?: boolean;
|
|
42
59
|
environment?: string;
|
|
43
|
-
/**
|
|
60
|
+
/**
|
|
61
|
+
* Injected for tests so nothing reaches the network.
|
|
62
|
+
*
|
|
63
|
+
* All THREE must be here, and a new network call added below has to gain its
|
|
64
|
+
* seam in the same commit: `introspect` was added without one, so every test
|
|
65
|
+
* in `cloud-enrollment-cli.test.ts` silently began making a real request to
|
|
66
|
+
* `be.failproof.ai`. It usually failed fast enough to pass, which is the worst
|
|
67
|
+
* available outcome — the suite went intermittently red on network timing
|
|
68
|
+
* rather than on anything a change had broken.
|
|
69
|
+
*/
|
|
44
70
|
verify?: typeof verifyCloudCredentials;
|
|
45
71
|
verifyIngest?: typeof validateIngestKey;
|
|
72
|
+
introspect?: typeof introspectKey;
|
|
46
73
|
daemonStatus?: () => ReturnType<typeof daemonServiceStatus>;
|
|
47
74
|
}
|
|
48
75
|
|
|
@@ -116,10 +143,14 @@ export async function runConnectCommand(opts: ConnectOptions): Promise<CommandRe
|
|
|
116
143
|
const validated = validateCloudUrl(cloudBaseFor(opts.url));
|
|
117
144
|
if (!validated.ok) return { exitCode: 1, lines: [validated.reason] };
|
|
118
145
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
146
|
+
// The stable key: an explicit --machine-id wins, else the id already enrolled
|
|
147
|
+
// here is reused (idempotent re-connect), else a fresh one is minted. Never
|
|
148
|
+
// the hostname — that is the label, so same-hostname hosts do not merge.
|
|
149
|
+
const machineId = resolveMachineId(opts.machineId);
|
|
150
|
+
const machineLabel = resolveMachineLabel(opts.machineLabel ?? opts.defaultMachineId);
|
|
151
|
+
// Humans read the label; the id is shown in parentheses only when it differs,
|
|
152
|
+
// so an operator who set an explicit --machine-id still sees it.
|
|
153
|
+
const shownAs = machineLabel === machineId ? machineId : `${machineLabel} (${machineId})`;
|
|
123
154
|
|
|
124
155
|
// ONE connection, both capabilities. Each is verified before anything is
|
|
125
156
|
// written and reported on its own, because a key can carry `policies:pull`
|
|
@@ -128,14 +159,16 @@ export async function runConnectCommand(opts: ConnectOptions): Promise<CommandRe
|
|
|
128
159
|
url: validated.url,
|
|
129
160
|
token: opts.token,
|
|
130
161
|
machineId,
|
|
162
|
+
machineLabel,
|
|
131
163
|
sessions: opts.sessions,
|
|
132
164
|
environment: opts.environment,
|
|
133
165
|
verifyPolicy: opts.verify,
|
|
134
166
|
verifyIngest: opts.verifyIngest,
|
|
167
|
+
introspect: opts.introspect,
|
|
135
168
|
});
|
|
136
169
|
|
|
137
170
|
if (!outcome.anyConfigured) {
|
|
138
|
-
return { exitCode: 1, lines: describeOutcome(outcome,
|
|
171
|
+
return { exitCode: 1, lines: describeOutcome(outcome, shownAs, validated.url) };
|
|
139
172
|
}
|
|
140
173
|
|
|
141
174
|
// The exit code tracks the PRIMARY purpose — enrolling this machine for
|
|
@@ -149,13 +182,20 @@ export async function runConnectCommand(opts: ConnectOptions): Promise<CommandRe
|
|
|
149
182
|
const status = (opts.daemonStatus ?? daemonServiceStatus)();
|
|
150
183
|
const paths = configuredPaths(outcome);
|
|
151
184
|
const lines = [
|
|
152
|
-
...describeOutcome(outcome,
|
|
185
|
+
...describeOutcome(outcome, shownAs, validated.url),
|
|
153
186
|
` Token ${maskToken(opts.token)} stored in ${paths.join(" and ")} (owner-only).`,
|
|
154
187
|
];
|
|
155
|
-
if (outcome.ingest.ok
|
|
156
|
-
//
|
|
157
|
-
// transcripts
|
|
158
|
-
|
|
188
|
+
if (outcome.ingest.ok) {
|
|
189
|
+
// Stated on BOTH branches, never only on the surprising one. Connecting
|
|
190
|
+
// sends transcripts by default — prompts, file contents, command output —
|
|
191
|
+
// and a default that carries that much is one the user has to be told
|
|
192
|
+
// about at the moment it takes effect, not left to find in --help.
|
|
193
|
+
lines.push(
|
|
194
|
+
opts.sessions === false
|
|
195
|
+
? " Session transcripts are NOT being sent (--no-transcripts). Decisions only."
|
|
196
|
+
: " Sending policy decisions AND full session transcripts (prompts, file\n" +
|
|
197
|
+
" contents, command output). Use --no-transcripts for decisions only.",
|
|
198
|
+
);
|
|
159
199
|
}
|
|
160
200
|
lines.push(...daemonWarning(status));
|
|
161
201
|
|
|
@@ -170,24 +210,63 @@ export function runDisconnectCommand(): CommandResult {
|
|
|
170
210
|
// leave the machine still shipping activity to a cloud the user believes
|
|
171
211
|
// they have left — the one outcome nobody expects from this command.
|
|
172
212
|
const removedIngest = clearIngestCredential();
|
|
213
|
+
// Stop ENFORCING them too, not merely refreshing them. Clearing the
|
|
214
|
+
// credential ends the daemon's polling; every artifact already on disk stayed
|
|
215
|
+
// referenced by `active.json` and kept being loaded on every tool call — so a
|
|
216
|
+
// machine that had deliberately left its organisation went on being governed
|
|
217
|
+
// by whatever generation was current when it left, indefinitely, while
|
|
218
|
+
// `--status` reported it as unconnected.
|
|
219
|
+
const stoppedManaged = clearActiveCloudManagedPolicies();
|
|
220
|
+
// Back to OSS. Leaving mode = "cloud" with no credentials would describe a
|
|
221
|
+
// machine that does not exist, and every cloud code path keys off this flag
|
|
222
|
+
// rather than off "is a token lying around" precisely so that a disconnected
|
|
223
|
+
// machine is provably silent instead of silent-by-happenstance.
|
|
224
|
+
updateConfig({ mode: "oss" });
|
|
173
225
|
|
|
174
|
-
if (!removed && !existing && !hadIngest) {
|
|
226
|
+
if (!removed && !existing && !hadIngest && !stoppedManaged) {
|
|
175
227
|
return { exitCode: 0, lines: ["This machine is not connected to Failproof Cloud."] };
|
|
176
228
|
}
|
|
177
229
|
|
|
178
230
|
const lines = [
|
|
179
231
|
"Disconnected from Failproof Cloud.",
|
|
180
232
|
"",
|
|
181
|
-
|
|
182
|
-
|
|
233
|
+
stoppedManaged
|
|
234
|
+
? " Cloud-managed policies stop being enforced and stop being refreshed.\n" +
|
|
235
|
+
" Local builtin, custom and convention policies are unaffected."
|
|
236
|
+
: " Local builtin, custom and convention policies are unaffected.",
|
|
183
237
|
];
|
|
184
238
|
if (removedIngest) {
|
|
185
|
-
|
|
239
|
+
// Named honestly. The collector manager starts once for the daemon's
|
|
240
|
+
// lifetime (`main.rs`) and the uploader caches its bearer key at
|
|
241
|
+
// construction, so nothing already running notices this file disappear —
|
|
242
|
+
// "stop being sent" was true only of the NEXT daemon start. Telling the
|
|
243
|
+
// user the step that makes it true beats a claim that quietly is not.
|
|
244
|
+
lines.push(
|
|
245
|
+
" No new hook activity or transcripts will be queued. A running failproofaid",
|
|
246
|
+
" keeps the key it started with, so restart it to stop the current process",
|
|
247
|
+
` sending: ${daemonRestartCommand() ?? "restart failproofaid"}`,
|
|
248
|
+
);
|
|
186
249
|
}
|
|
187
250
|
return { exitCode: 0, lines };
|
|
188
251
|
}
|
|
189
252
|
|
|
190
253
|
/** The connection half of `--status`. Never prints the token. */
|
|
254
|
+
/**
|
|
255
|
+
* The version line for `--status`.
|
|
256
|
+
*
|
|
257
|
+
* First thing worth knowing in a bug report, and the only place a user can
|
|
258
|
+
* currently find out which daemon they are running without listing a directory.
|
|
259
|
+
*/
|
|
260
|
+
export function versionStatusLines(): string[] {
|
|
261
|
+
const skew = daemonVersionSkew();
|
|
262
|
+
const recorded = readVersionFile();
|
|
263
|
+
const daemon = recorded?.daemon ?? "not installed";
|
|
264
|
+
return [
|
|
265
|
+
`CLI ${cliVersion} · daemon ${daemon}${skew ? " (STALE)" : ""} · layout ${recorded?.layout ?? "-"}`,
|
|
266
|
+
...(skew ? [" Run `failproofai config` to update the daemon."] : []),
|
|
267
|
+
];
|
|
268
|
+
}
|
|
269
|
+
|
|
191
270
|
export function connectionStatusLines(daemonStatus = daemonServiceStatus): string[] {
|
|
192
271
|
const envUrl = process.env.FAILPROOFAI_CLOUD_URL;
|
|
193
272
|
if (envUrl) {
|
|
@@ -206,15 +285,34 @@ export function connectionStatusLines(daemonStatus = daemonServiceStatus): strin
|
|
|
206
285
|
// catch, and two unrelated lines made it easy to miss.
|
|
207
286
|
if (!creds && !ingest) return ["Cloud: not connected."];
|
|
208
287
|
|
|
288
|
+
// Recorded at connect time from the server's own answer, never guessed from
|
|
289
|
+
// the URL: one deployment hosts many orgs, so the host says nothing about
|
|
290
|
+
// which one this machine's data lands in. Absent against a server with no
|
|
291
|
+
// introspect endpoint, and on credentials written before this was recorded —
|
|
292
|
+
// in both cases the line is simply omitted rather than guessed at.
|
|
293
|
+
const org = readCredentials().org;
|
|
294
|
+
const orgLine = org
|
|
295
|
+
? org.name && org.slug
|
|
296
|
+
? `${org.name} (${org.slug})`
|
|
297
|
+
: (org.name ?? org.slug ?? org.id)
|
|
298
|
+
: undefined;
|
|
299
|
+
|
|
209
300
|
const lines: string[] = [];
|
|
210
301
|
if (creds) {
|
|
211
|
-
|
|
302
|
+
// Show the human label with the stable id in parentheses; fall back to the
|
|
303
|
+
// bare id for credentials written before labels existed.
|
|
304
|
+
const shownAs = creds.machineLabel
|
|
305
|
+
? `${creds.machineLabel} (${creds.machineId})`
|
|
306
|
+
: creds.machineId;
|
|
307
|
+
lines.push(`Cloud: connected to ${creds.url} as ${shownAs} (token ${maskToken(creds.token)}).`);
|
|
212
308
|
lines.push(` Policy pulling centrally-managed policies.`);
|
|
213
309
|
} else {
|
|
214
310
|
lines.push(`Cloud: connected to ${cloudBaseFor(ingest!.url)} for reporting only.`);
|
|
215
311
|
lines.push(` Policy NOT pulling — this machine enforces only its local policies.`);
|
|
216
312
|
}
|
|
217
313
|
|
|
314
|
+
if (orgLine) lines.push(` Org ${orgLine}`);
|
|
315
|
+
|
|
218
316
|
if (ingest) {
|
|
219
317
|
lines.push(` Dashboard sending hook activity to ${ingest.url}.`);
|
|
220
318
|
} else {
|