failproofai 1.0.0-beta.4 → 1.0.0-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-path-routes-manifest.json +2 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/routes-manifest.json +6 -0
- package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js +3 -1
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js +3 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/audit/invite/route.js +3 -2
- package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js +4 -3
- package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/status/route.js +1 -1
- package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js +2 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +3 -2
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route.js +3 -2
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js +3 -2
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js +3 -2
- package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page.js +5 -3
- package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js +3 -1
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +10 -10
- package/.next/standalone/.next/server/app/policies/page.js +4 -2
- package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js +4 -2
- package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +6 -4
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js +4 -2
- package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/page/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/settings/page/build-manifest.json +18 -0
- package/.next/standalone/.next/server/app/settings/page/next-font-manifest.json +6 -0
- package/.next/standalone/.next/server/app/settings/page/react-loadable-manifest.json +1 -0
- package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +53 -0
- package/.next/standalone/.next/server/app/settings/page.js +18 -0
- package/.next/standalone/.next/server/app/settings/page.js.map +5 -0
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app-paths-manifest.json +2 -1
- package/.next/standalone/.next/server/chunks/{[externals]__1nl3dvw._.js → [externals]__0r-zamh._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__06hexd0._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__094p1f1._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_0xu5z._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ed01_d._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0g0vcwt._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0h3lfmp._.js → [root-of-the-server]__0ky_n0r._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__18d-9oi._.js → [root-of-the-server]__0lk_935._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1p7s8-d._.js → [root-of-the-server]__0pbp9fe._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q-v9z2._.js +1 -1
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__10oa-v9._.js → [root-of-the-server]__0v2fpxe._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0sb_5m8._.js → [root-of-the-server]__131ebum._.js} +3 -3
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0-dh5jy._.js → [root-of-the-server]__1_ps0jw._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0l4vuqm._.js → [root-of-the-server]__1a7i2q4._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ibjy5x._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1iny24d._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tvn4wf._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tyedjt._.js +3 -0
- package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +5 -0
- package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +5 -0
- package/.next/standalone/.next/server/chunks/lib_telemetry_ts_0dctyyw._.js +5 -0
- package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +5 -5
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__06bp_fg._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__074qmkp._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0spkm68._.js +10 -10
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1_a_gwn._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1a2hcb_._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1e7-pa7._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0rtdfof._.js → [root-of-the-server]__1rdruw4._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1rv-sc9._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1tyf0tc._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1u-wx42._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1v185mo._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0rag5dg._.js → [root-of-the-server]__1yw368c._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_0-yi74u._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_04mekdy._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0igtyj5._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0r-dsre._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0rjgfln._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0se484m._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0uz7o9y._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_11_p9y8._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1fahg9e._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1gmzkwj._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/_1w8sola._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1w_6p9g._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0dwo94s.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +5 -0
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/middleware.js +2 -2
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +54 -12
- package/.next/standalone/.next/static/chunks/{2c90h1g6x8z8y.js → 0_2n13i94rnw5.js} +1 -1
- package/.next/standalone/.next/static/chunks/1bm0q12hgs22l.css +2 -0
- package/.next/standalone/.next/static/chunks/1v1gqvpjk62jm.js +1 -0
- package/.next/standalone/.next/static/chunks/23557z4e6dtsr.js +1 -0
- package/.next/standalone/.next/static/chunks/28zkwzu50puki.js +1 -0
- package/.next/standalone/.next/static/chunks/2uvhw57mf9lg_.css +2 -0
- package/.next/standalone/.next/static/chunks/3081gykdubv8b.js +1 -0
- package/.next/standalone/.next/static/chunks/{06jakt_xhoolk.js → 34fa65k0cldkj.js} +1 -1
- package/.next/standalone/.next/static/chunks/35v07j9gc1pvr.js +6 -0
- package/.next/standalone/.next/static/chunks/{2zb3m1tzq6h98.js → 3f_939wi3kfnx.js} +22 -22
- package/.next/standalone/.next/static/chunks/{31cqiv_cpgj9m.js → 3p1vpm2_-tfwm.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0ue9ak_xexiqh.js → 3rbpw_waieafm.js} +1 -1
- package/.next/standalone/.next/static/chunks/40ffnfpkeyvb0.js +1 -0
- package/.next/standalone/app/actions/get-hooks-config.ts +2 -1
- package/.next/standalone/app/actions/get-scheduled-audit.ts +70 -0
- package/.next/standalone/app/actions/update-scheduled-audit.ts +44 -0
- package/.next/standalone/app/api/audit/run/route.ts +28 -0
- package/.next/standalone/app/api/audit/status/route.ts +13 -1
- package/.next/standalone/app/api/auth/status/route.ts +1 -1
- package/.next/standalone/app/audit/_components/auth-dialog.css +159 -0
- package/.next/standalone/app/audit/_components/auth-dialog.tsx +3 -0
- package/.next/standalone/app/audit/audit-styles.css +6 -149
- package/.next/standalone/app/settings/page.tsx +31 -0
- package/.next/standalone/app/settings/settings-client.tsx +488 -0
- package/.next/standalone/components/navbar.tsx +2 -0
- package/.next/standalone/lib/auth/api-server-client.ts +2 -3
- package/.next/standalone/lib/auth/auth-store.ts +4 -4
- package/.next/standalone/lib/codex-sessions.ts +2 -1
- package/.next/standalone/lib/dashboard-host.ts +101 -0
- package/.next/standalone/lib/install-check.ts +22 -7
- package/.next/standalone/lib/pi-sessions.ts +99 -14
- package/.next/standalone/lib/telemetry-enabled.ts +54 -0
- package/.next/standalone/lib/telemetry-id.ts +52 -1
- package/.next/standalone/lib/telemetry.ts +8 -4
- package/.next/standalone/node_modules/react/cjs/react.development.js +1 -1
- package/.next/standalone/node_modules/react/cjs/react.production.js +1 -1
- package/.next/standalone/node_modules/react/package.json +3 -3
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.browser.production.js +1 -1
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.node.production.js +1 -1
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.browser.production.js +3 -3
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.edge.production.js +3 -3
- package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.node.production.js +3 -3
- package/.next/standalone/node_modules/react-dom/cjs/react-dom.production.js +1 -1
- package/.next/standalone/node_modules/react-dom/package.json +4 -4
- package/.next/standalone/package.json +7 -6
- package/.next/standalone/proxy.ts +89 -1
- package/.next/standalone/server.js +1 -1
- package/bin/failproofai.mjs +197 -80
- package/dist/cli.mjs +17699 -15345
- package/dist/worker.mjs +1620 -257
- package/lib/auth/api-server-client.ts +2 -3
- package/lib/auth/auth-store.ts +4 -4
- package/lib/codex-sessions.ts +2 -1
- package/lib/dashboard-host.ts +101 -0
- package/lib/install-check.ts +22 -7
- package/lib/pi-sessions.ts +99 -14
- package/lib/telemetry-enabled.ts +54 -0
- package/lib/telemetry-id.ts +52 -1
- package/lib/telemetry.ts +8 -4
- package/package.json +7 -6
- package/scripts/install-telemetry.mjs +8 -1
- package/scripts/launch.ts +25 -3
- package/scripts/parse-script-args.ts +17 -1
- package/scripts/prune-standalone.mjs +20 -0
- package/scripts/translate-docs/readme-translator.ts +163 -4
- package/scripts/validate-mdx.ts +153 -13
- package/src/audit/audit-lock.ts +285 -0
- package/src/audit/audit-schedule.ts +111 -0
- package/src/audit/cache.ts +18 -4
- package/src/audit/cli-adapters/goose.ts +2 -1
- package/src/audit/cli-adapters/hermes.ts +28 -10
- package/src/audit/cli.ts +191 -35
- package/src/audit/dashboard-cache.ts +2 -1
- package/src/hooks/builtin-policies.ts +100 -3
- package/src/hooks/cloud-connection.ts +163 -14
- package/src/hooks/cloud-enrollment-cli.ts +119 -21
- package/src/hooks/cloud-enrollment.ts +87 -17
- package/src/hooks/cloud-introspect.ts +147 -0
- package/src/hooks/cloud-managed-policies.ts +33 -2
- package/src/hooks/collector-config.ts +32 -40
- package/src/hooks/configure-wizard.ts +696 -318
- package/src/hooks/custom-hooks-loader.ts +125 -11
- package/src/hooks/daemon-client.ts +83 -17
- package/src/hooks/daemon-download.ts +54 -2
- package/src/hooks/daemon-service.ts +595 -27
- package/src/hooks/first-run-gate.ts +39 -0
- package/src/hooks/fp-config.ts +497 -0
- package/src/hooks/fp-home.ts +342 -0
- package/src/hooks/fp-reset.ts +332 -0
- package/src/hooks/handler.ts +42 -1
- package/src/hooks/hook-activity-store.ts +35 -20
- package/src/hooks/hook-logger.ts +2 -1
- package/src/hooks/hook-telemetry.ts +5 -1
- package/src/hooks/hooks-config.ts +4 -3
- package/src/hooks/loader-utils.ts +166 -5
- package/src/hooks/manager.ts +5 -4
- package/src/hooks/onboarding-lock.ts +119 -0
- package/src/hooks/policy-types.ts +0 -7
- package/src/hooks/session-pause-cli.ts +15 -13
- package/src/hooks/session-pause.ts +36 -4
- package/src/hooks/setup-state.ts +256 -0
- package/src/hooks/tui.ts +4 -4
- package/src/hooks/worker-server.ts +53 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0f8nu8d._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0szqzl8._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__19120tr._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1fwl2mz._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1myjm-d._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1rhmvod._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02r5bgf._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0cmdyn_._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e8sjqm._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0lkzqax._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ls0gsr._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n_uvv0._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qucxyj._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0sdrz-j._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0u02miy._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__14dd6h8._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1j4u3yd._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1zqz4v8._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/_1m_p7pi._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/node_modules_html-to-image_es_index_1q9xxca.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1ezd2jf._.js +0 -5
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1tnuifj._.js +0 -5
- package/.next/standalone/.next/static/chunks/0h7auy7hzjyhw.js +0 -1
- package/.next/standalone/.next/static/chunks/0oe2-hp0_2tzs.js +0 -6
- package/.next/standalone/.next/static/chunks/1fw3pxobk_otl.js +0 -1
- package/.next/standalone/.next/static/chunks/3h5_3u46gu9jx.js +0 -1
- package/.next/standalone/.next/static/chunks/3i27c3hcriawq.css +0 -1
- package/.next/standalone/.next/static/chunks/3zdwnnthucs_1.css +0 -2
- package/.next/standalone/.next/static/chunks/43a1ywqsg9bq9.js +0 -1
- package/.next/standalone/Cargo.lock +0 -2222
- package/.next/standalone/Cargo.toml +0 -9
- package/.next/standalone/crates/CLOUD_POLICIES.md +0 -136
- package/.next/standalone/crates/PROTOCOL.md +0 -122
- package/.next/standalone/crates/failproofaid/Cargo.toml +0 -25
- package/.next/standalone/crates/failproofaid/src/cloud_client.rs +0 -484
- package/.next/standalone/crates/failproofaid/src/cloud_policies.rs +0 -921
- package/.next/standalone/crates/failproofaid/src/lock.rs +0 -81
- package/.next/standalone/crates/failproofaid/src/main.rs +0 -532
- package/.next/standalone/crates/failproofaid/src/paths.rs +0 -201
- package/.next/standalone/crates/failproofaid/src/server.rs +0 -502
- package/.next/standalone/crates/failproofaid/src/worker.rs +0 -400
- package/.next/standalone/crates/failproofaid/tests/daemon_e2e.rs +0 -241
- package/.next/standalone/crates/fpai-collect/Cargo.toml +0 -43
- package/.next/standalone/crates/fpai-collect/src/config.rs +0 -412
- package/.next/standalone/crates/fpai-collect/src/cursor.rs +0 -520
- package/.next/standalone/crates/fpai-collect/src/delivery.rs +0 -472
- package/.next/standalone/crates/fpai-collect/src/filetail.rs +0 -484
- package/.next/standalone/crates/fpai-collect/src/health.rs +0 -369
- package/.next/standalone/crates/fpai-collect/src/lib.rs +0 -34
- package/.next/standalone/crates/fpai-collect/src/redact.rs +0 -516
- package/.next/standalone/crates/fpai-collect/src/sources/claude/mod.rs +0 -279
- package/.next/standalone/crates/fpai-collect/src/sources/claude/transform.rs +0 -619
- package/.next/standalone/crates/fpai-collect/src/sources/codex/mod.rs +0 -156
- package/.next/standalone/crates/fpai-collect/src/sources/codex/transform.rs +0 -715
- package/.next/standalone/crates/fpai-collect/src/sources/copilot/mod.rs +0 -158
- package/.next/standalone/crates/fpai-collect/src/sources/copilot/transform.rs +0 -512
- package/.next/standalone/crates/fpai-collect/src/sources/goose/mod.rs +0 -511
- package/.next/standalone/crates/fpai-collect/src/sources/goose/transform.rs +0 -586
- package/.next/standalone/crates/fpai-collect/src/sources/hermes/mod.rs +0 -318
- package/.next/standalone/crates/fpai-collect/src/sources/hermes/transform.rs +0 -579
- package/.next/standalone/crates/fpai-collect/src/sources/hooks/mod.rs +0 -310
- package/.next/standalone/crates/fpai-collect/src/sources/hooks/transform.rs +0 -448
- package/.next/standalone/crates/fpai-collect/src/sources/mod.rs +0 -23
- package/.next/standalone/crates/fpai-collect/src/sources/openclaw/mod.rs +0 -176
- package/.next/standalone/crates/fpai-collect/src/sources/openclaw/transform.rs +0 -500
- package/.next/standalone/crates/fpai-collect/src/sources/opencode/mod.rs +0 -315
- package/.next/standalone/crates/fpai-collect/src/sources/opencode/transform.rs +0 -493
- package/.next/standalone/crates/fpai-collect/src/sources/pi/mod.rs +0 -201
- package/.next/standalone/crates/fpai-collect/src/sources/pi/transform.rs +0 -533
- package/.next/standalone/crates/fpai-collect/src/spool.rs +0 -458
- package/.next/standalone/crates/fpai-collect/src/sqlitepoll.rs +0 -387
- package/.next/standalone/crates/fpai-collect/src/supervisor.rs +0 -423
- package/.next/standalone/crates/fpai-collect/src/uploader.rs +0 -600
- package/.next/standalone/crates/fpai-collect/tests/claude_source.rs +0 -738
- package/.next/standalone/crates/fpai-collect/tests/claude_subagents.rs +0 -393
- package/.next/standalone/crates/fpai-collect/tests/codex_source.rs +0 -975
- package/.next/standalone/crates/fpai-collect/tests/config.rs +0 -286
- package/.next/standalone/crates/fpai-collect/tests/copilot_source.rs +0 -1019
- package/.next/standalone/crates/fpai-collect/tests/delivery.rs +0 -281
- package/.next/standalone/crates/fpai-collect/tests/goose_source.rs +0 -1008
- package/.next/standalone/crates/fpai-collect/tests/hermes_source.rs +0 -1129
- package/.next/standalone/crates/fpai-collect/tests/hooks_source.rs +0 -621
- package/.next/standalone/crates/fpai-collect/tests/openclaw_source.rs +0 -854
- package/.next/standalone/crates/fpai-collect/tests/opencode_source.rs +0 -1478
- package/.next/standalone/crates/fpai-collect/tests/pi_source.rs +0 -1191
- package/.next/standalone/crates/fpai-collect/tests/supervisor.rs +0 -290
- package/.next/standalone/crates/fpai-collect/tests/uploader.rs +0 -506
- package/.next/standalone/crates/fpai-ipc/Cargo.toml +0 -16
- package/.next/standalone/crates/fpai-ipc/src/envelope.rs +0 -175
- package/.next/standalone/crates/fpai-ipc/src/framing.rs +0 -177
- package/.next/standalone/crates/fpai-ipc/src/lib.rs +0 -10
- package/.next/standalone/crates/fpai-ipc/src/peer.rs +0 -80
- package/.next/standalone/docker-hook-sync/Dockerfile +0 -79
- package/.next/standalone/docker-hook-sync/entrypoint.sh +0 -109
- package/.next/standalone/integration-suite/Dockerfile +0 -47
- package/.next/standalone/integration-suite/README.md +0 -129
- package/.next/standalone/integration-suite/canary-policies.mjs +0 -45
- package/.next/standalone/integration-suite/capture-tokens.sh +0 -48
- package/.next/standalone/integration-suite/ci-entrypoint.sh +0 -179
- package/.next/standalone/integration-suite/inject-tokens.sh +0 -44
- package/.next/standalone/integration-suite/install-clis.sh +0 -136
- package/.next/standalone/integration-suite/probe-cli.sh +0 -248
- package/.next/standalone/integration-suite/report.js +0 -120
- package/.next/standalone/integration-suite/run.sh +0 -159
- package/.next/standalone/openclaw-plugin/index.js +0 -223
- package/.next/standalone/openclaw-plugin/openclaw.plugin.json +0 -6
- package/.next/standalone/openclaw-plugin/package.json +0 -12
- package/.next/standalone/osv-scanner.toml +0 -17
- package/.next/standalone/pi-extension/index.ts +0 -524
- package/.next/standalone/pi-extension/package.json +0 -12
- package/.next/standalone/postcss.config.mjs +0 -8
- package/.next/standalone/readme-arch-hq.gif +0 -0
- package/.next/standalone/rust-toolchain.toml +0 -4
- package/src/auth/cli.ts +0 -371
- /package/.next/standalone/.next/static/{StV6Lay7Q1cU4ysYCFJmH → Ptn8aBQl_cnNgOd0ebyv0}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{StV6Lay7Q1cU4ysYCFJmH → Ptn8aBQl_cnNgOd0ebyv0}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{StV6Lay7Q1cU4ysYCFJmH → Ptn8aBQl_cnNgOd0ebyv0}/_ssgManifest.js +0 -0
|
@@ -126,13 +126,6 @@ export interface HooksConfig {
|
|
|
126
126
|
* Only ever written explicitly as `false`.
|
|
127
127
|
*/
|
|
128
128
|
customPoliciesEnabled?: boolean;
|
|
129
|
-
/**
|
|
130
|
-
* Upper bound, in ms, on how long `failproofai config --pause` may suspend
|
|
131
|
-
* enforcement. Only ever LOWERS the built-in 8h ceiling — a value above it is
|
|
132
|
-
* clamped back down, because a ceiling a project can raise is not a ceiling.
|
|
133
|
-
* Absent means the built-in ceiling applies.
|
|
134
|
-
*/
|
|
135
|
-
maxPauseMs?: number;
|
|
136
129
|
/**
|
|
137
130
|
* Record of the convention policies (`.failproofai/policies/*policies.mjs`)
|
|
138
131
|
* discovered at this scope the last time a failproofai command ran.
|
|
@@ -17,7 +17,6 @@ import {
|
|
|
17
17
|
writePause,
|
|
18
18
|
type ActivePause,
|
|
19
19
|
} from "./session-pause";
|
|
20
|
-
import { readMergedHooksConfig } from "./hooks-config";
|
|
21
20
|
|
|
22
21
|
export interface PauseCommandOptions {
|
|
23
22
|
action: "pause" | "resume" | "status";
|
|
@@ -39,18 +38,21 @@ export interface PauseCommandResult {
|
|
|
39
38
|
}
|
|
40
39
|
|
|
41
40
|
/**
|
|
42
|
-
* The ceiling
|
|
43
|
-
*
|
|
41
|
+
* The ceiling on a single `--pause`.
|
|
42
|
+
*
|
|
43
|
+
* Took a `cwd` and consulted `readMergedHooksConfig(cwd).maxPauseMs` to let a
|
|
44
|
+
* project LOWER it. That path was dead: the merge in `hooks-config.ts` builds
|
|
45
|
+
* its result field by field and never emits `maxPauseMs`, so the lookup could
|
|
46
|
+
* only ever read `undefined` — and the two tests that claimed to cover it
|
|
47
|
+
* `vi.mock`ed `readMergedHooksConfig` to return a field the real function
|
|
48
|
+
* cannot produce, which is why the gap survived. The knob is removed rather
|
|
49
|
+
* than wired up: nothing documented it, nothing could have used it, and the
|
|
50
|
+
* hard ceiling was doing all the work already.
|
|
51
|
+
*
|
|
52
|
+
* Kept as a function, and still the only thing `--pause` measures against, so
|
|
53
|
+
* reinstating a config lowering later is a change in one place.
|
|
44
54
|
*/
|
|
45
|
-
export function effectiveCeilingMs(
|
|
46
|
-
try {
|
|
47
|
-
const configured = readMergedHooksConfig(cwd).maxPauseMs;
|
|
48
|
-
if (typeof configured === "number" && Number.isFinite(configured) && configured > 0) {
|
|
49
|
-
return Math.min(configured, PAUSE_CEILING_MS);
|
|
50
|
-
}
|
|
51
|
-
} catch {
|
|
52
|
-
// An unreadable config must not remove the ceiling.
|
|
53
|
-
}
|
|
55
|
+
export function effectiveCeilingMs(): number {
|
|
54
56
|
return PAUSE_CEILING_MS;
|
|
55
57
|
}
|
|
56
58
|
|
|
@@ -109,7 +111,7 @@ export function runPauseCommand(opts: PauseCommandOptions): PauseCommandResult {
|
|
|
109
111
|
// pause
|
|
110
112
|
let durationMs: number;
|
|
111
113
|
try {
|
|
112
|
-
durationMs = parsePauseDuration(opts.duration, effectiveCeilingMs(
|
|
114
|
+
durationMs = parsePauseDuration(opts.duration, effectiveCeilingMs());
|
|
113
115
|
} catch (err) {
|
|
114
116
|
return { exitCode: 1, lines: [err instanceof Error ? err.message : String(err)], affected: 0 };
|
|
115
117
|
}
|
|
@@ -27,6 +27,7 @@ import { createHash } from "node:crypto";
|
|
|
27
27
|
import { join, resolve } from "node:path";
|
|
28
28
|
import { writeJsonAtomically } from "../../lib/atomic-write";
|
|
29
29
|
import { getAllHookActivityEntries } from "./hook-activity-store";
|
|
30
|
+
import { sessionPauseDir } from "./fp-home";
|
|
30
31
|
|
|
31
32
|
const SCHEMA_VERSION = 1;
|
|
32
33
|
|
|
@@ -44,6 +45,19 @@ export interface ActivePause {
|
|
|
44
45
|
sessionId: string;
|
|
45
46
|
/** Epoch ms. */
|
|
46
47
|
pausedAt: number;
|
|
48
|
+
/**
|
|
49
|
+
* Epoch ms of the FIRST pause in this unbroken run, which the ceiling is
|
|
50
|
+
* measured from.
|
|
51
|
+
*
|
|
52
|
+
* `pausedAt` moves to now on every renewal, so a ceiling measured from it is
|
|
53
|
+
* not a ceiling at all: `--pause 8h` every seven hours suspends enforcement
|
|
54
|
+
* indefinitely, one legal command at a time, and each individual pause passes
|
|
55
|
+
* every check. This field is what makes 8h mean 8h. Carried forward by
|
|
56
|
+
* `writePause` while a pause is still live, and reset once one has expired —
|
|
57
|
+
* the limit is on how long enforcement can stay off in one stretch, not a
|
|
58
|
+
* daily quota.
|
|
59
|
+
*/
|
|
60
|
+
firstPausedAt: number;
|
|
47
61
|
/** Epoch ms. Always finite — there is no unbounded pause. */
|
|
48
62
|
expiresAt: number;
|
|
49
63
|
/** Free-form provenance, e.g. "cli". Recorded so the activity log can say who. */
|
|
@@ -59,7 +73,7 @@ interface StoredPause extends ActivePause {
|
|
|
59
73
|
export function pauseStateDir(): string {
|
|
60
74
|
const override = process.env.FAILPROOFAI_STATE_DIR;
|
|
61
75
|
if (override) return resolve(override, "sessions");
|
|
62
|
-
return
|
|
76
|
+
return sessionPauseDir();
|
|
63
77
|
}
|
|
64
78
|
|
|
65
79
|
/**
|
|
@@ -119,11 +133,22 @@ function parseStored(raw: unknown): StoredPause | null {
|
|
|
119
133
|
if (p.schemaVersion !== SCHEMA_VERSION) return null;
|
|
120
134
|
if (typeof p.sessionId !== "string" || p.sessionId.length === 0) return null;
|
|
121
135
|
if (!Number.isFinite(p.pausedAt) || !Number.isFinite(p.expiresAt)) return null;
|
|
136
|
+
const pausedAt = p.pausedAt as number;
|
|
137
|
+
// A file written before this field existed measures its ceiling from the
|
|
138
|
+
// only start it recorded. Same meaning for a pause that was never renewed.
|
|
139
|
+
const firstPausedAt = Number.isFinite(p.firstPausedAt) ? (p.firstPausedAt as number) : pausedAt;
|
|
122
140
|
return {
|
|
123
141
|
schemaVersion: SCHEMA_VERSION,
|
|
124
142
|
sessionId: p.sessionId,
|
|
125
|
-
pausedAt
|
|
126
|
-
|
|
143
|
+
pausedAt,
|
|
144
|
+
firstPausedAt,
|
|
145
|
+
// Clamped at READ time, not only at write. The ceiling has to hold against
|
|
146
|
+
// a file this process did not write: `~/.failproofai/state/sessions/` is
|
|
147
|
+
// owner-writable by design, and an `expiresAt` a year out would otherwise
|
|
148
|
+
// be honoured on every subsequent tool call forever. Enforcing it here
|
|
149
|
+
// means the bound is a property of the pause, not of the path that created
|
|
150
|
+
// it.
|
|
151
|
+
expiresAt: Math.min(p.expiresAt as number, firstPausedAt + PAUSE_CEILING_MS),
|
|
127
152
|
setBy: typeof p.setBy === "string" ? p.setBy : "unknown",
|
|
128
153
|
...(typeof p.cwd === "string" ? { cwd: p.cwd } : {}),
|
|
129
154
|
};
|
|
@@ -159,10 +184,17 @@ export function writePause(opts: {
|
|
|
159
184
|
now?: number;
|
|
160
185
|
}): ActivePause {
|
|
161
186
|
const now = opts.now ?? Date.now();
|
|
187
|
+
// Carry the run's original start forward while a pause is still live, so a
|
|
188
|
+
// renewal extends the same stretch rather than starting a fresh ceiling.
|
|
189
|
+
const existing = readActivePause(opts.sessionId, now);
|
|
190
|
+
const firstPausedAt = existing?.firstPausedAt ?? now;
|
|
162
191
|
const pause: ActivePause = {
|
|
163
192
|
sessionId: opts.sessionId,
|
|
164
193
|
pausedAt: now,
|
|
165
|
-
|
|
194
|
+
firstPausedAt,
|
|
195
|
+
// The requested duration, but never past the ceiling measured from the
|
|
196
|
+
// start of the run. A renewal can shorten a pause; it cannot outrun 8h.
|
|
197
|
+
expiresAt: Math.min(now + opts.durationMs, firstPausedAt + PAUSE_CEILING_MS),
|
|
166
198
|
setBy: opts.setBy ?? "cli",
|
|
167
199
|
...(opts.cwd ? { cwd: opts.cwd } : {}),
|
|
168
200
|
};
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What is already set up on this machine, and where.
|
|
3
|
+
*
|
|
4
|
+
* Two questions live here, both of which used to be answered ad hoc in two
|
|
5
|
+
* different places:
|
|
6
|
+
*
|
|
7
|
+
* 1. "Has this user ever completed setup?" — drives first-run onboarding.
|
|
8
|
+
* 2. "Is this cwd a project, a home directory, or both?" — drives which
|
|
9
|
+
* scope the wizard offers to configure.
|
|
10
|
+
*
|
|
11
|
+
* Both are pure functions over the filesystem so they can be unit-tested
|
|
12
|
+
* without a TTY, a wizard, or a real home directory. Every path is derived
|
|
13
|
+
* from an injectable `home`/`cwd` rather than read from the environment at
|
|
14
|
+
* call time, because the wizard, the CLI entry point and the tests each have
|
|
15
|
+
* a different idea of where "home" is.
|
|
16
|
+
*/
|
|
17
|
+
import { existsSync, realpathSync, statSync } from "node:fs";
|
|
18
|
+
import { dirname, resolve } from "node:path";
|
|
19
|
+
import { homedir } from "node:os";
|
|
20
|
+
import { getIntegration } from "./integrations";
|
|
21
|
+
import { INTEGRATION_TYPES } from "./types";
|
|
22
|
+
import { globalPolicyConfigFile, launcherMarker as layoutLauncherMarker } from "./fp-home";
|
|
23
|
+
|
|
24
|
+
/** Which config a wizard run is going to write. */
|
|
25
|
+
export type SetupTarget = "user" | "project" | "both";
|
|
26
|
+
|
|
27
|
+
export interface SetupState {
|
|
28
|
+
/** Absolute cwd this was resolved against. */
|
|
29
|
+
cwd: string;
|
|
30
|
+
/** Absolute home directory this was resolved against. */
|
|
31
|
+
home: string;
|
|
32
|
+
/**
|
|
33
|
+
* The directory a project-scope write would land in — the nearest ancestor
|
|
34
|
+
* holding a `.failproofai/`, else `cwd` itself. Never the home directory:
|
|
35
|
+
* `~/.failproofai` is the GLOBAL config, and treating it as a project root
|
|
36
|
+
* would make a wizard run from `~` offer to "configure this project" and
|
|
37
|
+
* then write the global file under a project label.
|
|
38
|
+
*/
|
|
39
|
+
projectRoot: string;
|
|
40
|
+
/** `~/.failproofai/policies-config.json` exists. */
|
|
41
|
+
hasGlobalConfig: boolean;
|
|
42
|
+
/** `<projectRoot>/.failproofai/policies-config.json` exists. */
|
|
43
|
+
hasProjectConfig: boolean;
|
|
44
|
+
/** Any agent CLI has failproofai hooks installed at user scope. */
|
|
45
|
+
hasGlobalHooks: boolean;
|
|
46
|
+
/** The legacy first-run marker written by earlier versions. */
|
|
47
|
+
hasLegacyMarker: boolean;
|
|
48
|
+
/** cwd resolves to the home directory itself. */
|
|
49
|
+
inHomeDir: boolean;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function globalConfigPath(home: string = homedir()): string {
|
|
53
|
+
return globalPolicyConfigFile(home);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function projectConfigPath(projectRoot: string): string {
|
|
57
|
+
return resolve(projectRoot, ".failproofai", "policies-config.json");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function legacyMarkerPath(home: string): string {
|
|
61
|
+
return layoutLauncherMarker(home);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function isDir(path: string): boolean {
|
|
65
|
+
try {
|
|
66
|
+
return statSync(path).isDirectory();
|
|
67
|
+
} catch {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The nearest ancestor of `start` holding a `.failproofai/` directory, or
|
|
74
|
+
* `start` itself when there is none.
|
|
75
|
+
*
|
|
76
|
+
* Mirrors `hooks-config.findProjectConfigDir`, but takes `home` as a
|
|
77
|
+
* parameter instead of calling `homedir()` — the wizard needs to resolve this
|
|
78
|
+
* against a caller-supplied home in tests, and the two must not disagree
|
|
79
|
+
* about where the walk stops or the wizard would offer to write a project
|
|
80
|
+
* config at a path the policy loader never reads.
|
|
81
|
+
*/
|
|
82
|
+
export function findProjectRoot(start: string, home: string = homedir()): string {
|
|
83
|
+
// Both sides real-resolved for the same reason `detectSetupState` does it:
|
|
84
|
+
// a symlinked home would never equal the walked path, so the walk would run
|
|
85
|
+
// straight past home and could claim `~` — whose `.failproofai/` is the
|
|
86
|
+
// global config — as a project root.
|
|
87
|
+
const resolvedHome = realResolve(home);
|
|
88
|
+
let dir = realResolve(start);
|
|
89
|
+
while (dir !== resolvedHome) {
|
|
90
|
+
if (isDir(resolve(dir, ".failproofai"))) return dir;
|
|
91
|
+
const parent = dirname(dir);
|
|
92
|
+
if (parent === dir) break;
|
|
93
|
+
dir = parent;
|
|
94
|
+
}
|
|
95
|
+
return resolve(start);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Whether any agent CLI carries failproofai hooks at user scope.
|
|
100
|
+
*
|
|
101
|
+
* Deliberately ignores project scope: a checkout that happens to contain
|
|
102
|
+
* committed project hooks (this repo does) must not convince the wizard that
|
|
103
|
+
* the MACHINE has been set up.
|
|
104
|
+
*/
|
|
105
|
+
export function hasGlobalHooksInstalled(): boolean {
|
|
106
|
+
for (const id of INTEGRATION_TYPES) {
|
|
107
|
+
try {
|
|
108
|
+
if (getIntegration(id).hooksInstalledInSettings("user")) return true;
|
|
109
|
+
} catch {
|
|
110
|
+
// A malformed settings file is not evidence of an install.
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* `resolve()` plus symlink resolution, falling back to the lexical path.
|
|
118
|
+
*
|
|
119
|
+
* `$HOME` is very often a symlink (`/home/x` → `/mnt/data/x`, macOS
|
|
120
|
+
* `/tmp` → `/private/tmp`) while a shell's cwd reports the real path. Compared
|
|
121
|
+
* lexically, the two never match: `inHomeDir` reads false while standing in
|
|
122
|
+
* home, and the wizard offers to "configure this project" pointing at the home
|
|
123
|
+
* directory — whose `.failproofai/` is the GLOBAL config. Comparing real paths
|
|
124
|
+
* is what makes "am I in my home directory" answerable.
|
|
125
|
+
*
|
|
126
|
+
* Falls back to the lexical path when the target does not exist (a cwd that
|
|
127
|
+
* has been deleted, a home that has not been created yet), because a missing
|
|
128
|
+
* path is not a reason to fail detection.
|
|
129
|
+
*/
|
|
130
|
+
function realResolve(path: string): string {
|
|
131
|
+
const lexical = resolve(path);
|
|
132
|
+
try {
|
|
133
|
+
return realpathSync(lexical);
|
|
134
|
+
} catch {
|
|
135
|
+
return lexical;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function detectSetupState(
|
|
140
|
+
cwd: string = process.cwd(),
|
|
141
|
+
home: string = homedir(),
|
|
142
|
+
): SetupState {
|
|
143
|
+
const resolvedCwd = realResolve(cwd);
|
|
144
|
+
const resolvedHome = realResolve(home);
|
|
145
|
+
const projectRoot = findProjectRoot(resolvedCwd, resolvedHome);
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
cwd: resolvedCwd,
|
|
149
|
+
home: resolvedHome,
|
|
150
|
+
projectRoot,
|
|
151
|
+
hasGlobalConfig: existsSync(globalConfigPath(resolvedHome)),
|
|
152
|
+
// When cwd IS home, `projectRoot` is home and its `.failproofai` is the
|
|
153
|
+
// global config — reporting that as a project config would double-count
|
|
154
|
+
// one file as two scopes and offer "Both" for a single target.
|
|
155
|
+
hasProjectConfig:
|
|
156
|
+
projectRoot !== resolvedHome && existsSync(projectConfigPath(projectRoot)),
|
|
157
|
+
hasGlobalHooks: hasGlobalHooksInstalled(),
|
|
158
|
+
hasLegacyMarker: existsSync(legacyMarkerPath(resolvedHome)),
|
|
159
|
+
inHomeDir: resolvedCwd === resolvedHome,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Whether this machine has ever completed setup.
|
|
165
|
+
*
|
|
166
|
+
* Deliberately NOT just the marker file. The marker is one of three
|
|
167
|
+
* independent signals, and any of them means "configured":
|
|
168
|
+
*
|
|
169
|
+
* • a global policies-config.json — the wizard, or `policies --install`,
|
|
170
|
+
* has written real configuration
|
|
171
|
+
* • user-scope hooks in any agent CLI — enforcement is live even if the
|
|
172
|
+
* config file was hand-deleted
|
|
173
|
+
* • the legacy marker — so users onboarded by an earlier version are never
|
|
174
|
+
* shown the wizard a second time
|
|
175
|
+
*
|
|
176
|
+
* Relying on the marker alone made deleting one file re-run onboarding on a
|
|
177
|
+
* fully configured machine; relying on hooks alone re-ran it for anyone who
|
|
178
|
+
* had uninstalled hooks but kept their policy config. Requiring all three
|
|
179
|
+
* would never fire for a genuinely fresh install. The union is the only
|
|
180
|
+
* combination that is right in each case.
|
|
181
|
+
*/
|
|
182
|
+
export function isConfigured(state: SetupState = detectSetupState()): boolean {
|
|
183
|
+
return state.hasGlobalConfig || state.hasGlobalHooks || state.hasLegacyMarker;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export interface TargetChoice {
|
|
187
|
+
label: string;
|
|
188
|
+
value: SetupTarget;
|
|
189
|
+
hint: string;
|
|
190
|
+
/** True when this target would UPDATE existing config rather than create it. */
|
|
191
|
+
existing: boolean;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* The scope choices to offer, ordered so the most likely intent is first
|
|
196
|
+
* (and therefore pre-selected).
|
|
197
|
+
*
|
|
198
|
+
* The ordering rule is "what did the user point us at": run from inside a
|
|
199
|
+
* project, the project comes first; run from home — where there is no project
|
|
200
|
+
* to configure — only the global row is offered, because a "Just this
|
|
201
|
+
* project" row pointing at `~` would write `~/.failproofai/` and call the
|
|
202
|
+
* machine-wide config a project.
|
|
203
|
+
*/
|
|
204
|
+
export function buildTargetChoices(state: SetupState): TargetChoice[] {
|
|
205
|
+
const globalRow: TargetChoice = {
|
|
206
|
+
label: state.hasGlobalConfig ? "Update my global policies" : "Set up global policies",
|
|
207
|
+
value: "user",
|
|
208
|
+
hint: "applies in every project on this machine",
|
|
209
|
+
existing: state.hasGlobalConfig,
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// From home (or anywhere with no project marker above it) there is no
|
|
213
|
+
// second target to offer.
|
|
214
|
+
if (state.inHomeDir || state.projectRoot === state.home) {
|
|
215
|
+
return [globalRow];
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const projectRow: TargetChoice = {
|
|
219
|
+
label: state.hasProjectConfig
|
|
220
|
+
? "Update this project's policies"
|
|
221
|
+
: "Set up this project's policies",
|
|
222
|
+
value: "project",
|
|
223
|
+
hint: homeify(state.projectRoot, state.home),
|
|
224
|
+
existing: state.hasProjectConfig,
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
const bothRow: TargetChoice = {
|
|
228
|
+
label: "Both",
|
|
229
|
+
value: "both",
|
|
230
|
+
hint: "global defaults, plus overrides for this project",
|
|
231
|
+
existing: state.hasGlobalConfig && state.hasProjectConfig,
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
// Inside a project, the project is the likelier intent — unless nothing
|
|
235
|
+
// global exists yet, in which case the machine has never been set up and
|
|
236
|
+
// configuring only this one project would leave every other project
|
|
237
|
+
// unprotected without saying so.
|
|
238
|
+
return state.hasGlobalConfig
|
|
239
|
+
? [projectRow, globalRow, bothRow]
|
|
240
|
+
: [globalRow, projectRow, bothRow];
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/** `/home/x/y` → `~/y`, for display only. */
|
|
244
|
+
export function homeify(path: string, home: string = homedir()): string {
|
|
245
|
+
const resolvedHome = resolve(home);
|
|
246
|
+
const resolvedPath = resolve(path);
|
|
247
|
+
if (resolvedPath === resolvedHome) return "~";
|
|
248
|
+
return resolvedPath.startsWith(resolvedHome + "/")
|
|
249
|
+
? `~${resolvedPath.slice(resolvedHome.length)}`
|
|
250
|
+
: resolvedPath;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/** The scopes a `SetupTarget` expands to. */
|
|
254
|
+
export function scopesFor(target: SetupTarget): Array<"user" | "project"> {
|
|
255
|
+
return target === "both" ? ["user", "project"] : [target];
|
|
256
|
+
}
|
package/src/hooks/tui.ts
CHANGED
|
@@ -112,10 +112,10 @@ export function colorsEnabled(out: TTYOut): boolean {
|
|
|
112
112
|
|
|
113
113
|
/**
|
|
114
114
|
* The raw ANSI opening sequence for a brand role, for callers that assemble
|
|
115
|
-
* their own strings instead of using `paint()`'s wrappers (`src/audit/cli.ts
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
115
|
+
* their own strings instead of using `paint()`'s wrappers (`src/audit/cli.ts`).
|
|
116
|
+
* That file previously hardcoded its own 256-colour palette — a green and a
|
|
117
|
+
* blue that appear nowhere in the brand — so `audit` looked like a different
|
|
118
|
+
* product from `config`. Routing it here
|
|
119
119
|
* keeps HUES the single source of truth: change a hue once and every surface
|
|
120
120
|
* follows. Emits truecolor where the terminal advertises it, basic ANSI
|
|
121
121
|
* otherwise; the caller still decides *whether* to colour at all.
|
|
@@ -54,15 +54,67 @@ function encodeFrame(value: unknown): Buffer {
|
|
|
54
54
|
return Buffer.concat([header, body]);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Last-resort deadline on a single queued task.
|
|
59
|
+
*
|
|
60
|
+
* Deliberately far above `daemon-client.ts`'s 30s `DAEMON_RESPONSE_TIMEOUT_MS`:
|
|
61
|
+
* by the time this fires the client has long since given up and fail-closed, so
|
|
62
|
+
* nothing legitimate is waiting. It exists only to detect a task that will never
|
|
63
|
+
* settle at all.
|
|
64
|
+
*/
|
|
65
|
+
const TASK_DEADLINE_MS = 60_000;
|
|
66
|
+
|
|
57
67
|
/**
|
|
58
68
|
* Serializes every request across every connection through one chain, so
|
|
59
69
|
* `evaluateHookEvent` calls never overlap. `.catch()` on each link keeps the
|
|
60
70
|
* chain alive even if a handler throws unexpectedly — one bad request must
|
|
61
71
|
* never wedge every request queued behind it.
|
|
72
|
+
*
|
|
73
|
+
* `.catch()` covers a task that REJECTS. It does nothing for one that never
|
|
74
|
+
* SETTLES, and that state is reachable: a policy file with a top-level `await`
|
|
75
|
+
* that never resolves hangs its `import()`, so the task neither resolves nor
|
|
76
|
+
* rejects and every hook queued behind it waits forever. Each client then burns
|
|
77
|
+
* its own 30s budget and fail-closed denies — every tool call, every CLI on the
|
|
78
|
+
* machine, until someone restarts the daemon. This is a class the warm worker
|
|
79
|
+
* creates: in the one-shot path the identical file hangs one hook process and
|
|
80
|
+
* the agent CLI's own timeout reaps it.
|
|
81
|
+
*
|
|
82
|
+
* `custom-hooks-loader.ts` bounds that import directly, which is the graceful
|
|
83
|
+
* fix and covers the known cause. This is the backstop for the ones nobody
|
|
84
|
+
* thought of, and it EXITS rather than continuing: the orphaned task is still
|
|
85
|
+
* running and still holds the `globalThis` policy registry this chain exists to
|
|
86
|
+
* serialize access to, so letting the next request proceed would trade a wedge
|
|
87
|
+
* for silent cross-request registry corruption. Exiting hands the supervisor a
|
|
88
|
+
* process it will respawn clean (`worker.rs`'s `ensure_started` respawns a
|
|
89
|
+
* worker whose `try_wait()` reports it gone), which costs one cold start and
|
|
90
|
+
* denies the in-flight requests — the same fail-closed outcome they were headed
|
|
91
|
+
* for anyway, but recovered on the next call instead of never.
|
|
62
92
|
*/
|
|
93
|
+
const WEDGED_EXIT_CODE = 75;
|
|
94
|
+
|
|
63
95
|
let processingChain: Promise<void> = Promise.resolve();
|
|
64
96
|
function enqueue(task: () => Promise<void>): void {
|
|
65
|
-
processingChain = processingChain
|
|
97
|
+
processingChain = processingChain
|
|
98
|
+
.then(
|
|
99
|
+
() =>
|
|
100
|
+
new Promise<void>((settle) => {
|
|
101
|
+
const timer = setTimeout(() => {
|
|
102
|
+
hookLogWarn(
|
|
103
|
+
`worker: a request did not settle within ${TASK_DEADLINE_MS}ms; ` +
|
|
104
|
+
`exiting so the supervisor can respawn a clean worker`,
|
|
105
|
+
);
|
|
106
|
+
process.exit(WEDGED_EXIT_CODE);
|
|
107
|
+
}, TASK_DEADLINE_MS);
|
|
108
|
+
// Never let the deadline itself hold the event loop open.
|
|
109
|
+
timer.unref?.();
|
|
110
|
+
const done = () => {
|
|
111
|
+
clearTimeout(timer);
|
|
112
|
+
settle();
|
|
113
|
+
};
|
|
114
|
+
void task().then(done, done);
|
|
115
|
+
}),
|
|
116
|
+
)
|
|
117
|
+
.catch(() => {});
|
|
66
118
|
}
|
|
67
119
|
|
|
68
120
|
function handleConnection(socket: Socket): void {
|