failproofai 1.0.0-beta.1 → 1.0.0-beta.11
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} +4 -4
- 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]__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]__1a2hcb_._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1gwr8l-._.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/[root-of-the-server]__20ie7me._.js +3 -0
- 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/_0n4bc3i._.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/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/{2ovmv4esqalpb.js → 0-m1vctj2jny6.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1b3a1scouf40o.js → 04y6igmx5olt6.js} +1 -1
- package/.next/standalone/.next/static/chunks/{35584kn409ad1.js → 06abmgw7cvecc.js} +22 -22
- package/.next/standalone/.next/static/chunks/{03fmihek9n986.js → 06zgzyh3wv1ig.js} +1 -1
- package/.next/standalone/.next/static/chunks/0on899o88y54u.js +1 -0
- package/.next/standalone/.next/static/chunks/0p_y4ndalc68e.js +6 -0
- package/.next/standalone/.next/static/chunks/{1hdhteui932bq.js → 0qmo2t50kpb30.js} +1 -1
- package/.next/standalone/.next/static/chunks/0ug1y_6-uwu5t.js +1 -0
- package/.next/standalone/.next/static/chunks/13vrxdsdihqd_.css +2 -0
- package/.next/standalone/.next/static/chunks/16p68cybetr31.js +1 -0
- package/.next/standalone/.next/static/chunks/19lrnqxn7ni7i.js +1 -0
- package/.next/standalone/.next/static/chunks/{30is-6r00sbd7.js → 1a9qlmo5s678i.js} +1 -1
- package/.next/standalone/.next/static/chunks/1v1gqvpjk62jm.js +1 -0
- package/.next/standalone/.next/static/chunks/23kev26by1e4f.js +1 -0
- package/.next/standalone/.next/static/chunks/2uvhw57mf9lg_.css +2 -0
- package/.next/standalone/.next/static/chunks/31coz11ia5vc4.js +1 -0
- package/.next/standalone/.next/static/chunks/{07ix3lb4gib0x.js → 37nu_nos28w1x.js} +1 -1
- package/.next/standalone/.next/static/chunks/{191njgoik03fm.js → 43ylh_2r15k-w.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 +23 -10
- package/.next/standalone/proxy.ts +111 -1
- package/.next/standalone/server.js +1 -1
- package/bin/failproofai.mjs +580 -81
- package/dist/cli.mjs +12974 -7447
- package/dist/worker.mjs +2020 -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 +23 -10
- package/scripts/build-daemon-packages.mjs +247 -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 +27 -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 +930 -158
- package/src/hooks/custom-hooks-loader.ts +191 -33
- package/src/hooks/daemon-client.ts +144 -17
- package/src/hooks/daemon-download.ts +264 -30
- package/src/hooks/daemon-service.ts +1030 -72
- 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 +349 -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]__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]__1ig795d._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1yo1gyz._.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_14q3-7b.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/0fdx7ikab08-g.js +0 -6
- package/.next/standalone/.next/static/chunks/0h7auy7hzjyhw.js +0 -1
- package/.next/standalone/.next/static/chunks/0zbxssxh53n-3.js +0 -1
- package/.next/standalone/.next/static/chunks/1d71o1_tav721.js +0 -1
- package/.next/standalone/.next/static/chunks/24gs8ip6_spcb.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/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/{avJMC2AXvrg13Pbm4QH8F → BZDo0aAHzDwh5ntxgIgpc}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{avJMC2AXvrg13Pbm4QH8F → BZDo0aAHzDwh5ntxgIgpc}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{avJMC2AXvrg13Pbm4QH8F → BZDo0aAHzDwh5ntxgIgpc}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What happens when this CLI meets a home directory written by a different
|
|
3
|
+
* layout.
|
|
4
|
+
*
|
|
5
|
+
* The decision was wipe-and-re-setup rather than migrate. A migration has to
|
|
6
|
+
* be right on every path or it half-moves a home, and a half-moved home fails
|
|
7
|
+
* in the worst available way: the daemon writes where the dashboard does not
|
|
8
|
+
* read, and an absent directory is indistinguishable from an idle one. A reset
|
|
9
|
+
* is one destructive operation that is either done or not done.
|
|
10
|
+
*
|
|
11
|
+
* ## Where the deletion happens, and where it deliberately does not
|
|
12
|
+
*
|
|
13
|
+
* Only a real CLI command resets. A HOOK never deletes anything, because a
|
|
14
|
+
* hook runs unattended, once per tool call, with an agent waiting on stdout —
|
|
15
|
+
* removing a user's audit history and cursors from inside one would be a
|
|
16
|
+
* destructive act nobody asked for and nobody saw.
|
|
17
|
+
*
|
|
18
|
+
* But a hook must not stay silent either. On a stale layout the merged config
|
|
19
|
+
* resolves to nothing, so every builtin policy quietly stops firing: the
|
|
20
|
+
* machine looks protected and is not. That is the single worst outcome here,
|
|
21
|
+
* so the hook path says so on stderr, every time, until setup is re-run.
|
|
22
|
+
*
|
|
23
|
+
* ## Why the hook does not simply deny
|
|
24
|
+
*
|
|
25
|
+
* Failing closed is this product's instinct, and it is the wrong instinct
|
|
26
|
+
* here. A stale layout is the result of an upgrade the user did not ask to be
|
|
27
|
+
* interrupted by, and this branch has already demonstrated — on this very
|
|
28
|
+
* machine — that a blanket deny takes `UserPromptSubmit` with it and locks the
|
|
29
|
+
* user out of their agent entirely, with no way back except hand-editing JSON.
|
|
30
|
+
* A loud warning that survives until setup runs is the proportionate answer.
|
|
31
|
+
*/
|
|
32
|
+
import { copyFileSync, existsSync, mkdirSync, readdirSync, renameSync, rmSync } from "node:fs";
|
|
33
|
+
import { resolve } from "node:path";
|
|
34
|
+
import {
|
|
35
|
+
LAYOUT_VERSION,
|
|
36
|
+
customPoliciesDir,
|
|
37
|
+
failproofaiHome,
|
|
38
|
+
hookActivityDir,
|
|
39
|
+
legacy,
|
|
40
|
+
policiesDir,
|
|
41
|
+
resettablePaths,
|
|
42
|
+
} from "./fp-home";
|
|
43
|
+
import { detectLayout, readConfig, updateConfig, writeVersionFile, type LayoutState } from "./fp-config";
|
|
44
|
+
import {
|
|
45
|
+
daemonServiceStatus,
|
|
46
|
+
daemonStatusCommand,
|
|
47
|
+
daemonVersionSkew,
|
|
48
|
+
isDaemonSupportedPlatform,
|
|
49
|
+
probeDaemonEndToEnd,
|
|
50
|
+
} from "./daemon-service";
|
|
51
|
+
|
|
52
|
+
export interface ResetOutcome {
|
|
53
|
+
/** Paths that existed and were removed. */
|
|
54
|
+
removed: string[];
|
|
55
|
+
/** Basenames of user-authored policy files moved into `custom-policies/`. */
|
|
56
|
+
migrated: string[];
|
|
57
|
+
/** Basenames of decision-log pages carried into layout 2's `hook-activity/`. */
|
|
58
|
+
activity: string[];
|
|
59
|
+
/** The layout that was found before the reset. */
|
|
60
|
+
from: number;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Script files a person could have written by hand. `.d.ts` is a type stub. */
|
|
64
|
+
const USER_SOURCE_RE = /\.(js|mjs|ts)$/;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Move hand-written policies from layout 1's `policies/` into layout 2's
|
|
68
|
+
* `policies/custom-policies/`, where the loader actually reads them.
|
|
69
|
+
*
|
|
70
|
+
* Layout 1 documented `~/.failproofai/policies/` as the user scope for personal
|
|
71
|
+
* convention policies, and layout 2 moved the directory the loader opens down a
|
|
72
|
+
* level (`customPoliciesDir()`). Left alone, those files survive the reset —
|
|
73
|
+
* that part is handled by keeping the parent out of `resettablePaths()` — but
|
|
74
|
+
* nothing would ever load them again, which is the same silent enforcement gap
|
|
75
|
+
* by a slower route.
|
|
76
|
+
*
|
|
77
|
+
* Every loadable extension moves, not just the `*policies.{js,mjs,ts}` names
|
|
78
|
+
* the convention loads: a file that misses the naming convention is still
|
|
79
|
+
* source somebody wrote, and `findSkippedPolicyFiles` exists precisely to tell
|
|
80
|
+
* them so. Leaving it behind to be reported against an empty directory helps
|
|
81
|
+
* nobody.
|
|
82
|
+
*
|
|
83
|
+
* A destination that already exists is never overwritten — the source is left
|
|
84
|
+
* in place instead. The parent directory is no longer deleted, so "left in
|
|
85
|
+
* place" means "still there to look at", which is the right outcome for the
|
|
86
|
+
* only case that reaches it (a half-finished earlier migration).
|
|
87
|
+
*/
|
|
88
|
+
export function migrateConventionPolicies(): string[] {
|
|
89
|
+
const from = policiesDir();
|
|
90
|
+
if (!existsSync(from)) return [];
|
|
91
|
+
const moved: string[] = [];
|
|
92
|
+
try {
|
|
93
|
+
const entries = readdirSync(from, { withFileTypes: true }).filter(
|
|
94
|
+
(e) => e.isFile() && USER_SOURCE_RE.test(e.name) && !e.name.endsWith(".d.ts"),
|
|
95
|
+
);
|
|
96
|
+
if (entries.length === 0) return [];
|
|
97
|
+
|
|
98
|
+
const to = customPoliciesDir();
|
|
99
|
+
mkdirSync(to, { recursive: true });
|
|
100
|
+
for (const entry of entries) {
|
|
101
|
+
const target = resolve(to, entry.name);
|
|
102
|
+
if (existsSync(target)) continue;
|
|
103
|
+
try {
|
|
104
|
+
renameSync(resolve(from, entry.name), target);
|
|
105
|
+
moved.push(entry.name);
|
|
106
|
+
} catch {
|
|
107
|
+
// One unmovable file must not strand the rest. It stays where it is,
|
|
108
|
+
// and the reset no longer deletes that directory.
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
} catch {
|
|
112
|
+
// A policies directory we cannot read is not worth aborting a reset over.
|
|
113
|
+
}
|
|
114
|
+
return moved.sort((a, b) => a.localeCompare(b));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Carry layout 1's decision log into layout 2, WITHOUT re-shipping it.
|
|
119
|
+
*
|
|
120
|
+
* `cache/hook-activity` was deleted along with the rest of `cache/`, so an
|
|
121
|
+
* upgrade silently discarded every decision the machine had ever recorded —
|
|
122
|
+
* the data the dashboard's activity tab exists to show, and on a connected
|
|
123
|
+
* machine the data an operator had already been billed the collection of.
|
|
124
|
+
*
|
|
125
|
+
* # Why this MOVES rather than copies
|
|
126
|
+
*
|
|
127
|
+
* The collector keys its cursors on `(device, inode)` — deliberately, because
|
|
128
|
+
* the store rotates by RENAMING `current.jsonl`, and a path-keyed cursor would
|
|
129
|
+
* both re-ship the rotated file and carry its offset onto the fresh one.
|
|
130
|
+
* `rename()` preserves the inode, so a moved page is still the file its cursor
|
|
131
|
+
* belongs to and resumes at the right offset. A copy gives every page a NEW
|
|
132
|
+
* inode, which reads as "never seen before" and re-ships all of it.
|
|
133
|
+
*
|
|
134
|
+
* `head_fingerprint` is what makes that safe rather than lucky: the cursor
|
|
135
|
+
* verifies the file's first bytes whenever a resumed cursor's path has changed,
|
|
136
|
+
* which is exactly this situation. It was added for inode REUSE; a migration is
|
|
137
|
+
* the same question asked the other way round.
|
|
138
|
+
*
|
|
139
|
+
* The fallback for `EXDEV` (a `cache/` on a different filesystem — rare, since
|
|
140
|
+
* both live under one home, but possible with bind mounts) is a copy, accepting
|
|
141
|
+
* that those pages re-ship. Ingest dedups on a content hash and collapses them
|
|
142
|
+
* at merge, so the cost is bandwidth, not duplicate rows.
|
|
143
|
+
*
|
|
144
|
+
* # What is deliberately NOT carried
|
|
145
|
+
*
|
|
146
|
+
* `current.count` and `stats.json` are derived state, and two of each cannot be
|
|
147
|
+
* merged without inventing a number. They are dropped and the store rebuilds
|
|
148
|
+
* them. The legacy `current.jsonl` is moved under a PAGE name rather than onto
|
|
149
|
+
* the destination's own `current.jsonl`, which may already exist and may be
|
|
150
|
+
* mid-write — a rotated page is exactly what the store would have made of it.
|
|
151
|
+
*/
|
|
152
|
+
export function migrateHookActivity(): string[] {
|
|
153
|
+
const from = legacy.hookActivityDir();
|
|
154
|
+
if (!existsSync(from)) return [];
|
|
155
|
+
const moved: string[] = [];
|
|
156
|
+
try {
|
|
157
|
+
const entries = readdirSync(from, { withFileTypes: true }).filter(
|
|
158
|
+
(e) => e.isFile() && e.name.endsWith(".jsonl"),
|
|
159
|
+
);
|
|
160
|
+
if (entries.length === 0) return [];
|
|
161
|
+
|
|
162
|
+
const to = hookActivityDir();
|
|
163
|
+
mkdirSync(to, { recursive: true });
|
|
164
|
+
|
|
165
|
+
// One timestamp for the whole migration, with a per-file counter, so the
|
|
166
|
+
// names are stable, ordered, and cannot collide with each other.
|
|
167
|
+
const stamp = Date.now();
|
|
168
|
+
let seq = 0;
|
|
169
|
+
|
|
170
|
+
for (const entry of entries) {
|
|
171
|
+
const source = resolve(from, entry.name);
|
|
172
|
+
// `current.jsonl` becomes a page: the destination has its own, and the
|
|
173
|
+
// store's reader treats pages and current identically.
|
|
174
|
+
let name = entry.name === "current.jsonl" ? `page-${stamp}-${seq++}.jsonl` : entry.name;
|
|
175
|
+
let target = resolve(to, name);
|
|
176
|
+
// Never overwrite. A same-named page in the destination is a different
|
|
177
|
+
// file with different records, and losing either is worse than a rename.
|
|
178
|
+
while (existsSync(target)) {
|
|
179
|
+
name = `page-${stamp}-${seq++}.jsonl`;
|
|
180
|
+
target = resolve(to, name);
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
renameSync(source, target);
|
|
184
|
+
moved.push(name);
|
|
185
|
+
} catch (err) {
|
|
186
|
+
// EXDEV: a rename across filesystems. Copy instead and accept the
|
|
187
|
+
// re-ship; a page left behind would be data lost.
|
|
188
|
+
if ((err as NodeJS.ErrnoException)?.code === "EXDEV") {
|
|
189
|
+
try {
|
|
190
|
+
copyFileSync(source, target);
|
|
191
|
+
moved.push(name);
|
|
192
|
+
} catch {
|
|
193
|
+
// Unreadable or undeletable — leave it where it is. `cache/` is no
|
|
194
|
+
// longer deleted wholesale, so "left behind" means "still there".
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
} catch {
|
|
200
|
+
// An activity directory we cannot read is not worth aborting a reset over.
|
|
201
|
+
}
|
|
202
|
+
return moved.sort((a, b) => a.localeCompare(b));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Delete every path layout 1 or layout 2 could have written, then stamp
|
|
207
|
+
* VERSION so the next run reads as current.
|
|
208
|
+
*
|
|
209
|
+
* Enumerated rather than "remove the home directory": a reset must never take
|
|
210
|
+
* out something a future layout adds that this list has not been taught about,
|
|
211
|
+
* and `bin/` and `run/` are excluded on purpose — a downloaded daemon binary is
|
|
212
|
+
* large, version-pinned and re-verified on use, and `run/` holds sockets
|
|
213
|
+
* belonging to a process that may be alive right now.
|
|
214
|
+
*/
|
|
215
|
+
export function resetHome(from: number): ResetOutcome {
|
|
216
|
+
// BEFORE the deletions, so a file that is mid-move is never one the reset
|
|
217
|
+
// then walks over.
|
|
218
|
+
const migrated = migrateConventionPolicies();
|
|
219
|
+
const activity = migrateHookActivity();
|
|
220
|
+
const removed: string[] = [];
|
|
221
|
+
for (const path of resettablePaths()) {
|
|
222
|
+
if (!existsSync(path)) continue;
|
|
223
|
+
try {
|
|
224
|
+
rmSync(path, { recursive: true, force: true });
|
|
225
|
+
removed.push(path);
|
|
226
|
+
} catch {
|
|
227
|
+
// A path we cannot remove is not worth aborting the reset over; the
|
|
228
|
+
// VERSION stamp below is what stops this repeating, and a leftover
|
|
229
|
+
// directory from an old layout is inert once nothing reads it.
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
writeVersionFile();
|
|
233
|
+
return { removed, migrated, activity, from };
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export interface LayoutCheck {
|
|
237
|
+
state: LayoutState;
|
|
238
|
+
/** Lines to print. Empty when there is nothing to say. */
|
|
239
|
+
lines: string[];
|
|
240
|
+
/** True when the caller should stop rather than continue. */
|
|
241
|
+
fatal: boolean;
|
|
242
|
+
/**
|
|
243
|
+
* True when this call actually reset the home.
|
|
244
|
+
*
|
|
245
|
+
* The caller must force setup when it is set. A reset removes the global
|
|
246
|
+
* policy config, but `isConfigured()` is a union that also counts the agent
|
|
247
|
+
* CLIs' settings files — which the reset deliberately leaves alone — so the
|
|
248
|
+
* machine still reads as configured, the wizard is skipped, and
|
|
249
|
+
* `markLauncherSeen()` back-fills the marker so every later run skips it too.
|
|
250
|
+
* The user is left with hooks firing on every tool call against no policies
|
|
251
|
+
* at all, and nothing ever says so again.
|
|
252
|
+
*/
|
|
253
|
+
didReset: boolean;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* The interactive path: reset a stale home, refuse a future one.
|
|
258
|
+
*
|
|
259
|
+
* A future layout is refused rather than reset because the two failures are
|
|
260
|
+
* not the same. An older home can be rebuilt by re-running setup; a home
|
|
261
|
+
* written by a NEWER CLI holds data this build cannot read but a simple
|
|
262
|
+
* upgrade could, and deleting it would destroy something recoverable.
|
|
263
|
+
*/
|
|
264
|
+
export async function checkLayoutForCli(): Promise<LayoutCheck> {
|
|
265
|
+
const state = detectLayout();
|
|
266
|
+
|
|
267
|
+
if (state.kind === "future") {
|
|
268
|
+
return {
|
|
269
|
+
state,
|
|
270
|
+
fatal: true,
|
|
271
|
+
didReset: false,
|
|
272
|
+
lines: [
|
|
273
|
+
`This machine's failproofai directory was written by a newer version`,
|
|
274
|
+
`(layout ${state.found}; this build speaks ${LAYOUT_VERSION}).`,
|
|
275
|
+
``,
|
|
276
|
+
`Upgrade rather than reset — the data is fine, this build just cannot read it:`,
|
|
277
|
+
` npm install -g failproofai@latest`,
|
|
278
|
+
],
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (state.kind === "stale") {
|
|
283
|
+
const { removed, migrated, activity } = resetHome(state.found);
|
|
284
|
+
return {
|
|
285
|
+
state,
|
|
286
|
+
fatal: false,
|
|
287
|
+
didReset: true,
|
|
288
|
+
lines: [
|
|
289
|
+
`failproofai reorganised ${failproofaiHome()} in this version.`,
|
|
290
|
+
// "activity history" was in this sentence while the reset was deleting
|
|
291
|
+
// it. It is carried over now, so the message says what was KEPT as well
|
|
292
|
+
// as what went — a user who reads "removed" and nothing else has no way
|
|
293
|
+
// to know their decision log survived.
|
|
294
|
+
`Removed ${removed.length} item(s) from the old layout — policy config and`,
|
|
295
|
+
`audit cache. Your daemon binary and decision history were kept.`,
|
|
296
|
+
// Named individually rather than counted. These are files a person
|
|
297
|
+
// wrote; "moved 3 items" is not something you can check at a glance,
|
|
298
|
+
// and the whole point of saying it is that they can.
|
|
299
|
+
...(migrated.length > 0
|
|
300
|
+
? [
|
|
301
|
+
``,
|
|
302
|
+
`Kept your own policy file(s) and moved them to where this version`,
|
|
303
|
+
`loads them (${customPoliciesDir()}):`,
|
|
304
|
+
...migrated.map((name) => ` ${name}`),
|
|
305
|
+
]
|
|
306
|
+
: []),
|
|
307
|
+
// Counted, not named. Unlike policy files these are machine-written
|
|
308
|
+
// pages with generated names — a list of them tells the reader nothing
|
|
309
|
+
// they could act on, where the COUNT answers the only question they
|
|
310
|
+
// have: did my history survive.
|
|
311
|
+
...(activity.length > 0
|
|
312
|
+
? [
|
|
313
|
+
``,
|
|
314
|
+
`Carried ${activity.length} page(s) of decision history into ${hookActivityDir()}.`,
|
|
315
|
+
]
|
|
316
|
+
: []),
|
|
317
|
+
``,
|
|
318
|
+
`Run \`failproofai config\` to set up again.`,
|
|
319
|
+
],
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (state.kind === "absent") writeVersionFile();
|
|
324
|
+
return {
|
|
325
|
+
state,
|
|
326
|
+
fatal: false,
|
|
327
|
+
didReset: false,
|
|
328
|
+
lines: [...(await healDaemonFlag()), ...staleDaemonHint()],
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Clear `daemonConfigured` when the service it points at is provably gone.
|
|
334
|
+
*
|
|
335
|
+
* This exists because the combination it repairs bricked a real machine during
|
|
336
|
+
* development. `daemonConfigured` makes every hook route through failproofaid
|
|
337
|
+
* and FAIL CLOSED when it cannot be reached — so removing the service without
|
|
338
|
+
* first clearing the flag denies every tool call on the box, including
|
|
339
|
+
* `UserPromptSubmit`, which locks the user out of their agent entirely. There
|
|
340
|
+
* was no command to undo it: the only recovery was hand-editing JSON.
|
|
341
|
+
*
|
|
342
|
+
* Deliberately keyed on "not-installed", never on "stopped". A stopped service
|
|
343
|
+
* is usually a restart in progress, and clearing the flag there would silently
|
|
344
|
+
* downgrade a healthy machine to the in-process path — trading a loud, correct
|
|
345
|
+
* failure for a quiet, wrong one.
|
|
346
|
+
*/
|
|
347
|
+
async function healDaemonFlag(): Promise<string[]> {
|
|
348
|
+
try {
|
|
349
|
+
const cfg = readConfig();
|
|
350
|
+
if (!cfg.daemon.configured) return [];
|
|
351
|
+
if (!isDaemonSupportedPlatform()) return [];
|
|
352
|
+
|
|
353
|
+
const status = daemonServiceStatus();
|
|
354
|
+
if (status === "not-installed") {
|
|
355
|
+
updateConfig({ daemon: { configured: false } });
|
|
356
|
+
return [
|
|
357
|
+
`failproofaid is no longer installed, but this machine was still configured`,
|
|
358
|
+
`to require it — which denies every tool call. Cleared that flag; policies`,
|
|
359
|
+
`now evaluate in-process. Run \`failproofai config\` to reinstall the daemon.`,
|
|
360
|
+
``,
|
|
361
|
+
];
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Installed, and systemd has refused to start it: one of the paths the unit
|
|
365
|
+
// is gated on is gone. This is what `npm rm -g failproofai` leaves behind —
|
|
366
|
+
// npm runs no uninstall script, so the unit survives the package that
|
|
367
|
+
// supplies its worker, and every tool call on the machine then denies with
|
|
368
|
+
// nothing to point at.
|
|
369
|
+
//
|
|
370
|
+
// Treated like "not-installed" rather than like "stopped" because systemd
|
|
371
|
+
// has already made the call and will keep making it at every boot. That is
|
|
372
|
+
// the distinction `condition-failed` exists to carry; see its definition.
|
|
373
|
+
if (status === "condition-failed") {
|
|
374
|
+
updateConfig({ daemon: { configured: false } });
|
|
375
|
+
return [
|
|
376
|
+
`failproofaid is installed but cannot start — a file its service requires is`,
|
|
377
|
+
`gone (most often because failproofai was removed with \`npm rm -g\`, which`,
|
|
378
|
+
`deletes the worker but leaves the service behind). This machine was`,
|
|
379
|
+
`configured to require the daemon, which denies every tool call, so that flag`,
|
|
380
|
+
`is cleared; policies now evaluate in-process.`,
|
|
381
|
+
``,
|
|
382
|
+
`Run \`failproofai uninstall\` to remove the leftover service, or`,
|
|
383
|
+
`\`failproofai config\` to rebuild it. \`${daemonStatusCommand()}\` names the missing path.`,
|
|
384
|
+
``,
|
|
385
|
+
];
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Installed and RUNNING is not the same as working, and the difference is
|
|
389
|
+
// a total lockout. `ExecStart` bakes in `process.execPath`, so an
|
|
390
|
+
// `nvm uninstall 20` months later leaves a unit systemd still calls active
|
|
391
|
+
// whose worker dies on every spawn. Nothing else catches it: the install
|
|
392
|
+
// probe cannot run retroactively, and the not-installed branch above never
|
|
393
|
+
// fires because the unit is very much installed.
|
|
394
|
+
//
|
|
395
|
+
// Clearing the flag is the whole repair, and it is deliberately NOT
|
|
396
|
+
// accompanied by an uninstall: this runs unprompted at the top of whatever
|
|
397
|
+
// command the user typed, and tearing down a root-owned service from there
|
|
398
|
+
// is not a decision to make on their behalf. Removing and reinstalling the
|
|
399
|
+
// unit is the wizard's job, where a person is present — see the
|
|
400
|
+
// `daemonAlreadyHealthy` probe in `configure-wizard.ts`.
|
|
401
|
+
if (status === "running" && !(await probeDaemonEndToEnd())) {
|
|
402
|
+
updateConfig({ daemon: { configured: false } });
|
|
403
|
+
return [
|
|
404
|
+
`failproofaid is running but cannot evaluate policies — its worker process`,
|
|
405
|
+
`will not start (most often because the Node install its service was built`,
|
|
406
|
+
`against is gone). This machine was configured to require it, which denies`,
|
|
407
|
+
`every tool call, so that flag is cleared; policies now evaluate in-process.`,
|
|
408
|
+
`Run \`failproofai config\` to rebuild the service.`,
|
|
409
|
+
``,
|
|
410
|
+
];
|
|
411
|
+
}
|
|
412
|
+
return [];
|
|
413
|
+
} catch {
|
|
414
|
+
// Never let a self-heal attempt break the command the user actually typed.
|
|
415
|
+
return [];
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* One line when the daemon is older than the CLI.
|
|
421
|
+
*
|
|
422
|
+
* Deliberately NOT on the hook path. A stale daemon still enforces every policy
|
|
423
|
+
* correctly — it is slower to notice an upgrade, not broken — so a warning once
|
|
424
|
+
* per tool call would be noise about something that is working. CLI commands
|
|
425
|
+
* are where a person is present to act on it.
|
|
426
|
+
*/
|
|
427
|
+
function staleDaemonHint(): string[] {
|
|
428
|
+
try {
|
|
429
|
+
const skew = daemonVersionSkew();
|
|
430
|
+
if (!skew) return [];
|
|
431
|
+
return [
|
|
432
|
+
`[failproofai] daemon is ${skew.installed}, CLI is ${skew.expected} — ` +
|
|
433
|
+
`run \`failproofai config\` to update it.`,
|
|
434
|
+
``,
|
|
435
|
+
];
|
|
436
|
+
} catch {
|
|
437
|
+
return [];
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* The hook path: never delete, never deny, but never stay quiet either.
|
|
443
|
+
*
|
|
444
|
+
* Returns a single stderr line when the layout is not current. Hooks run once
|
|
445
|
+
* per tool call, so this repeats — deliberately. A warning that appears once
|
|
446
|
+
* and then stops is a warning nobody sees, and the state it describes (a
|
|
447
|
+
* machine whose global policies have silently stopped firing) persists until
|
|
448
|
+
* somebody acts on it.
|
|
449
|
+
*/
|
|
450
|
+
export function layoutWarningForHook(): string | null {
|
|
451
|
+
const state = detectLayout();
|
|
452
|
+
if (state.kind === "current" || state.kind === "absent") return null;
|
|
453
|
+
if (state.kind === "future") {
|
|
454
|
+
return (
|
|
455
|
+
`[failproofai] this directory was written by a newer version ` +
|
|
456
|
+
`(layout ${state.found} vs ${LAYOUT_VERSION}) — policies are NOT being enforced. ` +
|
|
457
|
+
`Upgrade failproofai.`
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
return (
|
|
461
|
+
`[failproofai] setup predates this version — global policies are NOT being enforced. ` +
|
|
462
|
+
`Run \`failproofai config\` to re-create it.`
|
|
463
|
+
);
|
|
464
|
+
}
|