failproofai 1.0.0-beta.2 → 1.0.0-beta.21
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 +3 -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]__0l4vuqm._.js → [root-of-the-server]__00ni9za._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__06hexd0._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__08y94xv._.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]__0-dh5jy._.js → [root-of-the-server]__0effm9m._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0g0vcwt._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__18d-9oi._.js → [root-of-the-server]__0ix8gm7._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0h3lfmp._.js → [root-of-the-server]__0ji11a-._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__10oa-v9._.js → [root-of-the-server]__0ojwjxl._.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]__0vb5fl2._.js +3 -0
- 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]__1ibjy5x._.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]__20d06rh._.js +3 -0
- package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +3 -0
- package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_telemetry_ts_0dctyyw._.js +3 -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]__0-wfhrp._.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]__1apb7k_._.js → [root-of-the-server]__0_1tiya._.js} +2 -2
- 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]__0t281d4._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17itmx-._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__01od0m6._.js → [root-of-the-server]__1n2vcv4._.js} +2 -2
- 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]__1rv-sc9._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1tlvv9a._.js +3 -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/_0-yi74u._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0rjgfln._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0vo2qyt._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0xej-0e._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_10399ge._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_11_p9y8._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_149k9oy._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1_hwp06._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1ctse6u._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1e19atl._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1mnhi_r._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1ror7k9._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1sdgprl._.js +5 -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 +4 -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/{03fmihek9n986.js → 06zgzyh3wv1ig.js} +1 -1
- package/.next/standalone/.next/static/chunks/0km-jn9o5xyqs.css +2 -0
- package/.next/standalone/.next/static/chunks/{1hdhteui932bq.js → 0qmo2t50kpb30.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2sbelanzvxvv0.js → 113g8wtal6_c4.js} +22 -22
- package/.next/standalone/.next/static/chunks/16p68cybetr31.js +1 -0
- package/.next/standalone/.next/static/chunks/18wqn0_3mzylf.js +1 -0
- package/.next/standalone/.next/static/chunks/1v1gqvpjk62jm.js +1 -0
- package/.next/standalone/.next/static/chunks/{0fi645si-uiiq.js → 1xq1m8h14tnlj.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3hp8ulqknybil.js → 1y3vwogqb88dx.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3vs4ay36tjds_.js → 1zmh-b0ulrqu7.js} +1 -1
- package/.next/standalone/.next/static/chunks/23kev26by1e4f.js +1 -0
- package/.next/standalone/.next/static/chunks/299lhw60e8gr6.js +1 -0
- package/.next/standalone/.next/static/chunks/{18rvdw5v72364.js → 2adbpdaxp5ygq.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2j94uwkb4s3qr.js → 2kbqcw-6swmav.js} +1 -1
- package/.next/standalone/.next/static/chunks/2n9n5m0963pdg.js +6 -0
- package/.next/standalone/.next/static/chunks/2uvhw57mf9lg_.css +2 -0
- package/.next/standalone/.next/static/chunks/{31feojxhjyjpl.js → 30nrrpwymht5m.js} +1 -1
- package/.next/standalone/.next/static/chunks/31coz11ia5vc4.js +1 -0
- package/.next/standalone/.next/static/chunks/{turbopack-1lsv92x7klwrn.js → turbopack-3diub4ctvn1n0.js} +1 -1
- package/.next/standalone/SECURITY.md +8 -2
- package/.next/standalone/app/actions/get-active-pauses.ts +16 -0
- package/.next/standalone/app/actions/get-hooks-config.ts +2 -2
- 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/audit-dashboard.tsx +1 -3
- package/.next/standalone/app/audit/_components/audit-progress-strip.tsx +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/_components/come-back-better-section.tsx +1 -1
- package/.next/standalone/app/audit/_components/empty-state.tsx +0 -1
- package/.next/standalone/app/audit/_components/how-to-improve-section.tsx +1 -1
- package/.next/standalone/app/audit/_components/quirks-section.tsx +0 -1
- package/.next/standalone/app/audit/_components/report-footer.tsx +0 -2
- package/.next/standalone/app/audit/_components/run-progress.tsx +1 -1
- package/.next/standalone/app/audit/_components/strengths-section.tsx +0 -1
- package/.next/standalone/app/audit/audit-styles.css +6 -149
- package/.next/standalone/app/components/pause-notices.tsx +111 -0
- package/.next/standalone/app/components/raw-log-viewer.tsx +1 -1
- package/.next/standalone/app/components/toast.tsx +1 -1
- package/.next/standalone/app/policies/hooks-client.tsx +84 -8
- package/.next/standalone/app/settings/page.tsx +31 -0
- package/.next/standalone/app/settings/settings-client.tsx +487 -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 -5
- 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 -12
- package/.next/standalone/proxy.ts +111 -1
- package/.next/standalone/server.js +1 -1
- package/bin/failproofai-worker.mjs +1 -1
- package/bin/failproofai.mjs +1041 -81
- package/bin/failproofaid-shim.mjs +4 -4
- package/dist/cli.mjs +18513 -10474
- package/dist/worker.mjs +1223 -299
- package/lib/auth/api-server-client.ts +2 -3
- package/lib/auth/auth-store.ts +4 -5
- 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 -12
- package/scripts/build-daemon-packages.mjs +247 -0
- package/scripts/daemon-platforms.mjs +42 -0
- package/scripts/dev-hook.mjs +46 -5
- 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/cache.ts +1 -1
- package/scripts/translate-docs/cli.ts +2 -2
- package/scripts/translate-docs/mintlify-nav.ts +1 -1
- 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 -5
- 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 -3
- package/src/audit/report.ts +0 -1
- package/src/hooks/backfill-cli.ts +247 -0
- package/src/hooks/builtin-policies.ts +391 -3
- package/src/hooks/cloud-connection.ts +354 -0
- package/src/hooks/cloud-enrollment-cli.ts +439 -0
- package/src/hooks/cloud-enrollment.ts +284 -0
- package/src/hooks/cloud-introspect.ts +147 -0
- package/src/hooks/cloud-managed-policies.ts +206 -0
- package/src/hooks/collector-config.ts +218 -0
- package/src/hooks/configure-wizard.ts +1211 -233
- package/src/hooks/custom-hooks-loader.ts +243 -37
- package/src/hooks/daemon-client.ts +136 -33
- package/src/hooks/daemon-download.ts +264 -31
- package/src/hooks/daemon-service.ts +1124 -76
- package/src/hooks/first-run-gate.ts +50 -0
- package/src/hooks/flush-cli.ts +180 -0
- package/src/hooks/fp-config.ts +835 -0
- package/src/hooks/fp-home.ts +714 -0
- package/src/hooks/fp-reset.ts +1363 -0
- package/src/hooks/handler.ts +185 -6
- package/src/hooks/harness-cli.ts +386 -0
- package/src/hooks/hook-activity-store.ts +171 -24
- package/src/hooks/hook-logger.ts +2 -2
- package/src/hooks/hook-telemetry.ts +5 -1
- package/src/hooks/hooks-config.ts +4 -3
- package/src/hooks/integrations.ts +0 -1
- package/src/hooks/loader-utils.ts +172 -9
- package/src/hooks/manager.ts +41 -5
- package/src/hooks/migrations.ts +450 -0
- package/src/hooks/onboarding-attempt.ts +195 -0
- package/src/hooks/onboarding-lock.ts +118 -0
- package/src/hooks/policy-types.ts +28 -0
- package/src/hooks/session-pause-cli.ts +159 -0
- package/src/hooks/session-pause.ts +267 -0
- package/src/hooks/setup-state.ts +256 -0
- package/src/hooks/tui.ts +209 -9
- package/src/hooks/uninstall-cli.ts +418 -0
- package/src/hooks/worker-server.ts +134 -15
- 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]__0nb0syg._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qucxyj._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__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]__1psjybo._.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_0oy_-36.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/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/3s7myk_co0gbh.js +0 -1
- package/.next/standalone/.next/static/chunks/40k1_v4os4cw6.js +0 -6
- 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/{NWAjs0tHFyzk97gRGG09r → VjEdIL6W5uBsvEzknXqV9}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{NWAjs0tHFyzk97gRGG09r → VjEdIL6W5uBsvEzknXqV9}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{NWAjs0tHFyzk97gRGG09r → VjEdIL6W5uBsvEzknXqV9}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,714 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every path inside `~/.failproofai`, in one place.
|
|
3
|
+
*
|
|
4
|
+
* Before this module the layout was ~40 hardcoded `resolve(homedir(),
|
|
5
|
+
* ".failproofai", …)` calls in TypeScript and ~10 more in Rust, and the two
|
|
6
|
+
* sides had drifted into three different ideas of where things lived
|
|
7
|
+
* (`cache/hook-activity` vs `hook-activity`, `spool` at the root vs under
|
|
8
|
+
* state). Moving anything meant finding every one of them, and missing one
|
|
9
|
+
* meant the daemon wrote where the dashboard did not read — silently, because
|
|
10
|
+
* an absent directory is indistinguishable from an idle one.
|
|
11
|
+
*
|
|
12
|
+
* So: nothing outside this file may join a path onto the failproofai home.
|
|
13
|
+
* The Rust side mirrors it in `crates/failproofaid/src/paths.rs`. The test that
|
|
14
|
+
* asserts the two agree lives THERE, not here —
|
|
15
|
+
* `paths::tests::every_mirrored_path_agrees_with_fp_home_ts` imports this module
|
|
16
|
+
* in a child process and compares every mirrored path against its own.
|
|
17
|
+
*
|
|
18
|
+
* This line used to cite `__tests__/hooks/fp-home.test.ts`, which contains no
|
|
19
|
+
* reference to `crates/` and never checked anything cross-language. While both
|
|
20
|
+
* files claimed the guard existed, three paths were wrong at once: the daemon's
|
|
21
|
+
* `run/` ignored `FAILPROOFAI_HOME` (so a healthy daemon on a fail-closed
|
|
22
|
+
* machine denied every tool call), its cloud policy directory still said
|
|
23
|
+
* `cloud-managed`, and its credential still said `cloud.json`.
|
|
24
|
+
*
|
|
25
|
+
* ## Layout 3
|
|
26
|
+
*
|
|
27
|
+
* Three things changed from layout 2, all of them about a directory saying what
|
|
28
|
+
* it holds:
|
|
29
|
+
*
|
|
30
|
+
* - **Everything is JSON.** `config.toml` and `credentials.toml` are now
|
|
31
|
+
* `.json`. Two serialisation formats in one home meant two parsers, two
|
|
32
|
+
* escaping rules, and a `toml` dependency in both the CLI and the daemon to
|
|
33
|
+
* read files that were only ever flat key/value.
|
|
34
|
+
* - **`policies/` holds policies, and only policies.** It also held
|
|
35
|
+
* `local-policies/` — our config, not a policy at all, and the one file a
|
|
36
|
+
* user must not hand-edit sitting among the ones they should. That moved to
|
|
37
|
+
* the root. What stays is every policy on the machine: the user's own `*.mjs`
|
|
38
|
+
* directly in it, the fleet's under `cloud-policies/`. Nesting them is safe
|
|
39
|
+
* because the convention loader does not recurse (see `cloudPoliciesDir`),
|
|
40
|
+
* and it means one directory answers "what governs this machine".
|
|
41
|
+
* - **No per-deployment directories.** `cloud-policies/generations/<n>/` held a
|
|
42
|
+
* full copy of every artifact per deployment — a tree to create, prune and
|
|
43
|
+
* keep consistent with the manifest, on top of the `artifacts/` copy. They
|
|
44
|
+
* are content-addressed and therefore immutable, so the copies bought nothing
|
|
45
|
+
* the digests did not already give. `cloud-policies/` is flat now: one
|
|
46
|
+
* `artifacts/` directory, and `active.json` naming what is live — see
|
|
47
|
+
* `cloud_policies.rs` for why activation is still atomic without them.
|
|
48
|
+
*
|
|
49
|
+
* ```
|
|
50
|
+
* ~/.failproofai/
|
|
51
|
+
* VERSION layout / cli / daemon versions
|
|
52
|
+
* config.json 0644 non-secret: mode, daemon, collector prefs
|
|
53
|
+
* credentials.json 0600 every token
|
|
54
|
+
* policies-config.json the builtin enable/disable set + params
|
|
55
|
+
* bin/ downloaded daemon binaries, one per version
|
|
56
|
+
* policies/ every policy: the user's *.mjs sit directly here
|
|
57
|
+
* cloud-policies/ the fleet's — flat: active.json, desired-state.json, artifacts/
|
|
58
|
+
* cursors/<source>/ per-source collector watermarks
|
|
59
|
+
* audit/ audit report + per-session cache
|
|
60
|
+
* hook-activity/ decision log the dashboard reads
|
|
61
|
+
* custom-agents/ SDK spool (events/ + failed/)
|
|
62
|
+
* run/ sockets + flock — MUST stay shallow, see below
|
|
63
|
+
* state/ daemon scratch: spool, failed, health, pauses, shims
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* **`run/` is deliberately NOT under `state/`.** A Unix socket path must fit
|
|
67
|
+
* in `sockaddr_un.sun_path` (~108 bytes) and we have hit that ceiling twice
|
|
68
|
+
* already during development. Every directory level spends part of a budget
|
|
69
|
+
* that a long `$HOME` has already eaten into, so the socket stays as close to
|
|
70
|
+
* the root as it can.
|
|
71
|
+
*
|
|
72
|
+
* ## Project scope is NOT here
|
|
73
|
+
*
|
|
74
|
+
* `<project>/.failproofai/` keeps its old shape — `policies-config.json` and
|
|
75
|
+
* `policies/*.mjs` at the top. Those files are committed to users' git repos,
|
|
76
|
+
* so reorganising them would rewrite history in every repo that adopted
|
|
77
|
+
* failproofai. `hooks-config.ts` still owns those paths.
|
|
78
|
+
*/
|
|
79
|
+
import { homedir } from "node:os";
|
|
80
|
+
import { resolve } from "node:path";
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The on-disk layout this build speaks.
|
|
84
|
+
*
|
|
85
|
+
* Bumped whenever a path in this file moves. Recorded in `VERSION`, and what
|
|
86
|
+
* `detectLayout()` compares against — a home written by a different layout is
|
|
87
|
+
* refused rather than half-read, because reading a moved directory silently
|
|
88
|
+
* yields "no data" instead of an error.
|
|
89
|
+
*
|
|
90
|
+
* 1 — the original flat/`cache`-based layout, through 1.0.0-beta.5.
|
|
91
|
+
* 2 — this file.
|
|
92
|
+
*/
|
|
93
|
+
export const LAYOUT_VERSION = 3;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* `~/.failproofai`, or `FAILPROOFAI_HOME`.
|
|
97
|
+
*
|
|
98
|
+
* The override is load-bearing for tests and containers: everything below is
|
|
99
|
+
* derived from it, so pointing it elsewhere relocates the entire layout
|
|
100
|
+
* atomically rather than per-path.
|
|
101
|
+
*/
|
|
102
|
+
export function failproofaiHome(home?: string): string {
|
|
103
|
+
if (home) return resolve(home, ".failproofai");
|
|
104
|
+
return process.env.FAILPROOFAI_HOME || resolve(homedir(), ".failproofai");
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const at = (...parts: string[]): string => resolve(failproofaiHome(), ...parts);
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Same, against an explicitly supplied HOME (not the failproofai home).
|
|
111
|
+
*
|
|
112
|
+
* `setup-state` and `onboarding-lock` take a `home` parameter purely so their
|
|
113
|
+
* tests can point at a temp directory, and a helper that silently ignored it
|
|
114
|
+
* would send those tests at the developer's real home — which is precisely the
|
|
115
|
+
* bug this overload exists to make impossible.
|
|
116
|
+
*/
|
|
117
|
+
const atHome = (home: string | undefined, ...parts: string[]): string =>
|
|
118
|
+
home ? resolve(failproofaiHome(home), ...parts) : at(...parts);
|
|
119
|
+
|
|
120
|
+
// ── Top level ────────────────────────────────────────────────────────────────
|
|
121
|
+
|
|
122
|
+
/** Layout / CLI / daemon versions. Also the layout marker. */
|
|
123
|
+
export const versionFile = (home?: string) => atHome(home, "VERSION");
|
|
124
|
+
|
|
125
|
+
/** Non-secret configuration. World-readable by design; never holds a token. */
|
|
126
|
+
export const configFile = (home?: string) => atHome(home, "config.json");
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Every credential, owner-only.
|
|
130
|
+
*
|
|
131
|
+
* Split from `config.toml` because that file is written with a bare
|
|
132
|
+
* `writeFileSync` and inherits the umask (0664 on a normal machine). A token
|
|
133
|
+
* there would be readable by every local user on the box — which is exactly
|
|
134
|
+
* why `ingest.json` and `cloud.json` were separate files before this.
|
|
135
|
+
*/
|
|
136
|
+
export const credentialsFile = (home?: string) => atHome(home, "credentials.json");
|
|
137
|
+
|
|
138
|
+
// ── Daemon binaries ──────────────────────────────────────────────────────────
|
|
139
|
+
|
|
140
|
+
export const binDir = (home?: string) => atHome(home, "bin");
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* One file per version, never overwritten in place: an in-place write hits
|
|
144
|
+
* `ETXTBSY` against the running daemon on Linux, and would silently repoint a
|
|
145
|
+
* live service unit at a binary built from different source.
|
|
146
|
+
*/
|
|
147
|
+
export const daemonBinary = (version: string, home?: string) =>
|
|
148
|
+
resolve(binDir(home), `failproofaid-${version}`);
|
|
149
|
+
|
|
150
|
+
// ── Policies ─────────────────────────────────────────────────────────────────
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Where the user drops convention policies (`*.mjs`), loaded with no flag.
|
|
154
|
+
*
|
|
155
|
+
* Layout 3 made this the WHOLE meaning of the directory. It used to hold two
|
|
156
|
+
* subdirectories the user did not put there — `local-policies/` (our config)
|
|
157
|
+
* and `cloud-policies/` (the fleet's) — so "mine" and "not mine" shared a
|
|
158
|
+
* folder and nothing said which was which.
|
|
159
|
+
*/
|
|
160
|
+
export const policiesDir = (home?: string) => atHome(home, "policies");
|
|
161
|
+
|
|
162
|
+
/** Convention policies ARE the policies directory now; kept as an alias. */
|
|
163
|
+
export const customPoliciesDir = policiesDir;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* The builtin enable/disable set and per-policy params, GLOBAL scope only.
|
|
167
|
+
*
|
|
168
|
+
* At the root in layout 3. It is configuration, not a policy, and burying it
|
|
169
|
+
* two levels inside a directory users are told to drop files into put the one
|
|
170
|
+
* file they must not hand-edit among the ones they should.
|
|
171
|
+
*/
|
|
172
|
+
export const globalPolicyConfigFile = (home?: string) =>
|
|
173
|
+
atHome(home, "policies-config.json");
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Cloud-managed deployments: `active.json`, `desired-state.json`, and
|
|
177
|
+
* content-addressed `artifacts/`.
|
|
178
|
+
*
|
|
179
|
+
* A CHILD of `policies/`, so everything that is a policy lives under one
|
|
180
|
+
* directory and the home root stays readable — every policy on the machine is
|
|
181
|
+
* under `policies/`, whoever put it there.
|
|
182
|
+
*
|
|
183
|
+
* Safe to nest because the convention loader does not recurse:
|
|
184
|
+
* `discoverPolicyFiles()` and `findSkippedPolicyFiles()` both filter
|
|
185
|
+
* `isFile()`, so this directory is invisible to it. That is the property that
|
|
186
|
+
* makes the nesting safe rather than a coincidence — if either ever walks
|
|
187
|
+
* subdirectories, every cloud artifact becomes a convention policy loaded
|
|
188
|
+
* WITHOUT its digest being checked, which is the one path this whole module
|
|
189
|
+
* exists to prevent. `fp-home.test.ts` pins it.
|
|
190
|
+
*
|
|
191
|
+
* What is flat is the INSIDE of this directory: `artifacts/` holds every
|
|
192
|
+
* content-addressed policy for every deployment, and `active.json` names which
|
|
193
|
+
* of them is live. There is no `deployments/<n>/` tree — a per-deployment
|
|
194
|
+
* directory is one more moving part that has to be created, pruned and kept
|
|
195
|
+
* consistent with the manifest, and it bought nothing the digests did not
|
|
196
|
+
* already give.
|
|
197
|
+
*/
|
|
198
|
+
export const cloudPoliciesDir = (home?: string) => resolve(policiesDir(home), "cloud-policies");
|
|
199
|
+
|
|
200
|
+
// ── Collector ────────────────────────────────────────────────────────────────
|
|
201
|
+
|
|
202
|
+
/** Per-source watermarks. One directory per source — never shared: the cursor
|
|
203
|
+
* store rewrites its whole map atomically, so two sources sharing a file
|
|
204
|
+
* clobber each other and the loser re-reads from zero after every restart. */
|
|
205
|
+
export const cursorsDir = (source?: string, home?: string) =>
|
|
206
|
+
source ? resolve(atHome(home, "cursors"), source) : atHome(home, "cursors");
|
|
207
|
+
|
|
208
|
+
/** The SDK spool root. Mirrors `~/.agenteye/`, which stays supported. */
|
|
209
|
+
export const customAgentsDir = (home?: string) => atHome(home, "custom-agents");
|
|
210
|
+
export const customAgentsEventsDir = (home?: string) => resolve(customAgentsDir(home), "events");
|
|
211
|
+
export const customAgentsFailedDir = (home?: string) => resolve(customAgentsDir(home), "failed");
|
|
212
|
+
|
|
213
|
+
// ── Audit ────────────────────────────────────────────────────────────────────
|
|
214
|
+
|
|
215
|
+
export const auditDir = (home?: string) => atHome(home, "audit");
|
|
216
|
+
export const auditDashboardFile = (home?: string) => resolve(auditDir(home), "dashboard.json");
|
|
217
|
+
export const auditCacheDir = (home?: string) => resolve(auditDir(home), "cache");
|
|
218
|
+
|
|
219
|
+
// ── Hook activity ────────────────────────────────────────────────────────────
|
|
220
|
+
|
|
221
|
+
/** The decision log: page-sized JSONL the dashboard's activity tab reads. */
|
|
222
|
+
export const hookActivityDir = (home?: string) => atHome(home, "hook-activity");
|
|
223
|
+
|
|
224
|
+
// ── Runtime ──────────────────────────────────────────────────────────────────
|
|
225
|
+
|
|
226
|
+
/** Sockets and the singleton flock. Shallow on purpose — see the header note. */
|
|
227
|
+
export const runDir = (home?: string) => atHome(home, "run");
|
|
228
|
+
export const daemonSocket = () =>
|
|
229
|
+
process.env.FAILPROOFAI_DAEMON_SOCKET || resolve(runDir(), "failproofaid.sock");
|
|
230
|
+
export const workerSocket = (home?: string) => resolve(runDir(home), "worker.sock");
|
|
231
|
+
export const daemonLock = (home?: string) => resolve(runDir(home), "failproofaid.lock");
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Single-flight lock for the audit.
|
|
235
|
+
*
|
|
236
|
+
* Three separate processes can start one — a scheduled run, `failproofai
|
|
237
|
+
* audit`, and the dashboard's re-run — and all three write the same
|
|
238
|
+
* sha1-keyed cache files, so the lock has to be visible across processes.
|
|
239
|
+
* It sits in `run/` with the other runtime files rather than under `audit/`,
|
|
240
|
+
* which holds results a human might keep and a reset is expected to clear.
|
|
241
|
+
*
|
|
242
|
+
* NOT mirrored in `crates/failproofaid/src/paths.rs` yet: nothing in Rust
|
|
243
|
+
* takes this lock until the daemon grows its audit lane, and a `pub fn` no
|
|
244
|
+
* caller uses is a dead_code failure under `-D warnings`.
|
|
245
|
+
*/
|
|
246
|
+
export const auditLockFile = (home?: string) => resolve(runDir(home), "audit.lock");
|
|
247
|
+
|
|
248
|
+
// ── Daemon scratch state ─────────────────────────────────────────────────────
|
|
249
|
+
|
|
250
|
+
/** Everything the daemon writes that a human would never open by hand. */
|
|
251
|
+
export const stateDir = (home?: string) => atHome(home, "state");
|
|
252
|
+
/**
|
|
253
|
+
* Where the policy loader writes its ESM shim.
|
|
254
|
+
*
|
|
255
|
+
* Under the user's own home rather than beside the installed package: that
|
|
256
|
+
* directory belongs to whoever installed failproofai, and on a system-wide
|
|
257
|
+
* install it is root-owned, which made every non-root hook fail to load
|
|
258
|
+
* cloud-managed and custom policies — silently, and open.
|
|
259
|
+
*/
|
|
260
|
+
export const shimsDir = (home?: string) => resolve(stateDir(home), "shims");
|
|
261
|
+
export const spoolDir = (home?: string) => resolve(stateDir(home), "spool");
|
|
262
|
+
export const failedDir = (home?: string) => resolve(stateDir(home), "failed");
|
|
263
|
+
export const collectorHealthFile = (home?: string) => resolve(stateDir(home), "collector-health.json");
|
|
264
|
+
/** Per-session enforcement pauses, keyed by a hash of the session id. */
|
|
265
|
+
export const sessionPauseDir = () => resolve(stateDir(), "sessions");
|
|
266
|
+
/**
|
|
267
|
+
* When the scheduled audit last ran, and when the next one is due.
|
|
268
|
+
*
|
|
269
|
+
* The DAEMON is the sole writer (`crates/failproofaid/src/audit_lane.rs`, which
|
|
270
|
+
* mirrors this path in `paths.rs`) — it owns the schedule, and a second writer
|
|
271
|
+
* racing it could hand a machine two full scans back to back. Everything on this
|
|
272
|
+
* side reads it: the interval itself lives in `config.json`'s `audit` object,
|
|
273
|
+
* which a human edits, while this file is derived state a human never opens,
|
|
274
|
+
* which is why it sits under `state/` rather than beside the audit results.
|
|
275
|
+
*/
|
|
276
|
+
export const auditScheduleFile = (home?: string) => resolve(stateDir(home), "audit-schedule.json");
|
|
277
|
+
/**
|
|
278
|
+
* The anonymous instance id this machine reports telemetry under.
|
|
279
|
+
*
|
|
280
|
+
* The mirror image of `auditScheduleFile()` above: here the CLI is the sole
|
|
281
|
+
* writer (`getInstanceId()` in `lib/telemetry-id.ts`, which persists whatever it
|
|
282
|
+
* resolved) and **failproofaid** only reads, through `telemetry_id_path()` in
|
|
283
|
+
* `crates/failproofaid/src/paths.rs`. The daemon cannot re-derive the value —
|
|
284
|
+
* `getInstanceId`'s middle tier hashes Node-formatted strings (`os.arch()` is
|
|
285
|
+
* `x64` where Rust says `x86_64`), and a near-miss there does not fail, it
|
|
286
|
+
* silently files one machine under two PostHog persons — so this file is how the
|
|
287
|
+
* two agree. Derived state a human never opens, hence `state/` rather than
|
|
288
|
+
* beside `config.json`.
|
|
289
|
+
*/
|
|
290
|
+
export const telemetryIdFile = (home?: string) => resolve(stateDir(home), "telemetry-id");
|
|
291
|
+
export const launcherMarker = (home?: string) => resolve(stateDir(home), "launcher-configured");
|
|
292
|
+
/**
|
|
293
|
+
* The last first-run setup attempt that ABORTED, and why.
|
|
294
|
+
*
|
|
295
|
+
* Deliberately NOT one of `isConfigured()`'s signals: a failed attempt must
|
|
296
|
+
* never make a machine read as set up. It exists only so the next command can
|
|
297
|
+
* tell "never tried" from "tried and could not finish" — the wizard writes
|
|
298
|
+
* nothing on an abort, so without this the two are identical and setup
|
|
299
|
+
* relaunches on every single command forever.
|
|
300
|
+
*
|
|
301
|
+
* Under `state/` with the other derived markers a human never opens.
|
|
302
|
+
*/
|
|
303
|
+
export const onboardingAttemptFile = (home?: string) =>
|
|
304
|
+
resolve(stateDir(home), "onboarding-attempt.json");
|
|
305
|
+
/**
|
|
306
|
+
* The version that last reported an install, so an upgrade is reported once.
|
|
307
|
+
*
|
|
308
|
+
* Under `state/` in layout 2 like every other piece of derived state, and that
|
|
309
|
+
* placement fixes a real bug rather than being tidiness: at the root it was
|
|
310
|
+
* `~/.failproofai/last-version`, which `detectLayout()` lists as a LAYOUT-1
|
|
311
|
+
* MARKER — while the code that writes it still runs under layout 2, and runs
|
|
312
|
+
* BEFORE the layout check. So on a genuinely fresh machine the CLI created the
|
|
313
|
+
* file, then immediately read it back as evidence of an old layout, classified
|
|
314
|
+
* a brand-new home as stale, and opened every new user's first command with
|
|
315
|
+
* "failproofai reorganised … Removed 1 item(s) from the old layout."
|
|
316
|
+
*/
|
|
317
|
+
export const lastVersionFile = (home?: string) => resolve(stateDir(home), "last-version");
|
|
318
|
+
export const onboardingLockFile = (home?: string) => resolve(stateDir(home), "onboarding.lock");
|
|
319
|
+
export const codexSessionPathsFile = (home?: string) => resolve(stateDir(home), "codex-session-paths.json");
|
|
320
|
+
|
|
321
|
+
export const logsDir = (home?: string) => atHome(home, "logs");
|
|
322
|
+
|
|
323
|
+
// ── Migration state ──────────────────────────────────────────────────────────
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Where a migration records what it did, and what it saved first.
|
|
327
|
+
*
|
|
328
|
+
* The migration CODE ships in the npm package, never here. A home written by
|
|
329
|
+
* 1.0.0 contains only 1.0.0's migrations, and the steps that get that machine
|
|
330
|
+
* forward are precisely the ones its old install never had — so the installed
|
|
331
|
+
* CLI, always the newest thing on the machine, is the only correct source. What
|
|
332
|
+
* belongs in the home is the STATE: which steps have run, and the files they
|
|
333
|
+
* saved before running. Exactly the split a database makes, where migrations are
|
|
334
|
+
* code in the repo and the applied set is a table.
|
|
335
|
+
*/
|
|
336
|
+
export const migrationsDir = (home?: string) => atHome(home, "migrations");
|
|
337
|
+
|
|
338
|
+
/** One line per step that has run: `{from, to, cli, at, durationMs, ok}`. */
|
|
339
|
+
export const migrationLedgerFile = (home?: string) =>
|
|
340
|
+
resolve(migrationsDir(home), "applied.json");
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Copies of the irreplaceable files, taken before the layout-`n` migration ran.
|
|
344
|
+
*
|
|
345
|
+
* NOT a copy of the whole home, and the reason is that `HOME_CLASSES` already
|
|
346
|
+
* made one unnecessary: a migration deletes only `derived` and `refetchable`
|
|
347
|
+
* paths, so there is no longer anything irreplaceable for it to lose by design.
|
|
348
|
+
* What remains worth insuring against is a BUG in a step — and for that, the few
|
|
349
|
+
* kilobytes of `config.json`, `credentials.json`, `policies-config.json`, the
|
|
350
|
+
* marker, and the retired layout's own config are a real undo, where a full-home
|
|
351
|
+
* copy would cost a duplicate of `bin/` and `hook-activity/` and need a
|
|
352
|
+
* two-rename window that also has to dodge a live daemon holding `run/`.
|
|
353
|
+
*/
|
|
354
|
+
export const migrationBackupDir = (layout: number, home?: string) =>
|
|
355
|
+
resolve(migrationsDir(home), `backup-layout${layout}`);
|
|
356
|
+
|
|
357
|
+
// ── What each path HOLDS ─────────────────────────────────────────────────────
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* What kind of data a path in the home holds, which is what decides whether an
|
|
361
|
+
* upgrade may throw it away.
|
|
362
|
+
*
|
|
363
|
+
* The rule, stated once: **derived and re-fetchable may be dropped; anything a
|
|
364
|
+
* person typed, anything not yet delivered, and anything that identifies the
|
|
365
|
+
* machine is carried.**
|
|
366
|
+
*/
|
|
367
|
+
export type DataClass =
|
|
368
|
+
/** A person set this and nothing regenerates it. Never deleted. */
|
|
369
|
+
| "user-typed"
|
|
370
|
+
/** Recorded here and not yet shipped anywhere. Never deleted. */
|
|
371
|
+
| "undelivered"
|
|
372
|
+
/** Stable ids and watermarks. Never deleted — a new one is a new machine. */
|
|
373
|
+
| "identity"
|
|
374
|
+
/** Rebuilt on demand. May be dropped. */
|
|
375
|
+
| "derived"
|
|
376
|
+
/** The server is the source of truth. May be dropped and re-fetched. */
|
|
377
|
+
| "refetchable"
|
|
378
|
+
/** Sockets, locks, binaries: live process state. Never touched by a reset. */
|
|
379
|
+
| "ephemeral";
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Every path in the home, and what it holds.
|
|
383
|
+
*
|
|
384
|
+
* `resettablePaths()` is DERIVED from this rather than hand-listed beside it,
|
|
385
|
+
* and that is the whole point. Before this table one path was declared in four
|
|
386
|
+
* places — as a function above, again in `legacy` once it moved, again in the
|
|
387
|
+
* delete list, and again in `CARRIED_POLICY_CONFIG_KEYS` if it held carried
|
|
388
|
+
* keys — with nothing making the four agree. **Every silent-data-loss bug this
|
|
389
|
+
* module has had is one of those lists falling out of sync with a path that
|
|
390
|
+
* moved:** layout 1's `policies/` (hand-written source, deleted), layout 2's
|
|
391
|
+
* nested policy config (enabled policies, emptied), `cache/hook-activity` (the
|
|
392
|
+
* whole decision log, deleted with its parent), the layout-2 `credentials.toml`
|
|
393
|
+
* (a live token left behind), and `collector.sources.extra_paths` — which was
|
|
394
|
+
* on the delete list by way of `config.json` and would have taken every extra
|
|
395
|
+
* path a user typed at the next layout bump.
|
|
396
|
+
*
|
|
397
|
+
* Two consequences worth naming:
|
|
398
|
+
*
|
|
399
|
+
* - **Forgetting is now safe.** A path absent from this table is not deleted,
|
|
400
|
+
* because the delete list is a filter over what is here rather than a
|
|
401
|
+
* catch-all. The failure mode of an oversight becomes a stale file — loud
|
|
402
|
+
* and recoverable — instead of a deleted cloud token.
|
|
403
|
+
* - **`state/` is not classified as a whole**, because it is mixed: its
|
|
404
|
+
* `spool/` and `telemetry-id` are things we must never drop, and everything
|
|
405
|
+
* else under it is scratch. Listing the parent is exactly how a reset came
|
|
406
|
+
* to delete undelivered events and the machine's own telemetry identity.
|
|
407
|
+
*
|
|
408
|
+
* `home-classification.test.ts` asserts every exported path function in this
|
|
409
|
+
* module is either classified here or covered by a classified parent, so the
|
|
410
|
+
* next path added to the home cannot skip the one question that matters.
|
|
411
|
+
*/
|
|
412
|
+
export const HOME_CLASSES: readonly { path: (home?: string) => string; class: DataClass }[] = [
|
|
413
|
+
// ── Never deleted: a person typed it ──
|
|
414
|
+
// The cloud enrolment. Deleting it drops the machine out of cloud-managed
|
|
415
|
+
// policy silently — it keeps enforcing whatever it last had, reports healthy,
|
|
416
|
+
// and never reconciles again. Nothing re-derives a token.
|
|
417
|
+
{ path: credentialsFile, class: "user-typed" },
|
|
418
|
+
// Holds `daemon.configured` (the flag that makes the machine fail closed),
|
|
419
|
+
// the collector preferences, `[audit] auto`, the telemetry opt-out, and
|
|
420
|
+
// `collector.sources.*.extra_paths` — the entire output of `harness add-path`.
|
|
421
|
+
{ path: configFile, class: "user-typed" },
|
|
422
|
+
// The builtin enable/disable set and per-policy params. `resetHome` used to
|
|
423
|
+
// clear this and carry eight named keys back over; it is simply kept now.
|
|
424
|
+
{ path: globalPolicyConfigFile, class: "user-typed" },
|
|
425
|
+
// The user's own convention policies, the `lib/` they import and the data
|
|
426
|
+
// files they read. `at("policies")` was on the delete list once: hand-written
|
|
427
|
+
// source destroyed, while `isConfigured()` still read true so the wizard never
|
|
428
|
+
// re-asked and hooks kept firing against an empty policy set.
|
|
429
|
+
{ path: policiesDir, class: "user-typed" },
|
|
430
|
+
|
|
431
|
+
// ── Never deleted: recorded and not yet shipped ──
|
|
432
|
+
// Batches read out of transcripts and queued for upload. The reason losing
|
|
433
|
+
// these is PERMANENT and not merely slow is `cursorsDir` below: the watermark
|
|
434
|
+
// has already advanced past them, so nothing will ever read that range again.
|
|
435
|
+
{ path: spoolDir, class: "undelivered" },
|
|
436
|
+
{ path: failedDir, class: "undelivered" },
|
|
437
|
+
// The SDK spool (`events/` + `failed/`), same argument.
|
|
438
|
+
{ path: customAgentsDir, class: "undelivered" },
|
|
439
|
+
// The decision log the dashboard's activity tab reads. Neither derived nor
|
|
440
|
+
// re-fetchable: it is the record of what this machine did, and nothing
|
|
441
|
+
// regenerates it. Deleting its layout-1 parent threw away every decision a
|
|
442
|
+
// machine had recorded, which is why `migrateHookActivity()` exists.
|
|
443
|
+
{ path: hookActivityDir, class: "undelivered" },
|
|
444
|
+
// Requests the CLI wrote for the daemon to drain on its next tick. The file's
|
|
445
|
+
// existence IS the pending state, so deleting one silently cancels something
|
|
446
|
+
// a person asked for. Rust-only paths (`crates/failproofaid/src/paths.rs`),
|
|
447
|
+
// hence spelled here rather than exported — nothing on this side reads them.
|
|
448
|
+
{ path: (home) => resolve(stateDir(home), "flush-request.json"), class: "undelivered" },
|
|
449
|
+
{ path: (home) => resolve(stateDir(home), "backfill-request.json"), class: "undelivered" },
|
|
450
|
+
|
|
451
|
+
// ── Never deleted: it names the machine ──
|
|
452
|
+
// Per-source watermarks. Kept out of the reset so pages carried by
|
|
453
|
+
// `migrateHookActivity()` are not re-shipped in full — it MOVES them, which
|
|
454
|
+
// preserves the inode a cursor is keyed on. A cursor whose file is gone is
|
|
455
|
+
// inert (`retain_existing` drops it), so keeping them costs nothing.
|
|
456
|
+
{ path: cursorsDir, class: "identity" },
|
|
457
|
+
// The anonymous instance id both the CLI and the daemon report under. Tiers 1
|
|
458
|
+
// and 2 of `getInstanceId()` re-derive the same value, so most machines would
|
|
459
|
+
// survive losing it — but a machine that fell through to the daemon's own
|
|
460
|
+
// fallback would come back as a brand-new PostHog person, and no analysis
|
|
461
|
+
// spans that split.
|
|
462
|
+
{ path: telemetryIdFile, class: "identity" },
|
|
463
|
+
{ path: (home) => resolve(stateDir(home), "daemon-telemetry-id"), class: "identity" },
|
|
464
|
+
// The layout marker itself. Not user data, and `resetHome` rewrites it
|
|
465
|
+
// immediately — but listing it made a no-op reset report "removed 1 item" for
|
|
466
|
+
// a file it had just recreated.
|
|
467
|
+
{ path: versionFile, class: "identity" },
|
|
468
|
+
// The record of what this machine has been migrated through, and the copies a
|
|
469
|
+
// step took before running. A migration deleting its own audit trail would
|
|
470
|
+
// leave "what has this home been through?" answerable only by guessing, and
|
|
471
|
+
// deleting the backup is deleting the undo for the step that just ran.
|
|
472
|
+
{ path: migrationsDir, class: "identity" },
|
|
473
|
+
|
|
474
|
+
// ── May be dropped: rebuilt on demand ──
|
|
475
|
+
{ path: auditDir, class: "derived" },
|
|
476
|
+
{ path: collectorHealthFile, class: "derived" },
|
|
477
|
+
{ path: auditScheduleFile, class: "derived" },
|
|
478
|
+
{ path: codexSessionPathsFile, class: "derived" },
|
|
479
|
+
{ path: shimsDir, class: "derived" },
|
|
480
|
+
{ path: sessionPauseDir, class: "derived" },
|
|
481
|
+
{ path: logsDir, class: "derived" },
|
|
482
|
+
{ path: lastVersionFile, class: "derived" },
|
|
483
|
+
{ path: launcherMarker, class: "derived" },
|
|
484
|
+
{ path: onboardingLockFile, class: "derived" },
|
|
485
|
+
{ path: onboardingAttemptFile, class: "derived" },
|
|
486
|
+
|
|
487
|
+
// ── May be dropped: the server has it ──
|
|
488
|
+
// Re-fetched and digest-verified on the next daemon poll. This is the whole
|
|
489
|
+
// reason the delete list is per-entry rather than `rm -rf policies/`: one
|
|
490
|
+
// directory holds both the files a person wrote and the ones the fleet sent,
|
|
491
|
+
// and only the second kind may be thrown away.
|
|
492
|
+
{ path: cloudPoliciesDir, class: "refetchable" },
|
|
493
|
+
|
|
494
|
+
// ── Never touched ──
|
|
495
|
+
// A downloaded daemon binary is large, version-pinned and re-verified on use,
|
|
496
|
+
// so deleting it only forces a needless re-download.
|
|
497
|
+
{ path: binDir, class: "ephemeral" },
|
|
498
|
+
// Sockets and the singleton flock belong to a process that may be alive right
|
|
499
|
+
// now; removing them breaks it rather than resetting configuration.
|
|
500
|
+
{ path: runDir, class: "ephemeral" },
|
|
501
|
+
];
|
|
502
|
+
|
|
503
|
+
// ── Layout 1 (legacy) ────────────────────────────────────────────────────────
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Where layout 1 kept things.
|
|
507
|
+
*
|
|
508
|
+
* Retained ONLY so `detectLayout()` can recognise an old home and so the reset
|
|
509
|
+
* can delete it. Nothing reads data from these paths: the decision was
|
|
510
|
+
* wipe-and-re-setup rather than migrate, because a half-migrated home that
|
|
511
|
+
* silently reads "no data" is worse than one that says so.
|
|
512
|
+
*/
|
|
513
|
+
export const legacy = {
|
|
514
|
+
/**
|
|
515
|
+
* Layout 1's policy config — at the home root.
|
|
516
|
+
*
|
|
517
|
+
* Layout 3 puts the CURRENT config back at this exact path, so this is not a
|
|
518
|
+
* discriminating landmark on its own. `detectLayout()` checks for a layout-2+
|
|
519
|
+
* marker before consulting it; see the comment there.
|
|
520
|
+
*/
|
|
521
|
+
policyConfig: () => at("policies-config.json"),
|
|
522
|
+
/**
|
|
523
|
+
* Layout 2's `config.toml`. A landmark in its own right now: layout 1 had no
|
|
524
|
+
* such file, so its presence proves a home is newer than layout 1 even when
|
|
525
|
+
* `VERSION` is missing.
|
|
526
|
+
*/
|
|
527
|
+
configToml: () => at("config.toml"),
|
|
528
|
+
/** Layout 2's credentials, replaced by `credentials.json`. */
|
|
529
|
+
credentialsToml: () => at("credentials.toml"),
|
|
530
|
+
/** Layout 2 nested the policy config two levels down. */
|
|
531
|
+
localPoliciesDir: () => at("policies", "local-policies"),
|
|
532
|
+
/**
|
|
533
|
+
* Layout 2's policy config, at its nested path.
|
|
534
|
+
*
|
|
535
|
+
* The file `readCarriedPolicyConfig()` reads and `localPoliciesDir()` above
|
|
536
|
+
* deletes — so on the layout-2 leg this, not `policyConfig()`, is the policy
|
|
537
|
+
* selection the migration destroys. Named separately because its BASENAME is
|
|
538
|
+
* identical to the layout-1 root copy's, and the backup directory is flat.
|
|
539
|
+
*/
|
|
540
|
+
localPolicyConfig: () => at("policies", "local-policies", "policies-config.json"),
|
|
541
|
+
/** Layout 2 kept convention policies in a subdirectory. */
|
|
542
|
+
customPoliciesDir: () => at("policies", "custom-policies"),
|
|
543
|
+
// NO `cloudPoliciesDir` HERE. Layout 2 put cloud deployments at
|
|
544
|
+
// `policies/cloud-policies`, which is where layout 3 puts them too — so there
|
|
545
|
+
// is no old location to migrate from or prune, and an entry here would be a
|
|
546
|
+
// "legacy" path identical to the live one. That is not a harmless duplicate:
|
|
547
|
+
// it is exactly the shape that made `legacy.policyConfig()` unusable as a
|
|
548
|
+
// landmark, and anything treating this list as "safe to delete, it's old"
|
|
549
|
+
// would be deleting the current deployment. What DID change inside it is the
|
|
550
|
+
// shape — `deployments/<n>/` trees flattened into one `artifacts/` dir —
|
|
551
|
+
// which `cloud_policies.rs` prunes after the flip, not this list.
|
|
552
|
+
policyConfigLocal: () => at("policies-config.local.json"),
|
|
553
|
+
cloudCredentials: () => at("cloud.json"),
|
|
554
|
+
ingestCredentials: () => at("ingest.json"),
|
|
555
|
+
launcherMarker: () => at(".launcher-configured"),
|
|
556
|
+
lastVersion: () => at("last-version"),
|
|
557
|
+
auditDashboard: () => at("audit-dashboard.json"),
|
|
558
|
+
cacheDir: () => at("cache"),
|
|
559
|
+
hookActivityDir: () => at("cache", "hook-activity"),
|
|
560
|
+
auditCacheDir: () => at("cache", "audit"),
|
|
561
|
+
codexSessionPaths: () => at("cache", "codex-session-paths.json"),
|
|
562
|
+
spoolDir: () => at("spool"),
|
|
563
|
+
failedDir: () => at("failed"),
|
|
564
|
+
collectorHealth: () => at("collector-health.json"),
|
|
565
|
+
sessionPauseDir: () => at("state", "sessions"),
|
|
566
|
+
cloudManagedPolicies: () => at("policies", "cloud-managed"),
|
|
567
|
+
onboardingLock: () => at(".onboarding.lock"),
|
|
568
|
+
} as const;
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* Every path a reset must remove, in the order it should remove them.
|
|
572
|
+
*
|
|
573
|
+
* Enumerated rather than "delete the home directory" so a reset never takes
|
|
574
|
+
* out something a future layout adds and this list has not been taught about
|
|
575
|
+
* — and so the function is auditable at a glance, which matters for anything
|
|
576
|
+
* that deletes user data.
|
|
577
|
+
*
|
|
578
|
+
* TWO HALVES, and they are not maintained the same way. The paths of layouts
|
|
579
|
+
* that no longer exist are listed by hand below, because a retired path has no
|
|
580
|
+
* definition left to hang a class off — it exists only in this file. The paths
|
|
581
|
+
* of the CURRENT layout are DERIVED from `HOME_CLASSES`, so a path that moves
|
|
582
|
+
* or is added cannot silently fall off (or onto) the list. See `HOME_CLASSES`
|
|
583
|
+
* for what each class means and which incidents the split is answering.
|
|
584
|
+
*/
|
|
585
|
+
export function resettablePaths(): string[] {
|
|
586
|
+
return [
|
|
587
|
+
...retiredLayoutPaths(),
|
|
588
|
+
// The current layout, by what each path HOLDS. `user-typed`, `undelivered`
|
|
589
|
+
// and `identity` are absent from this list by construction rather than by
|
|
590
|
+
// anyone remembering to leave them out.
|
|
591
|
+
...HOME_CLASSES.filter((e) => e.class === "derived" || e.class === "refetchable").map((e) =>
|
|
592
|
+
e.path(),
|
|
593
|
+
),
|
|
594
|
+
];
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* The paths of layouts this build no longer writes.
|
|
599
|
+
*
|
|
600
|
+
* Hand-listed, and they have to be: a retired path has no definition to carry a
|
|
601
|
+
* class, and `legacy` is the only place it still exists. Each entry is here
|
|
602
|
+
* because an upgrade would otherwise leave it behind — see the notes inline,
|
|
603
|
+
* every one of which records something that actually happened.
|
|
604
|
+
*
|
|
605
|
+
* Phase-splitting these per migration step is what the migration registry does
|
|
606
|
+
* with them next; until then they are one list because `resetHome` is one step.
|
|
607
|
+
*/
|
|
608
|
+
function retiredLayoutPaths(): string[] {
|
|
609
|
+
return [
|
|
610
|
+
// Layout 1
|
|
611
|
+
//
|
|
612
|
+
// NOT `legacy.policyConfig()`. It is `at("policies-config.json")` — the
|
|
613
|
+
// EXACT path layout 3 puts the live config back at, which `legacy`'s own
|
|
614
|
+
// note records and `detectLayout()` has a whole ordering rule about. Listing
|
|
615
|
+
// it here while `HOME_CLASSES` calls the same path `user-typed` would have
|
|
616
|
+
// the two halves of this function contradict each other, and the delete
|
|
617
|
+
// would win.
|
|
618
|
+
//
|
|
619
|
+
// Leaving it in place is also strictly better than what it replaced. The old
|
|
620
|
+
// sequence was delete-then-carry-eight-named-keys, so every key outside
|
|
621
|
+
// `CARRIED_POLICY_CONFIG_KEYS` was dropped on a layout-1 upgrade; now the
|
|
622
|
+
// file is simply not touched and keeps everything. `readCarriedPolicyConfig`
|
|
623
|
+
// is narrowed to layout 2's NESTED copy accordingly — that path really is
|
|
624
|
+
// deleted (`legacy.localPoliciesDir()`, below) and really does need carrying.
|
|
625
|
+
//
|
|
626
|
+
// The project-scope `policies-config.local.json` is a different file at a
|
|
627
|
+
// different path (`{cwd}/.failproofai/`, see `hooks-config.ts`); the global
|
|
628
|
+
// one below is a layout-1 artefact nothing reads.
|
|
629
|
+
legacy.policyConfigLocal(),
|
|
630
|
+
legacy.cloudCredentials(),
|
|
631
|
+
legacy.ingestCredentials(),
|
|
632
|
+
legacy.launcherMarker(),
|
|
633
|
+
legacy.lastVersion(),
|
|
634
|
+
legacy.auditDashboard(),
|
|
635
|
+
// `legacy.cacheDir()` — the whole of `cache/` — stood here, and it CONTAINS
|
|
636
|
+
// `cache/hook-activity`: layout 1's decision log. Deleting the parent threw
|
|
637
|
+
// away every decision the machine had ever recorded, which is the data the
|
|
638
|
+
// dashboard's activity tab exists to show. Its children are now named
|
|
639
|
+
// individually so the log can be carried across by
|
|
640
|
+
// `migrateHookActivity()`, and everything else in `cache/` still goes —
|
|
641
|
+
// both remaining entries are re-derived on demand.
|
|
642
|
+
legacy.auditCacheDir(),
|
|
643
|
+
legacy.codexSessionPaths(),
|
|
644
|
+
legacy.spoolDir(),
|
|
645
|
+
legacy.failedDir(),
|
|
646
|
+
legacy.collectorHealth(),
|
|
647
|
+
legacy.onboardingLock(),
|
|
648
|
+
legacy.cloudManagedPolicies(),
|
|
649
|
+
// Layout 2's files, by their layout-2 names. Without these a layout-2 home
|
|
650
|
+
// upgrading to 3 keeps `config.toml` and `credentials.toml` sitting next to
|
|
651
|
+
// the new `.json` pair — two configs, one of them stale, and the reset that
|
|
652
|
+
// was supposed to clear the old layout leaving its most important files
|
|
653
|
+
// behind. `credentials.toml` is the worse half: a live token in a file
|
|
654
|
+
// nothing reads any more and nothing will clean up.
|
|
655
|
+
legacy.configToml(),
|
|
656
|
+
legacy.credentialsToml(),
|
|
657
|
+
legacy.localPoliciesDir(),
|
|
658
|
+
// NOT `legacy.customPoliciesDir()`. `migrateConventionPolicies()` empties it
|
|
659
|
+
// and removes it itself, and whatever it could NOT move is the user's own
|
|
660
|
+
// hand-written source — which this list would delete moments after that
|
|
661
|
+
// function deliberately decided to preserve it. That is not hypothetical:
|
|
662
|
+
// a `lib/` of helpers colliding with a stale `policies/lib/` was destroyed
|
|
663
|
+
// outright, and the policy that did move was left importing a file that no
|
|
664
|
+
// longer existed.
|
|
665
|
+
//
|
|
666
|
+
// Everything that used to follow here — `globalPolicyConfigFile()`,
|
|
667
|
+
// `cloudPoliciesDir()`, `at("state")`, `configFile()`, `credentialsFile()`,
|
|
668
|
+
// `auditDir()`, `customAgentsDir()`, `logsDir()` — was the CURRENT layout,
|
|
669
|
+
// hand-listed. It is derived from `HOME_CLASSES` now, and five of those
|
|
670
|
+
// entries stopped being deleted as a result, each for a reason recorded on
|
|
671
|
+
// its row: the cloud token, the whole of `config.json` (including the
|
|
672
|
+
// `extra_paths` a user typed), the undelivered spool, the SDK spool, and the
|
|
673
|
+
// machine's telemetry identity.
|
|
674
|
+
//
|
|
675
|
+
// `at("state")` is the sharpest of them. It is MIXED — `spool/` and
|
|
676
|
+
// `telemetry-id` sit under it beside a dozen scratch files — so listing the
|
|
677
|
+
// parent is precisely how a reset came to delete events that were recorded,
|
|
678
|
+
// queued, and then unreachable forever, because `cursors/` deliberately
|
|
679
|
+
// survives and the watermark had already moved past them. Its scratch
|
|
680
|
+
// children are classified individually now and the parent is not listed at
|
|
681
|
+
// all, so anything under it this table has not been taught about survives
|
|
682
|
+
// rather than being swept up.
|
|
683
|
+
//
|
|
684
|
+
// Two notes worth keeping from the old list, because they explain absences
|
|
685
|
+
// that still hold:
|
|
686
|
+
//
|
|
687
|
+
// `policies/` is `user-typed`, not absent by oversight. On layout 1 that
|
|
688
|
+
// directory IS the documented home for hand-written personal policies —
|
|
689
|
+
// `docs/configuration.mdx` names `~/.failproofai/policies/` as the user
|
|
690
|
+
// scope, and `manager.ts` read it. It stood on this list once: source files
|
|
691
|
+
// a person wrote, nothing regenerating them, nothing backing them up, and a
|
|
692
|
+
// reset message that named only "policy config, activity history and audit
|
|
693
|
+
// cache". Worse, the machine then reported itself configured —
|
|
694
|
+
// `isConfigured()` is a union that still sees the agent CLIs' untouched
|
|
695
|
+
// settings files — so the wizard was skipped and hooks kept firing against
|
|
696
|
+
// an empty policy set. Its `cloud-policies/` CHILD is `refetchable` and does
|
|
697
|
+
// still go, which is the whole reason this is a per-entry list and not
|
|
698
|
+
// `rm -rf policies/`.
|
|
699
|
+
//
|
|
700
|
+
// `cursors/` is `identity` for a reason load-bearing to the activity
|
|
701
|
+
// migration rather than a separate opinion. Cursors are keyed on
|
|
702
|
+
// `(device, inode)`; `migrateHookActivity()` MOVES pages, which preserves
|
|
703
|
+
// the inode, so a surviving cursor still points at the file it belongs to
|
|
704
|
+
// and resumes at the right offset. Delete the cursors and every carried page
|
|
705
|
+
// reads as new and re-ships in full — the outcome the move exists to avoid.
|
|
706
|
+
// A cursor whose file is gone is inert (`retain_existing` drops it), so
|
|
707
|
+
// keeping them costs nothing when there is nothing to resume.
|
|
708
|
+
//
|
|
709
|
+
// And `hook-activity/` is `undelivered`, never listed: it is the DESTINATION
|
|
710
|
+
// `migrateHookActivity()` moves layout 1's log into, so listing it deleted
|
|
711
|
+
// the migration moments after it happened — the reset runs every path in
|
|
712
|
+
// this list after the migrations.
|
|
713
|
+
];
|
|
714
|
+
}
|