failproofai 1.0.0-beta.0 → 1.0.0-beta.10
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 +6 -6
- 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/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 +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/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 +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/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 +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/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 +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/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +30 -18
- package/.next/standalone/.next/server/app/policies/page.js +5 -3
- 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 +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/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 +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/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 +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]__0h9_83k._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[externals]__1nl3dvw._.js → [externals]__0r-zamh._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[externals]__1ifpkx-._.js +3 -0
- 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]__16le-kd._.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} +2 -2
- 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/node_modules_posthog-node_dist_entrypoints_index_node_mjs_01r25oi._.js +2 -1
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_09z9-p7._.js +2 -1
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[externals]__1aq139v._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04pwh4t._.js +3 -0
- 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]__170799-._.js → [root-of-the-server]__0spkm68._.js} +11 -11
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__10butu6._.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]__1qapotl._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1apb7k_._.js → [root-of-the-server]__1rdruw4._.js} +2 -2
- 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]__01od0m6._.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/_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/_1e19atl._.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/_1y4qr7u._.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/node_modules_posthog-node_dist_entrypoints_index_node_mjs_11bnuzn._.js +2 -1
- 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 +6 -6
- 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 +74 -20
- package/.next/standalone/.next/static/chunks/00adubtgov21s.js +1 -0
- package/.next/standalone/.next/static/chunks/{03fmihek9n986.js → 06zgzyh3wv1ig.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1hdhteui932bq.js → 0qmo2t50kpb30.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1grd7y94-igz9.js → 0yudogeqddpzr.js} +1 -1
- package/.next/standalone/.next/static/chunks/16p68cybetr31.js +1 -0
- package/.next/standalone/.next/static/chunks/1bm0q12hgs22l.css +2 -0
- package/.next/standalone/.next/static/chunks/{1d6ncspjagm53.js → 1fu90ch80qngv.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2vr7aazw6k2-n.js → 1m416lie3qwsj.js} +1 -1
- package/.next/standalone/.next/static/chunks/1v1gqvpjk62jm.js +1 -0
- package/.next/standalone/.next/static/chunks/1ypqzvoal8j56.js +6 -0
- package/.next/standalone/.next/static/chunks/23kev26by1e4f.js +1 -0
- package/.next/standalone/.next/static/chunks/{29k6ef49zppxj.js → 2h4sbmp0ad78w.js} +1 -1
- package/.next/standalone/.next/static/chunks/2obwg4tterjpa.js +1 -0
- package/.next/standalone/.next/static/chunks/2uvhw57mf9lg_.css +2 -0
- package/.next/standalone/.next/static/chunks/{29ydr-8q0zis6.js → 30ufy4_e2n78e.js} +22 -22
- package/.next/standalone/.next/static/chunks/31coz11ia5vc4.js +1 -0
- package/.next/standalone/.next/static/chunks/{1s-_swlc80y43.js → 3p4j0l1o_p-nm.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0ip1n8xmgxarv.js → 3uxnxwxcctyj0.js} +1 -1
- package/.next/standalone/.next/static/chunks/{turbopack-1lsv92x7klwrn.js → turbopack-3diub4ctvn1n0.js} +1 -1
- package/.next/standalone/app/actions/get-active-pauses.ts +16 -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/components/pause-notices.tsx +111 -0
- package/.next/standalone/app/policies/hooks-client.tsx +81 -6
- 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 +17 -10
- package/.next/standalone/proxy.ts +89 -1
- package/.next/standalone/server.js +1 -1
- package/bin/failproofai.mjs +518 -79
- package/dist/cli.mjs +11484 -6046
- package/dist/worker.mjs +2019 -272
- 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 +17 -10
- package/scripts/build-daemon-packages.mjs +210 -0
- package/scripts/daemon-platforms.mjs +42 -0
- 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 +26 -0
- package/scripts/publish-aliases.mjs +62 -41
- package/scripts/repro-npm-install.sh +155 -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/backfill-cli.ts +247 -0
- package/src/hooks/builtin-policies.ts +390 -2
- package/src/hooks/cloud-connection.ts +354 -0
- package/src/hooks/cloud-enrollment-cli.ts +325 -0
- package/src/hooks/cloud-enrollment.ts +243 -0
- package/src/hooks/cloud-introspect.ts +147 -0
- package/src/hooks/cloud-managed-policies.ts +169 -0
- package/src/hooks/collector-config.ts +234 -0
- package/src/hooks/configure-wizard.ts +915 -158
- package/src/hooks/custom-hooks-loader.ts +191 -33
- package/src/hooks/daemon-client.ts +136 -17
- package/src/hooks/daemon-download.ts +192 -30
- package/src/hooks/daemon-service.ts +1190 -92
- package/src/hooks/first-run-gate.ts +50 -0
- package/src/hooks/fp-config.ts +497 -0
- package/src/hooks/fp-home.ts +375 -0
- package/src/hooks/fp-reset.ts +464 -0
- package/src/hooks/handler.ts +185 -6
- package/src/hooks/hook-activity-store.ts +85 -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 +171 -8
- package/src/hooks/manager.ts +5 -4
- package/src/hooks/onboarding-attempt.ts +179 -0
- package/src/hooks/onboarding-lock.ts +119 -0
- package/src/hooks/policy-types.ts +28 -0
- package/src/hooks/session-pause-cli.ts +159 -0
- package/src/hooks/session-pause.ts +268 -0
- package/src/hooks/setup-state.ts +256 -0
- package/src/hooks/tui.ts +119 -4
- package/src/hooks/uninstall-cli.ts +345 -0
- package/src/hooks/worker-server.ts +65 -3
- package/.next/standalone/.next/server/chunks/[externals]__14odj07._.js +0 -3
- package/.next/standalone/.next/server/chunks/[externals]__1s61mel._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0id_xf7._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0longh-._.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/[externals]__1_g_b3t._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0114ewg._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0259h38._.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]__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]__0qucxyj._.js +0 -4
- 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]__0uno39i._.js +0 -3
- 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]__1ath6v_._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1zj-87g._.js +0 -3
- 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_1-upb14.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/0u9hc6oxx-gpj.js +0 -6
- package/.next/standalone/.next/static/chunks/0zbxssxh53n-3.js +0 -1
- package/.next/standalone/.next/static/chunks/2mazwb1qmur1p.js +0 -1
- package/.next/standalone/.next/static/chunks/2pujpnfx4pws6.css +0 -2
- package/.next/standalone/.next/static/chunks/33u59vf_8xpd-.js +0 -1
- package/.next/standalone/.next/static/chunks/3i27c3hcriawq.css +0 -1
- package/.next/standalone/.next/static/chunks/3wrgbih-516uj.js +0 -1
- package/.next/standalone/Cargo.lock +0 -428
- package/.next/standalone/Cargo.toml +0 -9
- package/.next/standalone/crates/PROTOCOL.md +0 -122
- package/.next/standalone/crates/failproofaid/Cargo.toml +0 -18
- package/.next/standalone/crates/failproofaid/src/lock.rs +0 -81
- package/.next/standalone/crates/failproofaid/src/main.rs +0 -83
- package/.next/standalone/crates/failproofaid/src/paths.rs +0 -172
- 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-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/{7Lxtd352rSaHB-pmm6G8M → pBBcTvE6_VueYGbacy1kg}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{7Lxtd352rSaHB-pmm6G8M → pBBcTvE6_VueYGbacy1kg}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{7Lxtd352rSaHB-pmm6G8M → pBBcTvE6_VueYGbacy1kg}/_ssgManifest.js +0 -0
package/src/hooks/tui.ts
CHANGED
|
@@ -112,10 +112,10 @@ export function colorsEnabled(out: TTYOut): boolean {
|
|
|
112
112
|
|
|
113
113
|
/**
|
|
114
114
|
* The raw ANSI opening sequence for a brand role, for callers that assemble
|
|
115
|
-
* their own strings instead of using `paint()`'s wrappers (`src/audit/cli.ts
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
115
|
+
* their own strings instead of using `paint()`'s wrappers (`src/audit/cli.ts`).
|
|
116
|
+
* That file previously hardcoded its own 256-colour palette — a green and a
|
|
117
|
+
* blue that appear nowhere in the brand — so `audit` looked like a different
|
|
118
|
+
* product from `config`. Routing it here
|
|
119
119
|
* keeps HUES the single source of truth: change a hue once and every surface
|
|
120
120
|
* follows. Emits truecolor where the terminal advertises it, basic ANSI
|
|
121
121
|
* otherwise; the caller still decides *whether* to colour at all.
|
|
@@ -643,3 +643,118 @@ export function multiSelect<T>(opts: MultiSelectOptions<T>): Promise<T[] | null>
|
|
|
643
643
|
),
|
|
644
644
|
});
|
|
645
645
|
}
|
|
646
|
+
|
|
647
|
+
// ── promptText (single line, optionally masked) ───────────────────────────────
|
|
648
|
+
|
|
649
|
+
export interface PromptTextOptions {
|
|
650
|
+
message: string;
|
|
651
|
+
/** Shown dimmed under the prompt. */
|
|
652
|
+
hint?: string;
|
|
653
|
+
/** Used when the user submits an empty line. */
|
|
654
|
+
defaultValue?: string;
|
|
655
|
+
/**
|
|
656
|
+
* Render `•` instead of the typed characters. For credentials: the wizard is
|
|
657
|
+
* routinely run while screen-sharing, and a pasted key would otherwise sit in
|
|
658
|
+
* the scrollback of every recording of that session.
|
|
659
|
+
*/
|
|
660
|
+
mask?: boolean;
|
|
661
|
+
/** Return an error string to reject and re-ask, or null to accept. */
|
|
662
|
+
validate?: (value: string) => string | null;
|
|
663
|
+
stdin?: TTYIn;
|
|
664
|
+
stdout?: TTYOut;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Read one line. Resolves `null` on Ctrl-C / Escape, which every caller in the
|
|
669
|
+
* wizard treats as "cancel the whole run" — consistent with selectOne.
|
|
670
|
+
*
|
|
671
|
+
* Falls back to a plain non-TTY read so `failproofai config` still works when
|
|
672
|
+
* driven from a pipe or a test, the same way the other prompts do.
|
|
673
|
+
*/
|
|
674
|
+
export function promptText(opts: PromptTextOptions): Promise<string | null> {
|
|
675
|
+
const stdin: TTYIn = opts.stdin ?? process.stdin;
|
|
676
|
+
const stdout: TTYOut = opts.stdout ?? process.stdout;
|
|
677
|
+
const c = paint(colorsEnabled(stdout));
|
|
678
|
+
|
|
679
|
+
const accept = (raw: string): { ok: true; value: string } | { ok: false; error: string } => {
|
|
680
|
+
const value = raw.trim() || opts.defaultValue || "";
|
|
681
|
+
const error = opts.validate?.(value) ?? null;
|
|
682
|
+
return error ? { ok: false, error } : { ok: true, value };
|
|
683
|
+
};
|
|
684
|
+
|
|
685
|
+
if (!stdin.isTTY) {
|
|
686
|
+
// Non-TTY: read whatever is piped, validate once, no re-ask loop (there is
|
|
687
|
+
// no one to re-ask).
|
|
688
|
+
return new Promise((resolve) => {
|
|
689
|
+
let buf = "";
|
|
690
|
+
const onData = (chunk: Buffer | string) => {
|
|
691
|
+
buf += String(chunk);
|
|
692
|
+
if (buf.includes("\n")) done();
|
|
693
|
+
};
|
|
694
|
+
const done = () => {
|
|
695
|
+
stdin.removeListener("data", onData);
|
|
696
|
+
stdin.removeListener("end", done);
|
|
697
|
+
const r = accept(buf.split("\n")[0] ?? "");
|
|
698
|
+
resolve(r.ok ? r.value : null);
|
|
699
|
+
};
|
|
700
|
+
stdin.on("data", onData);
|
|
701
|
+
stdin.on("end", done);
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
return new Promise((resolve) => {
|
|
706
|
+
let value = "";
|
|
707
|
+
const draw = (error?: string) => {
|
|
708
|
+
const shown = opts.mask ? "•".repeat(value.length) : value;
|
|
709
|
+
const hint = opts.hint ? ` ${c.dim(opts.hint)}` : "";
|
|
710
|
+
const err = error ? `\n ${c.warn(error)}` : "";
|
|
711
|
+
stdout.write(`\r\x1b[2K${c.bold(opts.message)} ${shown}${hint}${err}`);
|
|
712
|
+
if (err) stdout.write("\x1b[1A");
|
|
713
|
+
};
|
|
714
|
+
draw();
|
|
715
|
+
|
|
716
|
+
readline.emitKeypressEvents(stdin);
|
|
717
|
+
const wasRaw = stdin.isRaw;
|
|
718
|
+
stdin.setRawMode?.(true);
|
|
719
|
+
stdin.resume();
|
|
720
|
+
|
|
721
|
+
const cleanup = () => {
|
|
722
|
+
stdin.removeListener("keypress", onKey);
|
|
723
|
+
stdin.setRawMode?.(wasRaw ?? false);
|
|
724
|
+
stdin.pause();
|
|
725
|
+
stdout.write("\n");
|
|
726
|
+
};
|
|
727
|
+
|
|
728
|
+
function onKey(str: string | undefined, key: readline.Key): void {
|
|
729
|
+
if (!key) return;
|
|
730
|
+
if ((key.ctrl && (key.name === "c" || key.name === "d")) || key.name === "escape") {
|
|
731
|
+
cleanup();
|
|
732
|
+
resolve(null);
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
if (key.name === "return" || key.name === "enter") {
|
|
736
|
+
const r = accept(value);
|
|
737
|
+
if (r.ok) {
|
|
738
|
+
cleanup();
|
|
739
|
+
resolve(r.value);
|
|
740
|
+
} else {
|
|
741
|
+
draw(r.error);
|
|
742
|
+
}
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
if (key.name === "backspace") {
|
|
746
|
+
value = value.slice(0, -1);
|
|
747
|
+
draw();
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
// Ignore control keys; accept any printable character, including a
|
|
751
|
+
// bracketed paste arriving as one chunk.
|
|
752
|
+
if (str && !key.ctrl && !key.meta) {
|
|
753
|
+
value += str;
|
|
754
|
+
draw();
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
stdin.on("keypress", onKey);
|
|
759
|
+
});
|
|
760
|
+
}
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `failproofai uninstall` — the sanctioned way off this machine.
|
|
3
|
+
*
|
|
4
|
+
* It exists because npm cannot do it. npm runs NO uninstall script (this repo
|
|
5
|
+
* proved that empirically and deleted the dead `preuninstall` that assumed
|
|
6
|
+
* otherwise), so `npm rm -g failproofai` deletes the package and leaves behind
|
|
7
|
+
* every durable thing the package installed: hook entries in up to twelve agent
|
|
8
|
+
* CLIs' settings files, and a root-owned systemd unit.
|
|
9
|
+
*
|
|
10
|
+
* That leftovers set is not inert. The hook entries invoke `npx -y failproofai`,
|
|
11
|
+
* which happily re-downloads the package from the registry — so a "removed"
|
|
12
|
+
* failproofai keeps running on every tool call. And on a machine with
|
|
13
|
+
* `[daemon] configured = true`, the surviving unit points at a worker script
|
|
14
|
+
* that npm just deleted, which under fail-closed semantics denies EVERY tool
|
|
15
|
+
* call across every agent CLI, with nothing on screen naming the cause.
|
|
16
|
+
*
|
|
17
|
+
* ORDER IS THE SAFETY PROPERTY HERE, and it is not the obvious one.
|
|
18
|
+
*
|
|
19
|
+
* `daemonConfigured` is cleared FIRST — before hooks, before the service, before
|
|
20
|
+
* anything that can fail or need a password. From that instant the machine can
|
|
21
|
+
* only fail OPEN: policies evaluate in-process, and every later step is
|
|
22
|
+
* best-effort cleanup. Doing it in the intuitive order (tear the service down,
|
|
23
|
+
* then update config) leaves a window where the flag demands a daemon that is
|
|
24
|
+
* already gone, and that window is a total lockout of the user's agent — the
|
|
25
|
+
* exact failure `healDaemonFlag` was written to repair after it bricked a
|
|
26
|
+
* machine during development.
|
|
27
|
+
*
|
|
28
|
+
* Nothing here is silent about failure. A step that cannot complete (no sudo,
|
|
29
|
+
* an unwritable settings file) is reported with the command to finish it by
|
|
30
|
+
* hand, and the exit code says whether anything was left behind — because the
|
|
31
|
+
* one thing worse than a leftover unit is a leftover unit the operator was told
|
|
32
|
+
* did not exist.
|
|
33
|
+
*/
|
|
34
|
+
import { existsSync, rmSync } from "node:fs";
|
|
35
|
+
|
|
36
|
+
import { failproofaiHome } from "./fp-home";
|
|
37
|
+
import { readConfig } from "./fp-config";
|
|
38
|
+
import {
|
|
39
|
+
daemonServiceFilePath,
|
|
40
|
+
daemonServiceStatus,
|
|
41
|
+
daemonStatusCommand,
|
|
42
|
+
isDaemonSupportedPlatform,
|
|
43
|
+
setDaemonConfigured,
|
|
44
|
+
uninstallDaemonService,
|
|
45
|
+
} from "./daemon-service";
|
|
46
|
+
import { listInstallableIds, getIntegration } from "./integrations";
|
|
47
|
+
import type { IntegrationType } from "./types";
|
|
48
|
+
import { removeHooks } from "./manager";
|
|
49
|
+
|
|
50
|
+
export interface UninstallOptions {
|
|
51
|
+
/** Also delete ~/.failproofai (config, credentials, state, audit cache, daemon binary). */
|
|
52
|
+
purge?: boolean;
|
|
53
|
+
/** Report what would change and touch nothing. */
|
|
54
|
+
dryRun?: boolean;
|
|
55
|
+
/** Proceed without the interactive confirmation. */
|
|
56
|
+
yes?: boolean;
|
|
57
|
+
/** Project/local scopes are read relative to here. */
|
|
58
|
+
cwd?: string;
|
|
59
|
+
/**
|
|
60
|
+
* Injected so the decision is testable without a TTY. Absent means "no
|
|
61
|
+
* confirmation available", which is a REFUSAL rather than an assumed yes —
|
|
62
|
+
* see the non-interactive branch.
|
|
63
|
+
*/
|
|
64
|
+
confirm?: (lines: string[]) => Promise<boolean>;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface UninstallResult {
|
|
68
|
+
exitCode: number;
|
|
69
|
+
lines: string[];
|
|
70
|
+
/**
|
|
71
|
+
* How many leading entries of `lines` are the plan — the block already handed
|
|
72
|
+
* to `confirm`.
|
|
73
|
+
*
|
|
74
|
+
* Returned rather than inferred so the caller can skip re-printing it without
|
|
75
|
+
* pattern-matching its own output. A caller that guesses (by searching for a
|
|
76
|
+
* blank line, say) silently prints the whole plan twice the day a message
|
|
77
|
+
* above it gains one.
|
|
78
|
+
*/
|
|
79
|
+
planLines: number;
|
|
80
|
+
/**
|
|
81
|
+
* Whether `~/.failproofai` was actually deleted.
|
|
82
|
+
*
|
|
83
|
+
* The caller needs this to know that NOTHING may touch the home afterwards.
|
|
84
|
+
* Telemetry is the trap: `getInstanceId()` lazily writes
|
|
85
|
+
* `state/telemetry-id`, so a routine post-command event re-created the whole
|
|
86
|
+
* directory seconds after the purge reported deleting it — leaving a machine
|
|
87
|
+
* the user had just wiped holding a brand-new tracking identifier, and the
|
|
88
|
+
* command's own "✓ deleted" line a lie. Caught by the container test, which
|
|
89
|
+
* checked the filesystem rather than the output.
|
|
90
|
+
*/
|
|
91
|
+
purged: boolean;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Everything this machine has that uninstalling would remove. */
|
|
95
|
+
interface Leftovers {
|
|
96
|
+
clis: IntegrationType[];
|
|
97
|
+
servicePath: string | null;
|
|
98
|
+
serviceInstalled: boolean;
|
|
99
|
+
daemonConfigured: boolean;
|
|
100
|
+
homeExists: boolean;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function survey(cwd?: string): Leftovers {
|
|
104
|
+
const clis: IntegrationType[] = [];
|
|
105
|
+
// Every INSTALLABLE cli, not every DETECTED one. A CLI can be uninstalled
|
|
106
|
+
// after failproofai wrote hooks into its settings file, and those entries are
|
|
107
|
+
// exactly the orphans this command exists to clear — surveying only what is
|
|
108
|
+
// currently on PATH would walk straight past them.
|
|
109
|
+
for (const id of listInstallableIds()) {
|
|
110
|
+
for (const scope of ["user", "project", "local"] as const) {
|
|
111
|
+
try {
|
|
112
|
+
if (getIntegration(id).hooksInstalledInSettings(scope, cwd)) {
|
|
113
|
+
clis.push(id);
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
} catch {
|
|
117
|
+
// An unreadable or malformed settings file is not proof of absence, but
|
|
118
|
+
// it is not proof of presence either, and `removeHooks` will report its
|
|
119
|
+
// own failure against it later with a better message than a guess here.
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
let daemonConfigured = false;
|
|
125
|
+
try {
|
|
126
|
+
daemonConfigured = readConfig().daemon.configured;
|
|
127
|
+
} catch {
|
|
128
|
+
/* no config = nothing configured */
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const servicePath = isDaemonSupportedPlatform() ? daemonServiceFilePath() : null;
|
|
132
|
+
return {
|
|
133
|
+
clis,
|
|
134
|
+
servicePath,
|
|
135
|
+
serviceInstalled: !!servicePath && existsSync(servicePath),
|
|
136
|
+
daemonConfigured,
|
|
137
|
+
homeExists: existsSync(failproofaiHome()),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export async function runUninstallCommand(opts: UninstallOptions = {}): Promise<UninstallResult> {
|
|
142
|
+
const found = survey(opts.cwd);
|
|
143
|
+
const lines: string[] = [];
|
|
144
|
+
|
|
145
|
+
const nothingToDo =
|
|
146
|
+
found.clis.length === 0 && !found.serviceInstalled && !found.daemonConfigured &&
|
|
147
|
+
!(opts.purge && found.homeExists);
|
|
148
|
+
if (nothingToDo) {
|
|
149
|
+
return {
|
|
150
|
+
exitCode: 0,
|
|
151
|
+
planLines: 0,
|
|
152
|
+
purged: false,
|
|
153
|
+
lines: [
|
|
154
|
+
"Nothing to uninstall — no hook entries, no daemon service, and nothing configured.",
|
|
155
|
+
...(found.homeExists && !opts.purge
|
|
156
|
+
? [``, `${failproofaiHome()} still holds settings and audit history.`,
|
|
157
|
+
`Remove it with \`failproofai uninstall --purge\`.`]
|
|
158
|
+
: []),
|
|
159
|
+
],
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// The plan is shown before anything happens and is the same text the
|
|
164
|
+
// confirmation asks about, so what is agreed to and what is done cannot drift.
|
|
165
|
+
const plan: string[] = [];
|
|
166
|
+
if (found.clis.length > 0) {
|
|
167
|
+
plan.push(
|
|
168
|
+
` • remove failproofai hook entries from ${found.clis.length} agent CLI${found.clis.length === 1 ? "" : "s"}: ` +
|
|
169
|
+
found.clis.map((id) => getIntegration(id).displayName ?? id).join(", "),
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
if (found.daemonConfigured) {
|
|
173
|
+
plan.push(` • stop requiring the daemon (policies go back to evaluating in-process)`);
|
|
174
|
+
}
|
|
175
|
+
if (found.serviceInstalled) {
|
|
176
|
+
plan.push(` • stop, disable and delete the service at ${found.servicePath} — needs sudo`);
|
|
177
|
+
}
|
|
178
|
+
let purged = false;
|
|
179
|
+
if (opts.purge && found.homeExists) {
|
|
180
|
+
plan.push(` • delete ${failproofaiHome()} — settings, credentials, audit history and the daemon binary`);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
lines.push("failproofai uninstall will:", ...plan);
|
|
184
|
+
if (!opts.purge && found.homeExists) {
|
|
185
|
+
lines.push(
|
|
186
|
+
``,
|
|
187
|
+
`${failproofaiHome()} is KEPT (settings and audit history survive a reinstall).`,
|
|
188
|
+
`Add --purge to delete it too.`,
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
// Everything pushed so far IS the plan; `confirm` is shown exactly this.
|
|
192
|
+
const planLines = lines.length;
|
|
193
|
+
|
|
194
|
+
if (opts.dryRun) {
|
|
195
|
+
lines.push(``, `--dry-run: nothing was changed.`);
|
|
196
|
+
return { exitCode: 0, lines, planLines, purged: false };
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (!opts.yes) {
|
|
200
|
+
// No confirmation channel and no --yes is a REFUSAL, never an assumed yes.
|
|
201
|
+
// This runs in scripts and CI, where a prompt that cannot be answered would
|
|
202
|
+
// otherwise read as consent to delete a root-owned service.
|
|
203
|
+
if (!opts.confirm) {
|
|
204
|
+
lines.push(``, `Refusing to uninstall without confirmation. Re-run with --yes.`);
|
|
205
|
+
return { exitCode: 1, lines, planLines, purged: false };
|
|
206
|
+
}
|
|
207
|
+
if (!(await opts.confirm(lines))) {
|
|
208
|
+
return { exitCode: 1, planLines, purged: false, lines: [...lines, ``, `Cancelled — nothing was changed.`] };
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
lines.push(``);
|
|
213
|
+
const failures: string[] = [];
|
|
214
|
+
|
|
215
|
+
// STEP 1, and it must stay step 1. See the header: from here the machine can
|
|
216
|
+
// only fail open, so every remaining step is cleanup rather than a step that
|
|
217
|
+
// can lock anybody out by failing halfway.
|
|
218
|
+
if (found.daemonConfigured) {
|
|
219
|
+
try {
|
|
220
|
+
setDaemonConfigured(false);
|
|
221
|
+
lines.push(`✓ policies now evaluate in-process (this machine no longer requires the daemon)`);
|
|
222
|
+
} catch (err) {
|
|
223
|
+
// Uniquely fatal: everything after this assumes the flag is down. Removing
|
|
224
|
+
// the service while it is still up is the lockout this command exists to
|
|
225
|
+
// prevent, so stop rather than press on.
|
|
226
|
+
return {
|
|
227
|
+
exitCode: 2,
|
|
228
|
+
planLines,
|
|
229
|
+
purged: false,
|
|
230
|
+
lines: [
|
|
231
|
+
...lines,
|
|
232
|
+
`✗ could not update ${failproofaiHome()}/config.toml: ${err instanceof Error ? err.message : String(err)}`,
|
|
233
|
+
``,
|
|
234
|
+
`Stopped before touching the service. Removing it while this machine still`,
|
|
235
|
+
`requires it would deny every tool call. Fix the file's permissions and re-run.`,
|
|
236
|
+
],
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (found.clis.length > 0) {
|
|
242
|
+
try {
|
|
243
|
+
// Scope "all" and every cli that HAS entries — the same list the plan
|
|
244
|
+
// named. `removeCustomHooks` clears the configured custom-policy paths as
|
|
245
|
+
// well; leaving them behind would point a reinstall at files this command
|
|
246
|
+
// may be about to purge.
|
|
247
|
+
await removeHooks(undefined, "all", opts.cwd, {
|
|
248
|
+
cli: found.clis,
|
|
249
|
+
removeCustomHooks: true,
|
|
250
|
+
source: "uninstall_command",
|
|
251
|
+
});
|
|
252
|
+
lines.push(`✓ removed hook entries from ${found.clis.length} agent CLI${found.clis.length === 1 ? "" : "s"}`);
|
|
253
|
+
} catch (err) {
|
|
254
|
+
failures.push(
|
|
255
|
+
`hook entries: ${err instanceof Error ? err.message : String(err)} ` +
|
|
256
|
+
`(finish with \`failproofai policies --uninstall --scope all\`)`,
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (found.serviceInstalled) {
|
|
262
|
+
try {
|
|
263
|
+
await uninstallDaemonService();
|
|
264
|
+
// uninstallDaemonService is best-effort by contract — it warns and
|
|
265
|
+
// returns rather than throwing when it cannot elevate — so the unit file
|
|
266
|
+
// is what gets believed here, not the absence of an exception.
|
|
267
|
+
if (found.servicePath && existsSync(found.servicePath)) {
|
|
268
|
+
failures.push(
|
|
269
|
+
`the service at ${found.servicePath} is still there (most often: no sudo). ` +
|
|
270
|
+
`Remove it with the commands below.`,
|
|
271
|
+
);
|
|
272
|
+
} else {
|
|
273
|
+
lines.push(`✓ stopped and removed the daemon service`);
|
|
274
|
+
}
|
|
275
|
+
} catch (err) {
|
|
276
|
+
failures.push(`daemon service: ${err instanceof Error ? err.message : String(err)}`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (opts.purge && found.homeExists) {
|
|
281
|
+
// Last, and only after the service is down: the daemon binary and its
|
|
282
|
+
// socket live here, and deleting them out from under a running unit is how
|
|
283
|
+
// a clean uninstall turns into a restart loop.
|
|
284
|
+
try {
|
|
285
|
+
rmSync(failproofaiHome(), { recursive: true, force: true });
|
|
286
|
+
purged = true;
|
|
287
|
+
lines.push(`✓ deleted ${failproofaiHome()}`);
|
|
288
|
+
} catch (err) {
|
|
289
|
+
failures.push(`${failproofaiHome()}: ${err instanceof Error ? err.message : String(err)}`);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (failures.length > 0) {
|
|
294
|
+
lines.push(``, `Not everything could be removed:`);
|
|
295
|
+
for (const f of failures) lines.push(` ✗ ${f}`);
|
|
296
|
+
if (found.servicePath && existsSync(found.servicePath)) {
|
|
297
|
+
lines.push(
|
|
298
|
+
``,
|
|
299
|
+
`To remove the service by hand:`,
|
|
300
|
+
...manualServiceRemoval(found.servicePath),
|
|
301
|
+
``,
|
|
302
|
+
`(\`${daemonStatusCommand()}\` shows its current state.)`,
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
// Exit 1, not 0: enforcement is off (step 1 succeeded, or there was nothing
|
|
306
|
+
// to clear), but something durable is still installed and the operator has
|
|
307
|
+
// to act. A 0 here is what makes people believe a machine is clean when a
|
|
308
|
+
// root-owned unit is still on it.
|
|
309
|
+
return { exitCode: 1, lines, planLines, purged };
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
lines.push(
|
|
313
|
+
``,
|
|
314
|
+
`Done. failproofai no longer enforces anything on this machine.`,
|
|
315
|
+
``,
|
|
316
|
+
`The npm package itself is still installed — npm runs no uninstall script, which`,
|
|
317
|
+
`is why this command exists. Remove it with:`,
|
|
318
|
+
` npm rm -g failproofai`,
|
|
319
|
+
);
|
|
320
|
+
if (!opts.purge && found.homeExists) {
|
|
321
|
+
lines.push(``, `${failproofaiHome()} was kept. Delete it with \`failproofai uninstall --purge\`.`);
|
|
322
|
+
}
|
|
323
|
+
return { exitCode: 0, lines, planLines, purged };
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/** The exact commands to finish a service removal that could not elevate. */
|
|
327
|
+
function manualServiceRemoval(servicePath: string): string[] {
|
|
328
|
+
if (process.platform === "darwin") {
|
|
329
|
+
return [` sudo launchctl unload -w ${servicePath}`, ` sudo rm -f ${servicePath}`];
|
|
330
|
+
}
|
|
331
|
+
const unit = servicePath.split("/").pop() ?? servicePath;
|
|
332
|
+
return [
|
|
333
|
+
` sudo systemctl disable --now ${unit}`,
|
|
334
|
+
` sudo rm -f ${servicePath}`,
|
|
335
|
+
` sudo systemctl daemon-reload`,
|
|
336
|
+
];
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/** What `daemonServiceStatus()` says, for the status line the CLI prints. */
|
|
340
|
+
export function serviceStateLabel(): string {
|
|
341
|
+
const status = daemonServiceStatus();
|
|
342
|
+
return status === "condition-failed"
|
|
343
|
+
? "installed but skipped by systemd (a file it needs is missing)"
|
|
344
|
+
: status;
|
|
345
|
+
}
|
|
@@ -43,7 +43,15 @@ function isWorkerHookRequest(msg: unknown): msg is WorkerHookRequest {
|
|
|
43
43
|
typeof m.hookEvent === "string" &&
|
|
44
44
|
typeof m.cli === "string" &&
|
|
45
45
|
typeof m.stdin === "string" &&
|
|
46
|
-
|
|
46
|
+
// `null` as well as `undefined`. `cwd` is `Option<String>` on the wire, and
|
|
47
|
+
// the daemon forwards it with `json!({ "cwd": cwd })`, which serialises
|
|
48
|
+
// `None` as an explicit NULL rather than omitting the key. Accepting only
|
|
49
|
+
// `undefined` therefore rejected every request that legitimately carried no
|
|
50
|
+
// cwd — including the setup health probe, which sends none, so
|
|
51
|
+
// `failproofai config` aborted with "its worker process could not be run"
|
|
52
|
+
// against a daemon and worker that were both perfectly healthy. On a
|
|
53
|
+
// daemonConfigured machine the same mismatch denies the tool call.
|
|
54
|
+
(m.cwd === undefined || m.cwd === null || typeof m.cwd === "string")
|
|
47
55
|
);
|
|
48
56
|
}
|
|
49
57
|
|
|
@@ -54,15 +62,67 @@ function encodeFrame(value: unknown): Buffer {
|
|
|
54
62
|
return Buffer.concat([header, body]);
|
|
55
63
|
}
|
|
56
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Last-resort deadline on a single queued task.
|
|
67
|
+
*
|
|
68
|
+
* Deliberately far above `daemon-client.ts`'s 30s `DAEMON_RESPONSE_TIMEOUT_MS`:
|
|
69
|
+
* by the time this fires the client has long since given up and fail-closed, so
|
|
70
|
+
* nothing legitimate is waiting. It exists only to detect a task that will never
|
|
71
|
+
* settle at all.
|
|
72
|
+
*/
|
|
73
|
+
const TASK_DEADLINE_MS = 60_000;
|
|
74
|
+
|
|
57
75
|
/**
|
|
58
76
|
* Serializes every request across every connection through one chain, so
|
|
59
77
|
* `evaluateHookEvent` calls never overlap. `.catch()` on each link keeps the
|
|
60
78
|
* chain alive even if a handler throws unexpectedly — one bad request must
|
|
61
79
|
* never wedge every request queued behind it.
|
|
80
|
+
*
|
|
81
|
+
* `.catch()` covers a task that REJECTS. It does nothing for one that never
|
|
82
|
+
* SETTLES, and that state is reachable: a policy file with a top-level `await`
|
|
83
|
+
* that never resolves hangs its `import()`, so the task neither resolves nor
|
|
84
|
+
* rejects and every hook queued behind it waits forever. Each client then burns
|
|
85
|
+
* its own 30s budget and fail-closed denies — every tool call, every CLI on the
|
|
86
|
+
* machine, until someone restarts the daemon. This is a class the warm worker
|
|
87
|
+
* creates: in the one-shot path the identical file hangs one hook process and
|
|
88
|
+
* the agent CLI's own timeout reaps it.
|
|
89
|
+
*
|
|
90
|
+
* `custom-hooks-loader.ts` bounds that import directly, which is the graceful
|
|
91
|
+
* fix and covers the known cause. This is the backstop for the ones nobody
|
|
92
|
+
* thought of, and it EXITS rather than continuing: the orphaned task is still
|
|
93
|
+
* running and still holds the `globalThis` policy registry this chain exists to
|
|
94
|
+
* serialize access to, so letting the next request proceed would trade a wedge
|
|
95
|
+
* for silent cross-request registry corruption. Exiting hands the supervisor a
|
|
96
|
+
* process it will respawn clean (`worker.rs`'s `ensure_started` respawns a
|
|
97
|
+
* worker whose `try_wait()` reports it gone), which costs one cold start and
|
|
98
|
+
* denies the in-flight requests — the same fail-closed outcome they were headed
|
|
99
|
+
* for anyway, but recovered on the next call instead of never.
|
|
62
100
|
*/
|
|
101
|
+
const WEDGED_EXIT_CODE = 75;
|
|
102
|
+
|
|
63
103
|
let processingChain: Promise<void> = Promise.resolve();
|
|
64
104
|
function enqueue(task: () => Promise<void>): void {
|
|
65
|
-
processingChain = processingChain
|
|
105
|
+
processingChain = processingChain
|
|
106
|
+
.then(
|
|
107
|
+
() =>
|
|
108
|
+
new Promise<void>((settle) => {
|
|
109
|
+
const timer = setTimeout(() => {
|
|
110
|
+
hookLogWarn(
|
|
111
|
+
`worker: a request did not settle within ${TASK_DEADLINE_MS}ms; ` +
|
|
112
|
+
`exiting so the supervisor can respawn a clean worker`,
|
|
113
|
+
);
|
|
114
|
+
process.exit(WEDGED_EXIT_CODE);
|
|
115
|
+
}, TASK_DEADLINE_MS);
|
|
116
|
+
// Never let the deadline itself hold the event loop open.
|
|
117
|
+
timer.unref?.();
|
|
118
|
+
const done = () => {
|
|
119
|
+
clearTimeout(timer);
|
|
120
|
+
settle();
|
|
121
|
+
};
|
|
122
|
+
void task().then(done, done);
|
|
123
|
+
}),
|
|
124
|
+
)
|
|
125
|
+
.catch(() => {});
|
|
66
126
|
}
|
|
67
127
|
|
|
68
128
|
function handleConnection(socket: Socket): void {
|
|
@@ -113,7 +173,9 @@ function handleConnection(socket: Socket): void {
|
|
|
113
173
|
try {
|
|
114
174
|
const result = await evaluateHookEvent(request.hookEvent, request.cli, request.stdin, {
|
|
115
175
|
awaitTelemetryFlush: false,
|
|
116
|
-
|
|
176
|
+
// Normalised here so no consumer has to know the wire spells
|
|
177
|
+
// "absent" as null.
|
|
178
|
+
fallbackCwd: request.cwd ?? undefined,
|
|
117
179
|
});
|
|
118
180
|
socket.write(
|
|
119
181
|
encodeFrame({
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
module.exports=[14747,(e,o,r)=>{o.exports=e.x("path",()=>require("path"))},78500,(e,o,r)=>{o.exports=e.x("node:async_hooks",()=>require("node:async_hooks"))},1457,(e,o,r)=>{o.exports=e.x("node:readline",()=>require("node:readline"))}];
|
|
2
|
-
|
|
3
|
-
//# sourceMappingURL=%5Bexternals%5D__14odj07._.js.map
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
module.exports=[14747,(e,o,r)=>{o.exports=e.x("path",()=>require("path"))},2157,(e,o,r)=>{o.exports=e.x("node:fs",()=>require("node:fs"))},1457,(e,o,r)=>{o.exports=e.x("node:readline",()=>require("node:readline"))},78500,(e,o,r)=>{o.exports=e.x("node:async_hooks",()=>require("node:async_hooks"))}];
|
|
2
|
-
|
|
3
|
-
//# sourceMappingURL=%5Bexternals%5D__1s61mel._.js.map
|