failproofai 0.0.2 → 0.0.3
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/.claude/settings.json +316 -0
- package/.next/standalone/.failproofai/policies/workflow-policies.mjs +62 -0
- package/.next/standalone/.failproofai/policies-config.json +39 -0
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +5 -5
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/required-server-files.json +3 -1
- package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +2 -2
- 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.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 +2 -2
- 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.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 +2 -2
- package/.next/standalone/.next/server/app/_not-found.rsc +17 -17
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +17 -17
- 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 +11 -11
- 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/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +16 -16
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +16 -16
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +11 -11
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -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 +2 -2
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
- 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 +2 -2
- 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.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 +2 -2
- 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.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 +2 -2
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- 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/chunks/[root-of-the-server]__0g72weg._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0kjo7d_._.js +1 -1
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_05pz9._._.js +1 -1
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_0z7w.hh._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__12kr5~_._.js → [root-of-the-server]__03kiqd5._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__092s1ta._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__09icjsf._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0qo8503._.js → [root-of-the-server]__0bo8s~-._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g.lg8b._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h..k-e._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0okos0k._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0w6l33k._.js +9 -9
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11pa2ra._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12t-wym._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_10lm7or._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_0xerkr6._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_0q-m0y-._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0a_7sdg.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0ef3uwk.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0j79~gv.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0pbja1x.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0r6o0i2.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_11y81~_.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_12or2kf.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_0mebn66._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +5 -5
- package/.next/standalone/.next/server/pages/404.html +2 -2
- 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 +9 -9
- package/.next/standalone/.next/static/chunks/{0x-625~1vx1lu.js → 02t9.s735hqyq.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0ov60i6md~37t.js → 03oepxbqx6o8~.js} +2 -2
- package/.next/standalone/.next/static/chunks/{031pa5~qfzt~_.js → 09e7drilkf1sn.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0y~0creqvl5wx.js → 0cwft44dh9bww.js} +1 -1
- package/.next/standalone/.next/static/chunks/{06og.7e9nkpjh.js → 0e2uz2g026ckb.js} +1 -1
- package/.next/standalone/.next/static/chunks/0gu_a.a80ritd.css +1 -0
- package/.next/standalone/.next/static/chunks/{15wf7x-e.8ia3.js → 0h5kbvg~.xf.v.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0_4y_t03jn2nq.js → 0od..umlku4bb.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0cvffh-pbsv5u.js → 0xbwzy4dl87-0.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0c_ljlxa._4lc.js → 18cl6wups7ouq.js} +2 -2
- package/.next/standalone/.next/static/chunks/{turbopack-0uc5y~g6h.n7-.js → turbopack-0r26pc8h0y_-e.js} +1 -1
- package/.next/standalone/CHANGELOG.md +103 -0
- package/.next/standalone/CLAUDE.md +28 -0
- package/.next/standalone/Dockerfile.docs +12 -0
- package/.next/standalone/README.md +95 -49
- package/.next/standalone/app/components/session-hooks-panel.tsx +14 -1
- package/.next/standalone/app/policies/hooks-client.tsx +14 -1
- package/.next/standalone/bin/failproofai.mjs +5 -0
- package/.next/standalone/bun.lock +76 -63
- package/.next/standalone/components/navbar.tsx +5 -0
- package/.next/standalone/dist/cli.mjs +539 -90
- package/.next/standalone/dist/index.js +2 -2
- package/.next/standalone/docs/ar/architecture.mdx +333 -0
- package/.next/standalone/docs/ar/built-in-policies.mdx +566 -0
- package/.next/standalone/docs/ar/cli/dashboard.mdx +28 -0
- package/.next/standalone/docs/ar/cli/environment-variables.mdx +34 -0
- package/.next/standalone/docs/ar/cli/hook.mdx +31 -0
- package/.next/standalone/docs/ar/cli/install-policies.mdx +49 -0
- package/.next/standalone/docs/ar/cli/list-policies.mdx +31 -0
- package/.next/standalone/docs/ar/cli/remove-policies.mdx +45 -0
- package/.next/standalone/docs/ar/cli/version.mdx +13 -0
- package/.next/standalone/docs/ar/configuration.mdx +223 -0
- package/.next/standalone/docs/ar/custom-policies.mdx +359 -0
- package/.next/standalone/docs/ar/dashboard.mdx +142 -0
- package/.next/standalone/docs/ar/examples.mdx +254 -0
- package/.next/standalone/docs/ar/for-agents.mdx +39 -0
- package/.next/standalone/docs/ar/getting-started.mdx +134 -0
- package/.next/standalone/docs/ar/introduction.mdx +58 -0
- package/.next/standalone/docs/ar/package-aliases.mdx +82 -0
- package/.next/standalone/docs/ar/testing.mdx +261 -0
- package/.next/standalone/docs/{architecture.md → architecture.mdx} +40 -23
- package/.next/standalone/docs/{built-in-policies.md → built-in-policies.mdx} +151 -13
- package/.next/standalone/docs/cli/dashboard.mdx +28 -0
- package/.next/standalone/docs/cli/environment-variables.mdx +34 -0
- package/.next/standalone/docs/cli/hook.mdx +30 -0
- package/.next/standalone/docs/cli/install-policies.mdx +48 -0
- package/.next/standalone/docs/cli/list-policies.mdx +31 -0
- package/.next/standalone/docs/cli/remove-policies.mdx +44 -0
- package/.next/standalone/docs/cli/version.mdx +12 -0
- package/.next/standalone/docs/{configuration.md → configuration.mdx} +62 -16
- package/.next/standalone/docs/custom-policies.mdx +357 -0
- package/.next/standalone/docs/{dashboard.md → dashboard.mdx} +26 -29
- package/.next/standalone/docs/de/architecture.mdx +332 -0
- package/.next/standalone/docs/de/built-in-policies.mdx +564 -0
- package/.next/standalone/docs/de/cli/dashboard.mdx +28 -0
- package/.next/standalone/docs/de/cli/environment-variables.mdx +34 -0
- package/.next/standalone/docs/de/cli/hook.mdx +30 -0
- package/.next/standalone/docs/de/cli/install-policies.mdx +48 -0
- package/.next/standalone/docs/de/cli/list-policies.mdx +31 -0
- package/.next/standalone/docs/de/cli/remove-policies.mdx +44 -0
- package/.next/standalone/docs/de/cli/version.mdx +12 -0
- package/.next/standalone/docs/de/configuration.mdx +222 -0
- package/.next/standalone/docs/de/custom-policies.mdx +357 -0
- package/.next/standalone/docs/de/dashboard.mdx +142 -0
- package/.next/standalone/docs/de/examples.mdx +253 -0
- package/.next/standalone/docs/de/for-agents.mdx +38 -0
- package/.next/standalone/docs/de/getting-started.mdx +134 -0
- package/.next/standalone/docs/de/introduction.mdx +57 -0
- package/.next/standalone/docs/de/package-aliases.mdx +82 -0
- package/.next/standalone/docs/de/testing.mdx +260 -0
- package/.next/standalone/docs/docs.json +938 -24
- package/.next/standalone/docs/es/architecture.mdx +332 -0
- package/.next/standalone/docs/es/built-in-policies.mdx +564 -0
- package/.next/standalone/docs/es/cli/dashboard.mdx +28 -0
- package/.next/standalone/docs/es/cli/environment-variables.mdx +34 -0
- package/.next/standalone/docs/es/cli/hook.mdx +30 -0
- package/.next/standalone/docs/es/cli/install-policies.mdx +48 -0
- package/.next/standalone/docs/es/cli/list-policies.mdx +31 -0
- package/.next/standalone/docs/es/cli/remove-policies.mdx +44 -0
- package/.next/standalone/docs/es/cli/version.mdx +12 -0
- package/.next/standalone/docs/es/configuration.mdx +222 -0
- package/.next/standalone/docs/es/custom-policies.mdx +357 -0
- package/.next/standalone/docs/es/dashboard.mdx +142 -0
- package/.next/standalone/docs/es/examples.mdx +253 -0
- package/.next/standalone/docs/es/for-agents.mdx +38 -0
- package/.next/standalone/docs/es/getting-started.mdx +134 -0
- package/.next/standalone/docs/es/introduction.mdx +57 -0
- package/.next/standalone/docs/es/package-aliases.mdx +82 -0
- package/.next/standalone/docs/es/testing.mdx +260 -0
- package/.next/standalone/docs/examples.mdx +253 -0
- package/.next/standalone/docs/for-agents.mdx +38 -0
- package/.next/standalone/docs/fr/architecture.mdx +332 -0
- package/.next/standalone/docs/fr/built-in-policies.mdx +564 -0
- package/.next/standalone/docs/fr/cli/dashboard.mdx +28 -0
- package/.next/standalone/docs/fr/cli/environment-variables.mdx +34 -0
- package/.next/standalone/docs/fr/cli/hook.mdx +30 -0
- package/.next/standalone/docs/fr/cli/install-policies.mdx +48 -0
- package/.next/standalone/docs/fr/cli/list-policies.mdx +31 -0
- package/.next/standalone/docs/fr/cli/remove-policies.mdx +44 -0
- package/.next/standalone/docs/fr/cli/version.mdx +12 -0
- package/.next/standalone/docs/fr/configuration.mdx +222 -0
- package/.next/standalone/docs/fr/custom-policies.mdx +357 -0
- package/.next/standalone/docs/fr/dashboard.mdx +142 -0
- package/.next/standalone/docs/fr/examples.mdx +253 -0
- package/.next/standalone/docs/fr/for-agents.mdx +38 -0
- package/.next/standalone/docs/fr/getting-started.mdx +134 -0
- package/.next/standalone/docs/fr/introduction.mdx +57 -0
- package/.next/standalone/docs/fr/package-aliases.mdx +82 -0
- package/.next/standalone/docs/fr/testing.mdx +260 -0
- package/.next/standalone/docs/getting-started.mdx +134 -0
- package/.next/standalone/docs/he/architecture.mdx +333 -0
- package/.next/standalone/docs/he/built-in-policies.mdx +564 -0
- package/.next/standalone/docs/he/cli/dashboard.mdx +28 -0
- package/.next/standalone/docs/he/cli/environment-variables.mdx +34 -0
- package/.next/standalone/docs/he/cli/hook.mdx +30 -0
- package/.next/standalone/docs/he/cli/install-policies.mdx +48 -0
- package/.next/standalone/docs/he/cli/list-policies.mdx +32 -0
- package/.next/standalone/docs/he/cli/remove-policies.mdx +44 -0
- package/.next/standalone/docs/he/cli/version.mdx +12 -0
- package/.next/standalone/docs/he/configuration.mdx +222 -0
- package/.next/standalone/docs/he/custom-policies.mdx +357 -0
- package/.next/standalone/docs/he/dashboard.mdx +142 -0
- package/.next/standalone/docs/he/examples.mdx +253 -0
- package/.next/standalone/docs/he/for-agents.mdx +38 -0
- package/.next/standalone/docs/he/getting-started.mdx +135 -0
- package/.next/standalone/docs/he/introduction.mdx +57 -0
- package/.next/standalone/docs/he/package-aliases.mdx +82 -0
- package/.next/standalone/docs/he/testing.mdx +260 -0
- package/.next/standalone/docs/hi/architecture.mdx +334 -0
- package/.next/standalone/docs/hi/built-in-policies.mdx +564 -0
- package/.next/standalone/docs/hi/cli/dashboard.mdx +28 -0
- package/.next/standalone/docs/hi/cli/environment-variables.mdx +34 -0
- package/.next/standalone/docs/hi/cli/hook.mdx +30 -0
- package/.next/standalone/docs/hi/cli/install-policies.mdx +48 -0
- package/.next/standalone/docs/hi/cli/list-policies.mdx +31 -0
- package/.next/standalone/docs/hi/cli/remove-policies.mdx +44 -0
- package/.next/standalone/docs/hi/cli/version.mdx +12 -0
- package/.next/standalone/docs/hi/configuration.mdx +222 -0
- package/.next/standalone/docs/hi/custom-policies.mdx +357 -0
- package/.next/standalone/docs/hi/dashboard.mdx +142 -0
- package/.next/standalone/docs/hi/examples.mdx +255 -0
- package/.next/standalone/docs/hi/for-agents.mdx +38 -0
- package/.next/standalone/docs/hi/getting-started.mdx +134 -0
- package/.next/standalone/docs/hi/introduction.mdx +57 -0
- package/.next/standalone/docs/hi/package-aliases.mdx +82 -0
- package/.next/standalone/docs/hi/testing.mdx +260 -0
- package/.next/standalone/docs/i18n/README.ar.md +312 -0
- package/.next/standalone/docs/i18n/README.de.md +307 -0
- package/.next/standalone/docs/i18n/README.es.md +307 -0
- package/.next/standalone/docs/i18n/README.fr.md +307 -0
- package/.next/standalone/docs/i18n/README.he.md +312 -0
- package/.next/standalone/docs/i18n/README.hi.md +307 -0
- package/.next/standalone/docs/i18n/README.it.md +307 -0
- package/.next/standalone/docs/i18n/README.ja.md +307 -0
- package/.next/standalone/docs/i18n/README.ko.md +307 -0
- package/.next/standalone/docs/i18n/README.pt-br.md +307 -0
- package/.next/standalone/docs/i18n/README.ru.md +308 -0
- package/.next/standalone/docs/i18n/README.tr.md +308 -0
- package/.next/standalone/docs/i18n/README.vi.md +308 -0
- package/.next/standalone/docs/i18n/README.zh.md +307 -0
- package/.next/standalone/docs/introduction.mdx +57 -0
- package/.next/standalone/docs/it/architecture.mdx +333 -0
- package/.next/standalone/docs/it/built-in-policies.mdx +564 -0
- package/.next/standalone/docs/it/cli/dashboard.mdx +28 -0
- package/.next/standalone/docs/it/cli/environment-variables.mdx +34 -0
- package/.next/standalone/docs/it/cli/hook.mdx +30 -0
- package/.next/standalone/docs/it/cli/install-policies.mdx +48 -0
- package/.next/standalone/docs/it/cli/list-policies.mdx +31 -0
- package/.next/standalone/docs/it/cli/remove-policies.mdx +44 -0
- package/.next/standalone/docs/it/cli/version.mdx +12 -0
- package/.next/standalone/docs/it/configuration.mdx +223 -0
- package/.next/standalone/docs/it/custom-policies.mdx +358 -0
- package/.next/standalone/docs/it/dashboard.mdx +142 -0
- package/.next/standalone/docs/it/examples.mdx +253 -0
- package/.next/standalone/docs/it/for-agents.mdx +38 -0
- package/.next/standalone/docs/it/getting-started.mdx +134 -0
- package/.next/standalone/docs/it/introduction.mdx +57 -0
- package/.next/standalone/docs/it/package-aliases.mdx +82 -0
- package/.next/standalone/docs/it/testing.mdx +260 -0
- package/.next/standalone/docs/ja/architecture.mdx +332 -0
- package/.next/standalone/docs/ja/built-in-policies.mdx +562 -0
- package/.next/standalone/docs/ja/cli/dashboard.mdx +28 -0
- package/.next/standalone/docs/ja/cli/environment-variables.mdx +34 -0
- package/.next/standalone/docs/ja/cli/hook.mdx +30 -0
- package/.next/standalone/docs/ja/cli/install-policies.mdx +48 -0
- package/.next/standalone/docs/ja/cli/list-policies.mdx +31 -0
- package/.next/standalone/docs/ja/cli/remove-policies.mdx +44 -0
- package/.next/standalone/docs/ja/cli/version.mdx +12 -0
- package/.next/standalone/docs/ja/configuration.mdx +222 -0
- package/.next/standalone/docs/ja/custom-policies.mdx +357 -0
- package/.next/standalone/docs/ja/dashboard.mdx +142 -0
- package/.next/standalone/docs/ja/examples.mdx +253 -0
- package/.next/standalone/docs/ja/for-agents.mdx +38 -0
- package/.next/standalone/docs/ja/getting-started.mdx +134 -0
- package/.next/standalone/docs/ja/introduction.mdx +57 -0
- package/.next/standalone/docs/ja/package-aliases.mdx +82 -0
- package/.next/standalone/docs/ja/testing.mdx +260 -0
- package/.next/standalone/docs/ko/architecture.mdx +332 -0
- package/.next/standalone/docs/ko/built-in-policies.mdx +562 -0
- package/.next/standalone/docs/ko/cli/dashboard.mdx +28 -0
- package/.next/standalone/docs/ko/cli/environment-variables.mdx +34 -0
- package/.next/standalone/docs/ko/cli/hook.mdx +30 -0
- package/.next/standalone/docs/ko/cli/install-policies.mdx +48 -0
- package/.next/standalone/docs/ko/cli/list-policies.mdx +31 -0
- package/.next/standalone/docs/ko/cli/remove-policies.mdx +44 -0
- package/.next/standalone/docs/ko/cli/version.mdx +12 -0
- package/.next/standalone/docs/ko/configuration.mdx +222 -0
- package/.next/standalone/docs/ko/custom-policies.mdx +357 -0
- package/.next/standalone/docs/ko/dashboard.mdx +142 -0
- package/.next/standalone/docs/ko/examples.mdx +253 -0
- package/.next/standalone/docs/ko/for-agents.mdx +38 -0
- package/.next/standalone/docs/ko/getting-started.mdx +134 -0
- package/.next/standalone/docs/ko/introduction.mdx +57 -0
- package/.next/standalone/docs/ko/package-aliases.mdx +82 -0
- package/.next/standalone/docs/ko/testing.mdx +260 -0
- package/.next/standalone/docs/logo/dark.svg +21 -0
- package/.next/standalone/docs/logo/light.svg +21 -0
- package/.next/standalone/docs/{package-aliases.md → package-aliases.mdx} +5 -5
- package/.next/standalone/docs/pt-br/architecture.mdx +332 -0
- package/.next/standalone/docs/pt-br/built-in-policies.mdx +564 -0
- package/.next/standalone/docs/pt-br/cli/dashboard.mdx +28 -0
- package/.next/standalone/docs/pt-br/cli/environment-variables.mdx +34 -0
- package/.next/standalone/docs/pt-br/cli/hook.mdx +30 -0
- package/.next/standalone/docs/pt-br/cli/install-policies.mdx +48 -0
- package/.next/standalone/docs/pt-br/cli/list-policies.mdx +31 -0
- package/.next/standalone/docs/pt-br/cli/remove-policies.mdx +44 -0
- package/.next/standalone/docs/pt-br/cli/version.mdx +12 -0
- package/.next/standalone/docs/pt-br/configuration.mdx +222 -0
- package/.next/standalone/docs/pt-br/custom-policies.mdx +357 -0
- package/.next/standalone/docs/pt-br/dashboard.mdx +142 -0
- package/.next/standalone/docs/pt-br/examples.mdx +253 -0
- package/.next/standalone/docs/pt-br/for-agents.mdx +38 -0
- package/.next/standalone/docs/pt-br/getting-started.mdx +134 -0
- package/.next/standalone/docs/pt-br/introduction.mdx +57 -0
- package/.next/standalone/docs/pt-br/package-aliases.mdx +82 -0
- package/.next/standalone/docs/pt-br/testing.mdx +260 -0
- package/.next/standalone/docs/ru/architecture.mdx +334 -0
- package/.next/standalone/docs/ru/built-in-policies.mdx +562 -0
- package/.next/standalone/docs/ru/cli/dashboard.mdx +28 -0
- package/.next/standalone/docs/ru/cli/environment-variables.mdx +34 -0
- package/.next/standalone/docs/ru/cli/hook.mdx +30 -0
- package/.next/standalone/docs/ru/cli/install-policies.mdx +48 -0
- package/.next/standalone/docs/ru/cli/list-policies.mdx +32 -0
- package/.next/standalone/docs/ru/cli/remove-policies.mdx +44 -0
- package/.next/standalone/docs/ru/cli/version.mdx +12 -0
- package/.next/standalone/docs/ru/configuration.mdx +223 -0
- package/.next/standalone/docs/ru/custom-policies.mdx +357 -0
- package/.next/standalone/docs/ru/dashboard.mdx +142 -0
- package/.next/standalone/docs/ru/examples.mdx +254 -0
- package/.next/standalone/docs/ru/for-agents.mdx +38 -0
- package/.next/standalone/docs/ru/getting-started.mdx +134 -0
- package/.next/standalone/docs/ru/introduction.mdx +57 -0
- package/.next/standalone/docs/ru/package-aliases.mdx +82 -0
- package/.next/standalone/docs/ru/testing.mdx +260 -0
- package/.next/standalone/docs/{testing.md → testing.mdx} +11 -11
- package/.next/standalone/docs/tr/architecture.mdx +333 -0
- package/.next/standalone/docs/tr/built-in-policies.mdx +562 -0
- package/.next/standalone/docs/tr/cli/dashboard.mdx +28 -0
- package/.next/standalone/docs/tr/cli/environment-variables.mdx +34 -0
- package/.next/standalone/docs/tr/cli/hook.mdx +30 -0
- package/.next/standalone/docs/tr/cli/install-policies.mdx +48 -0
- package/.next/standalone/docs/tr/cli/list-policies.mdx +31 -0
- package/.next/standalone/docs/tr/cli/remove-policies.mdx +45 -0
- package/.next/standalone/docs/tr/cli/version.mdx +12 -0
- package/.next/standalone/docs/tr/configuration.mdx +223 -0
- package/.next/standalone/docs/tr/custom-policies.mdx +357 -0
- package/.next/standalone/docs/tr/dashboard.mdx +142 -0
- package/.next/standalone/docs/tr/examples.mdx +253 -0
- package/.next/standalone/docs/tr/for-agents.mdx +38 -0
- package/.next/standalone/docs/tr/getting-started.mdx +134 -0
- package/.next/standalone/docs/tr/introduction.mdx +57 -0
- package/.next/standalone/docs/tr/package-aliases.mdx +82 -0
- package/.next/standalone/docs/tr/testing.mdx +260 -0
- package/.next/standalone/docs/vi/architecture.mdx +333 -0
- package/.next/standalone/docs/vi/built-in-policies.mdx +564 -0
- package/.next/standalone/docs/vi/cli/dashboard.mdx +28 -0
- package/.next/standalone/docs/vi/cli/environment-variables.mdx +34 -0
- package/.next/standalone/docs/vi/cli/hook.mdx +30 -0
- package/.next/standalone/docs/vi/cli/install-policies.mdx +48 -0
- package/.next/standalone/docs/vi/cli/list-policies.mdx +31 -0
- package/.next/standalone/docs/vi/cli/remove-policies.mdx +44 -0
- package/.next/standalone/docs/vi/cli/version.mdx +13 -0
- package/.next/standalone/docs/vi/configuration.mdx +222 -0
- package/.next/standalone/docs/vi/custom-policies.mdx +357 -0
- package/.next/standalone/docs/vi/dashboard.mdx +142 -0
- package/.next/standalone/docs/vi/examples.mdx +253 -0
- package/.next/standalone/docs/vi/for-agents.mdx +38 -0
- package/.next/standalone/docs/vi/getting-started.mdx +134 -0
- package/.next/standalone/docs/vi/introduction.mdx +57 -0
- package/.next/standalone/docs/vi/package-aliases.mdx +82 -0
- package/.next/standalone/docs/vi/testing.mdx +260 -0
- package/.next/standalone/docs/zh/architecture.mdx +332 -0
- package/.next/standalone/docs/zh/built-in-policies.mdx +562 -0
- package/.next/standalone/docs/zh/cli/dashboard.mdx +28 -0
- package/.next/standalone/docs/zh/cli/environment-variables.mdx +34 -0
- package/.next/standalone/docs/zh/cli/hook.mdx +30 -0
- package/.next/standalone/docs/zh/cli/install-policies.mdx +48 -0
- package/.next/standalone/docs/zh/cli/list-policies.mdx +31 -0
- package/.next/standalone/docs/zh/cli/remove-policies.mdx +44 -0
- package/.next/standalone/docs/zh/cli/version.mdx +12 -0
- package/.next/standalone/docs/zh/configuration.mdx +222 -0
- package/.next/standalone/docs/zh/custom-policies.mdx +357 -0
- package/.next/standalone/docs/zh/dashboard.mdx +142 -0
- package/.next/standalone/docs/zh/examples.mdx +253 -0
- package/.next/standalone/docs/zh/for-agents.mdx +38 -0
- package/.next/standalone/docs/zh/getting-started.mdx +134 -0
- package/.next/standalone/docs/zh/introduction.mdx +57 -0
- package/.next/standalone/docs/zh/package-aliases.mdx +82 -0
- package/.next/standalone/docs/zh/testing.mdx +260 -0
- package/.next/standalone/examples/convention-policies/security-policies.mjs +40 -0
- package/.next/standalone/examples/convention-policies/workflow-policies.mjs +41 -0
- package/.next/standalone/next.config.ts +5 -3
- package/.next/standalone/node_modules/@next/env/package.json +1 -1
- package/.next/standalone/node_modules/next/dist/build/swc/index.js +1 -1
- package/.next/standalone/node_modules/next/dist/compiled/jsonwebtoken/index.js +2 -2
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js +1 -1
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js +1 -1
- package/.next/standalone/node_modules/next/dist/compiled/next-server/pages-turbo.runtime.prod.js +1 -1
- package/.next/standalone/node_modules/next/dist/lib/patch-incorrect-lockfile.js +3 -3
- package/.next/standalone/node_modules/next/dist/server/config.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-turbopack.js +7 -2
- package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-webpack.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/lib/app-info-log.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/lib/start-server.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/render.js +20 -19
- package/.next/standalone/node_modules/next/dist/shared/lib/errors/canary-only-config-error.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/anonymous-meta.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/events/swc-load-failure.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/events/version.js +2 -2
- package/.next/standalone/node_modules/next/package.json +15 -15
- 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 +1 -1
- 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 +2 -2
- package/.next/standalone/package.json +13 -10
- package/.next/standalone/scripts/translate-docs/cache.ts +62 -0
- package/.next/standalone/scripts/translate-docs/cli.ts +357 -0
- package/.next/standalone/scripts/translate-docs/config.ts +248 -0
- package/.next/standalone/scripts/translate-docs/mdx-translator.ts +153 -0
- package/.next/standalone/scripts/translate-docs/mintlify-nav.ts +107 -0
- package/.next/standalone/scripts/translate-docs/readme-translator.ts +154 -0
- package/.next/standalone/scripts/translate-docs/translator.ts +68 -0
- package/.next/standalone/scripts/translate-docs/types.ts +43 -0
- package/.next/standalone/server.js +1 -1
- package/.next/standalone/skills-lock.json +10 -0
- package/.next/standalone/src/hooks/builtin-policies.ts +405 -25
- package/.next/standalone/src/hooks/custom-hooks-loader.ts +165 -21
- package/.next/standalone/src/hooks/handler.ts +33 -6
- package/.next/standalone/src/hooks/hook-activity-store.ts +6 -1
- package/.next/standalone/src/hooks/hooks-config.ts +47 -2
- package/.next/standalone/src/hooks/llm-client.ts +2 -2
- package/.next/standalone/src/hooks/loader-utils.ts +4 -4
- package/.next/standalone/src/hooks/manager.ts +67 -16
- package/.next/standalone/src/hooks/policy-evaluator.ts +58 -19
- package/.next/standalone/src/hooks/policy-helpers.ts +2 -2
- package/.next/standalone/vitest.config.e2e.mts +3 -0
- package/.next/standalone/vitest.config.mts +3 -0
- package/README.md +95 -49
- package/bin/failproofai.mjs +5 -0
- package/dist/cli.mjs +539 -90
- package/dist/index.js +2 -2
- package/package.json +13 -10
- package/scripts/translate-docs/cache.ts +62 -0
- package/scripts/translate-docs/cli.ts +357 -0
- package/scripts/translate-docs/config.ts +248 -0
- package/scripts/translate-docs/mdx-translator.ts +153 -0
- package/scripts/translate-docs/mintlify-nav.ts +107 -0
- package/scripts/translate-docs/readme-translator.ts +154 -0
- package/scripts/translate-docs/translator.ts +68 -0
- package/scripts/translate-docs/types.ts +43 -0
- package/src/hooks/builtin-policies.ts +405 -25
- package/src/hooks/custom-hooks-loader.ts +165 -21
- package/src/hooks/handler.ts +33 -6
- package/src/hooks/hook-activity-store.ts +6 -1
- package/src/hooks/hooks-config.ts +47 -2
- package/src/hooks/llm-client.ts +2 -2
- package/src/hooks/loader-utils.ts +4 -4
- package/src/hooks/manager.ts +67 -16
- package/src/hooks/policy-evaluator.ts +58 -19
- package/src/hooks/policy-helpers.ts +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__02nt~6d._.js +0 -3
- package/.next/standalone/.next/static/chunks/15jpradyu_531.css +0 -1
- package/.next/standalone/docs/cli-reference.md +0 -175
- package/.next/standalone/docs/custom-hooks.md +0 -261
- package/.next/standalone/docs/getting-started.md +0 -128
- package/.next/standalone/docs/introduction.md +0 -47
- /package/.next/standalone/.next/static/{WS-OQSqL1Lp1w_obXfjvl → En9eEShUkUjgeYbY9v6Gy}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{WS-OQSqL1Lp1w_obXfjvl → En9eEShUkUjgeYbY9v6Gy}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{WS-OQSqL1Lp1w_obXfjvl → En9eEShUkUjgeYbY9v6Gy}/_ssgManifest.js +0 -0
|
@@ -1,39 +1,51 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Loads
|
|
2
|
+
* Loads user-authored policy files with ESM import rewriting.
|
|
3
3
|
* Supports transitive local imports and `import { ... } from 'failproofai'`.
|
|
4
4
|
*
|
|
5
|
+
* Two loading modes:
|
|
6
|
+
* 1. Explicit: a single file via `customPoliciesPath` in policies-config.json
|
|
7
|
+
* 2. Convention: auto-discovered *policies.{js,mjs,ts} files from
|
|
8
|
+
* .failproofai/policies/ at project and user level (git-hooks style)
|
|
9
|
+
*
|
|
5
10
|
* Fail-open: any error (file not found, syntax error, import failure) is logged
|
|
6
|
-
* and results in an empty hook list. Builtins continue
|
|
11
|
+
* and results in an empty hook list for that file. Builtins continue normally.
|
|
7
12
|
*/
|
|
8
|
-
import { resolve, isAbsolute } from "node:path";
|
|
9
|
-
import { existsSync } from "node:fs";
|
|
13
|
+
import { resolve, isAbsolute, basename } from "node:path";
|
|
14
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
10
15
|
import { pathToFileURL } from "node:url";
|
|
11
|
-
import {
|
|
16
|
+
import { homedir } from "node:os";
|
|
17
|
+
import { hookLogWarn, hookLogError, hookLogInfo } from "./hook-logger";
|
|
12
18
|
import { getCustomHooks, clearCustomHooks } from "./custom-hooks-registry";
|
|
13
19
|
import { findDistIndex, rewriteFileTree, TMP_SUFFIX, cleanupTmpFiles } from "./loader-utils";
|
|
14
20
|
import type { CustomHook } from "./policy-types";
|
|
15
21
|
|
|
16
22
|
const LOADING_KEY = "__FAILPROOFAI_LOADING_HOOKS__";
|
|
17
23
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
opts?: { strict?: boolean },
|
|
21
|
-
): Promise<CustomHook[]> {
|
|
22
|
-
if (!customPoliciesPath) return [];
|
|
24
|
+
/** Regex matching convention policy filenames: *policies.{js,mjs,ts} */
|
|
25
|
+
const CONVENTION_FILE_RE = /policies\.(js|mjs|ts)$/;
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Scan a directory for convention policy files (*policies.{js,mjs,ts}).
|
|
29
|
+
* Returns sorted absolute paths. Returns [] if the directory doesn't exist.
|
|
30
|
+
*/
|
|
31
|
+
export function discoverPolicyFiles(dir: string): string[] {
|
|
32
|
+
if (!existsSync(dir)) return [];
|
|
33
|
+
try {
|
|
34
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
35
|
+
return entries
|
|
36
|
+
.filter((e) => e.isFile() && CONVENTION_FILE_RE.test(e.name))
|
|
37
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
38
|
+
.map((e) => resolve(dir, e.name));
|
|
39
|
+
} catch {
|
|
31
40
|
return [];
|
|
32
41
|
}
|
|
42
|
+
}
|
|
33
43
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Load a single policy file into the globalThis custom hooks registry.
|
|
46
|
+
* Does NOT clear the registry — caller is responsible for that.
|
|
47
|
+
*/
|
|
48
|
+
async function loadSingleFile(absPath: string, opts?: { strict?: boolean }): Promise<void> {
|
|
37
49
|
const g = globalThis as Record<string, unknown>;
|
|
38
50
|
g[LOADING_KEY] = true;
|
|
39
51
|
|
|
@@ -51,11 +63,143 @@ export async function loadCustomHooks(
|
|
|
51
63
|
const msg = err instanceof Error ? err.message : String(err);
|
|
52
64
|
if (opts?.strict) throw new Error(`Failed to load custom hooks from ${absPath}: ${msg}`);
|
|
53
65
|
hookLogError(`failed to load custom hooks from ${absPath}: ${msg}`);
|
|
54
|
-
return [];
|
|
55
66
|
} finally {
|
|
56
67
|
g[LOADING_KEY] = false;
|
|
57
68
|
await cleanupTmpFiles(tmpFiles);
|
|
58
69
|
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Load a single explicit custom hooks file (legacy API).
|
|
74
|
+
* Clears the registry, loads the file, returns registered hooks.
|
|
75
|
+
*/
|
|
76
|
+
export async function loadCustomHooks(
|
|
77
|
+
customPoliciesPath: string | undefined,
|
|
78
|
+
opts?: { strict?: boolean; sessionCwd?: string },
|
|
79
|
+
): Promise<CustomHook[]> {
|
|
80
|
+
if (!customPoliciesPath) return [];
|
|
81
|
+
|
|
82
|
+
const absPath = isAbsolute(customPoliciesPath)
|
|
83
|
+
? customPoliciesPath
|
|
84
|
+
: resolve(opts?.sessionCwd ?? process.cwd(), customPoliciesPath);
|
|
85
|
+
|
|
86
|
+
if (!existsSync(absPath)) {
|
|
87
|
+
if (opts?.strict) throw new Error(`Custom hooks file not found: ${absPath}`);
|
|
88
|
+
hookLogWarn(`customPoliciesPath not found: ${absPath}`);
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
59
91
|
|
|
92
|
+
clearCustomHooks();
|
|
93
|
+
await loadSingleFile(absPath, opts);
|
|
60
94
|
return getCustomHooks();
|
|
61
95
|
}
|
|
96
|
+
|
|
97
|
+
/** Source metadata for a loaded convention policy file. */
|
|
98
|
+
export interface ConventionSource {
|
|
99
|
+
scope: "project" | "user";
|
|
100
|
+
file: string;
|
|
101
|
+
hookNames: string[];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Result of loadAllCustomHooks with source metadata. */
|
|
105
|
+
export interface LoadAllResult {
|
|
106
|
+
hooks: CustomHook[];
|
|
107
|
+
conventionSources: ConventionSource[];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Load ALL custom hooks: explicit customPoliciesPath + convention-discovered files.
|
|
112
|
+
*
|
|
113
|
+
* Load order:
|
|
114
|
+
* 1. Explicit customPoliciesPath (if configured)
|
|
115
|
+
* 2. Project convention: {cwd}/.failproofai/policies/*policies.{js,mjs,ts} (alphabetical)
|
|
116
|
+
* 3. User convention: ~/.failproofai/policies/*policies.{js,mjs,ts} (alphabetical)
|
|
117
|
+
*
|
|
118
|
+
* Each file is loaded independently (fail-open per file).
|
|
119
|
+
* Convention hooks are tagged with __conventionScope so the handler can build scoped prefixes.
|
|
120
|
+
*/
|
|
121
|
+
export async function loadAllCustomHooks(
|
|
122
|
+
customPoliciesPath: string | undefined,
|
|
123
|
+
opts?: { sessionCwd?: string },
|
|
124
|
+
): Promise<LoadAllResult> {
|
|
125
|
+
clearCustomHooks();
|
|
126
|
+
|
|
127
|
+
const conventionSources: ConventionSource[] = [];
|
|
128
|
+
|
|
129
|
+
// 1. Explicit customPoliciesPath (existing behavior)
|
|
130
|
+
if (customPoliciesPath) {
|
|
131
|
+
const absPath = isAbsolute(customPoliciesPath)
|
|
132
|
+
? customPoliciesPath
|
|
133
|
+
: resolve(opts?.sessionCwd ?? process.cwd(), customPoliciesPath);
|
|
134
|
+
if (existsSync(absPath)) {
|
|
135
|
+
await loadSingleFile(absPath);
|
|
136
|
+
} else {
|
|
137
|
+
hookLogWarn(`customPoliciesPath not found: ${absPath}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const hooksBeforeConvention = getCustomHooks().length;
|
|
142
|
+
|
|
143
|
+
// 2. Project convention: {cwd}/.failproofai/policies/*policies.{js,mjs,ts}
|
|
144
|
+
const projectDir = resolve(opts?.sessionCwd ?? process.cwd(), ".failproofai", "policies");
|
|
145
|
+
const projectFiles = discoverPolicyFiles(projectDir);
|
|
146
|
+
for (const file of projectFiles) {
|
|
147
|
+
const hooksBefore = getCustomHooks().length;
|
|
148
|
+
await loadSingleFile(file);
|
|
149
|
+
const newHooks = getCustomHooks().slice(hooksBefore);
|
|
150
|
+
if (newHooks.length > 0) {
|
|
151
|
+
conventionSources.push({
|
|
152
|
+
scope: "project",
|
|
153
|
+
file: basename(file),
|
|
154
|
+
hookNames: newHooks.map((h) => h.name),
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// 3. User convention: ~/.failproofai/policies/*policies.{js,mjs,ts}
|
|
160
|
+
const userDir = resolve(homedir(), ".failproofai", "policies");
|
|
161
|
+
const userFiles = discoverPolicyFiles(userDir);
|
|
162
|
+
for (const file of userFiles) {
|
|
163
|
+
const hooksBefore = getCustomHooks().length;
|
|
164
|
+
await loadSingleFile(file);
|
|
165
|
+
const newHooks = getCustomHooks().slice(hooksBefore);
|
|
166
|
+
if (newHooks.length > 0) {
|
|
167
|
+
conventionSources.push({
|
|
168
|
+
scope: "user",
|
|
169
|
+
file: basename(file),
|
|
170
|
+
hookNames: newHooks.map((h) => h.name),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const allHooks = getCustomHooks();
|
|
176
|
+
const conventionCount = allHooks.length - hooksBeforeConvention;
|
|
177
|
+
|
|
178
|
+
if (projectFiles.length > 0 || userFiles.length > 0) {
|
|
179
|
+
hookLogInfo(
|
|
180
|
+
`convention policies: ${projectFiles.length} project file(s), ${userFiles.length} user file(s), ${conventionCount} hook(s)`,
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Tag convention hooks with their scope so the handler can build scoped prefixes.
|
|
185
|
+
// Build a name→scope map from conventionSources, then tag by object reference
|
|
186
|
+
// to avoid mis-tagging an explicit custom hook that shares the same name.
|
|
187
|
+
const hookNameToScope = new Map<string, string>();
|
|
188
|
+
for (const source of conventionSources) {
|
|
189
|
+
for (const name of source.hookNames) {
|
|
190
|
+
hookNameToScope.set(name, source.scope);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const conventionHookRefs = new Set<CustomHook>();
|
|
194
|
+
for (const hook of allHooks.slice(hooksBeforeConvention)) {
|
|
195
|
+
conventionHookRefs.add(hook);
|
|
196
|
+
}
|
|
197
|
+
for (const hook of allHooks) {
|
|
198
|
+
if (conventionHookRefs.has(hook)) {
|
|
199
|
+
(hook as CustomHook & { __conventionScope?: string }).__conventionScope =
|
|
200
|
+
hookNameToScope.get(hook.name) ?? "project";
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return { hooks: allHooks, conventionSources };
|
|
205
|
+
}
|
|
@@ -11,7 +11,8 @@ import { readMergedHooksConfig } from "./hooks-config";
|
|
|
11
11
|
import { registerBuiltinPolicies } from "./builtin-policies";
|
|
12
12
|
import { evaluatePolicies } from "./policy-evaluator";
|
|
13
13
|
import { clearPolicies, registerPolicy } from "./policy-registry";
|
|
14
|
-
import {
|
|
14
|
+
import { loadAllCustomHooks } from "./custom-hooks-loader";
|
|
15
|
+
import type { CustomHook } from "./policy-types";
|
|
15
16
|
import { persistHookActivity } from "./hook-activity-store";
|
|
16
17
|
import { trackHookEvent } from "./hook-telemetry";
|
|
17
18
|
import { getInstanceId } from "../../lib/telemetry-id";
|
|
@@ -71,9 +72,15 @@ export async function handleHookEvent(eventType: string): Promise<number> {
|
|
|
71
72
|
registerBuiltinPolicies(config.enabledPolicies);
|
|
72
73
|
|
|
73
74
|
// Load and register custom hooks (layer 2, after builtins)
|
|
74
|
-
const
|
|
75
|
+
const loadResult = await loadAllCustomHooks(config.customPoliciesPath, { sessionCwd: session.cwd });
|
|
76
|
+
const customHooksList = loadResult.hooks;
|
|
77
|
+
const conventionHookNames = new Set(loadResult.conventionSources.flatMap((s) => s.hookNames));
|
|
78
|
+
|
|
75
79
|
for (const hook of customHooksList) {
|
|
76
80
|
const hookName = hook.name;
|
|
81
|
+
const conventionScope = (hook as CustomHook & { __conventionScope?: string }).__conventionScope;
|
|
82
|
+
const isConvention = !!conventionScope;
|
|
83
|
+
const prefix = isConvention ? `.failproofai-${conventionScope}` : "custom";
|
|
77
84
|
const fn: PolicyFunction = async (ctx): Promise<PolicyResult> => {
|
|
78
85
|
try {
|
|
79
86
|
const result = await Promise.race([
|
|
@@ -86,17 +93,19 @@ export async function handleHookEvent(eventType: string): Promise<number> {
|
|
|
86
93
|
} catch (err) {
|
|
87
94
|
const msg = err instanceof Error ? err.message : String(err);
|
|
88
95
|
const isTimeout = msg === "timeout";
|
|
89
|
-
hookLogWarn(
|
|
96
|
+
hookLogWarn(`${prefix} hook "${hookName}" failed: ${msg}`);
|
|
90
97
|
void trackHookEvent(getInstanceId(), "custom_hook_error", {
|
|
91
98
|
hook_name: hookName,
|
|
92
99
|
error_type: isTimeout ? "timeout" : "exception",
|
|
93
100
|
event_type: eventType,
|
|
101
|
+
is_convention_policy: isConvention,
|
|
102
|
+
convention_scope: conventionScope ?? null,
|
|
94
103
|
});
|
|
95
104
|
return { decision: "allow" };
|
|
96
105
|
}
|
|
97
106
|
};
|
|
98
107
|
registerPolicy(
|
|
99
|
-
|
|
108
|
+
`${prefix}/${hookName}`,
|
|
100
109
|
hook.description ?? "",
|
|
101
110
|
fn,
|
|
102
111
|
hook.match ?? {},
|
|
@@ -113,7 +122,18 @@ export async function handleHookEvent(eventType: string): Promise<number> {
|
|
|
113
122
|
});
|
|
114
123
|
}
|
|
115
124
|
|
|
116
|
-
|
|
125
|
+
// Fire telemetry for convention-based policy discovery
|
|
126
|
+
if (loadResult.conventionSources.length > 0) {
|
|
127
|
+
void trackHookEvent(getInstanceId(), "convention_policies_loaded", {
|
|
128
|
+
event_type: eventType,
|
|
129
|
+
project_file_count: loadResult.conventionSources.filter((s) => s.scope === "project").length,
|
|
130
|
+
user_file_count: loadResult.conventionSources.filter((s) => s.scope === "user").length,
|
|
131
|
+
convention_hook_count: conventionHookNames.size,
|
|
132
|
+
convention_hook_names: [...conventionHookNames],
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
hookLogInfo(`event=${eventType} policies=${config.enabledPolicies.length} custom=${customHooksList.length} convention=${conventionHookNames.size}`);
|
|
117
137
|
|
|
118
138
|
// Evaluate policies
|
|
119
139
|
const result = await evaluatePolicies(eventType as HookEventType, parsed, session, config);
|
|
@@ -134,6 +154,7 @@ export async function handleHookEvent(eventType: string): Promise<number> {
|
|
|
134
154
|
eventType,
|
|
135
155
|
toolName: (parsed.tool_name as string) ?? null,
|
|
136
156
|
policyName: result.policyName,
|
|
157
|
+
policyNames: result.policyNames,
|
|
137
158
|
decision: result.decision,
|
|
138
159
|
reason: result.reason,
|
|
139
160
|
durationMs,
|
|
@@ -151,8 +172,12 @@ export async function handleHookEvent(eventType: string): Promise<number> {
|
|
|
151
172
|
if (result.decision === "deny" || result.decision === "instruct") {
|
|
152
173
|
try {
|
|
153
174
|
const isCustomHook = result.policyName?.startsWith("custom/") ?? false;
|
|
175
|
+
const isConventionPolicy = result.policyName?.startsWith(".failproofai-") ?? false;
|
|
176
|
+
const conventionScope = isConventionPolicy
|
|
177
|
+
? result.policyName!.match(/^\.failproofai-(project|user)\//)?.[1] ?? null
|
|
178
|
+
: null;
|
|
154
179
|
const hasCustomParams =
|
|
155
|
-
!isCustomHook && !!(result.policyName && config.policyParams?.[result.policyName]);
|
|
180
|
+
!isCustomHook && !isConventionPolicy && !!(result.policyName && config.policyParams?.[result.policyName]);
|
|
156
181
|
const paramKeysOverridden = hasCustomParams
|
|
157
182
|
? Object.keys(config.policyParams![result.policyName!])
|
|
158
183
|
: [];
|
|
@@ -163,6 +188,8 @@ export async function handleHookEvent(eventType: string): Promise<number> {
|
|
|
163
188
|
policy_name: result.policyName,
|
|
164
189
|
decision: result.decision,
|
|
165
190
|
is_custom_hook: isCustomHook,
|
|
191
|
+
is_convention_policy: isConventionPolicy,
|
|
192
|
+
convention_scope: conventionScope,
|
|
166
193
|
has_custom_params: hasCustomParams,
|
|
167
194
|
param_keys_overridden: paramKeysOverridden,
|
|
168
195
|
});
|
|
@@ -43,6 +43,7 @@ export interface HookActivityEntry {
|
|
|
43
43
|
eventType: string;
|
|
44
44
|
toolName: string | null;
|
|
45
45
|
policyName: string | null;
|
|
46
|
+
policyNames?: string[];
|
|
46
47
|
decision: "allow" | "deny" | "instruct";
|
|
47
48
|
reason: string | null;
|
|
48
49
|
durationMs: number;
|
|
@@ -186,7 +187,11 @@ function updateStats(entry: HookActivityEntry): void {
|
|
|
186
187
|
const s = readStoredStats();
|
|
187
188
|
s.totalEvents += 1;
|
|
188
189
|
if (entry.decision === "deny") s.denyCount += 1;
|
|
189
|
-
if (entry.
|
|
190
|
+
if (entry.policyNames && entry.policyNames.length > 0) {
|
|
191
|
+
for (const name of entry.policyNames) {
|
|
192
|
+
s.policyMap[name] = (s.policyMap[name] ?? 0) + 1;
|
|
193
|
+
}
|
|
194
|
+
} else if (entry.policyName) {
|
|
190
195
|
s.policyMap[entry.policyName] = (s.policyMap[entry.policyName] ?? 0) + 1;
|
|
191
196
|
}
|
|
192
197
|
// Write atomically: write to a PID-unique temp file then rename — prevents partial reads.
|
|
@@ -5,6 +5,7 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
|
|
|
5
5
|
import { resolve, dirname } from "node:path";
|
|
6
6
|
import { homedir } from "node:os";
|
|
7
7
|
import type { HooksConfig } from "./policy-types";
|
|
8
|
+
import type { HookScope } from "./types";
|
|
8
9
|
import { hookLogInfo, hookLogWarn } from "./hook-logger";
|
|
9
10
|
|
|
10
11
|
function readConfigAt(path: string): Partial<HooksConfig> {
|
|
@@ -100,14 +101,58 @@ export function writeHooksConfig(config: HooksConfig): void {
|
|
|
100
101
|
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf8");
|
|
101
102
|
}
|
|
102
103
|
|
|
104
|
+
/**
|
|
105
|
+
* Resolve the policies-config path for a specific scope.
|
|
106
|
+
*/
|
|
107
|
+
export function getConfigPathForScope(scope: HookScope, cwd?: string): string {
|
|
108
|
+
const base = cwd ? resolve(cwd) : process.cwd();
|
|
109
|
+
switch (scope) {
|
|
110
|
+
case "user":
|
|
111
|
+
return resolve(homedir(), ".failproofai", "policies-config.json");
|
|
112
|
+
case "project":
|
|
113
|
+
return resolve(base, ".failproofai", "policies-config.json");
|
|
114
|
+
case "local":
|
|
115
|
+
return resolve(base, ".failproofai", "policies-config.local.json");
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Read hooks config from a single specific scope (not merged).
|
|
121
|
+
*/
|
|
122
|
+
export function readScopedHooksConfig(scope: HookScope, cwd?: string): HooksConfig {
|
|
123
|
+
const configPath = getConfigPathForScope(scope, cwd);
|
|
124
|
+
if (!existsSync(configPath)) {
|
|
125
|
+
return { enabledPolicies: [] };
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
const raw = readFileSync(configPath, "utf8");
|
|
129
|
+
return JSON.parse(raw) as HooksConfig;
|
|
130
|
+
} catch (err) {
|
|
131
|
+
hookLogWarn(`failed to parse config at ${configPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
132
|
+
return { enabledPolicies: [] };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Write hooks config to the scope-appropriate path.
|
|
138
|
+
*/
|
|
139
|
+
export function writeScopedHooksConfig(config: HooksConfig, scope: HookScope, cwd?: string): void {
|
|
140
|
+
const configPath = getConfigPathForScope(scope, cwd);
|
|
141
|
+
const dir = dirname(configPath);
|
|
142
|
+
if (!existsSync(dir)) {
|
|
143
|
+
mkdirSync(dir, { recursive: true });
|
|
144
|
+
}
|
|
145
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf8");
|
|
146
|
+
}
|
|
147
|
+
|
|
103
148
|
export interface ResolvedLlmConfig {
|
|
104
149
|
baseUrl: string;
|
|
105
150
|
apiKey: string;
|
|
106
151
|
model: string;
|
|
107
152
|
}
|
|
108
153
|
|
|
109
|
-
export function readLlmConfig(): ResolvedLlmConfig | null {
|
|
110
|
-
const config =
|
|
154
|
+
export function readLlmConfig(cwd?: string): ResolvedLlmConfig | null {
|
|
155
|
+
const config = readMergedHooksConfig(cwd);
|
|
111
156
|
const baseUrl =
|
|
112
157
|
process.env.FAILPROOFAI_LLM_BASE_URL ?? config.llm?.baseUrl ?? "https://api.openai.com/v1";
|
|
113
158
|
const apiKey = process.env.FAILPROOFAI_LLM_API_KEY ?? config.llm?.apiKey;
|
|
@@ -30,9 +30,9 @@ export interface ChatCompletionResponse {
|
|
|
30
30
|
|
|
31
31
|
export async function chatCompletion(
|
|
32
32
|
messages: ChatMessage[],
|
|
33
|
-
options?: ChatCompletionOptions,
|
|
33
|
+
options?: ChatCompletionOptions & { cwd?: string },
|
|
34
34
|
): Promise<ChatCompletionResponse> {
|
|
35
|
-
const config = readLlmConfig();
|
|
35
|
+
const config = readLlmConfig(options?.cwd);
|
|
36
36
|
if (!config) {
|
|
37
37
|
throw new Error(
|
|
38
38
|
"No LLM API key configured. Set FAILPROOFAI_LLM_API_KEY or configure llm.apiKey in policies-config.json",
|
|
@@ -71,7 +71,8 @@ export async function resolveLocalImport(
|
|
|
71
71
|
|
|
72
72
|
/**
|
|
73
73
|
* Create an ESM shim that re-exports from the CJS dist module.
|
|
74
|
-
*
|
|
74
|
+
* Exports the full public API of failproofai: customPolicies, allow, deny, instruct,
|
|
75
|
+
* getCustomHooks, clearCustomHooks.
|
|
75
76
|
*/
|
|
76
77
|
export async function createEsmShim(
|
|
77
78
|
distIndex: string,
|
|
@@ -80,10 +81,9 @@ export async function createEsmShim(
|
|
|
80
81
|
const shimPath = distIndex + ".__failproofai_esm_shim__.mjs";
|
|
81
82
|
const shimCode = [
|
|
82
83
|
`import _cjs from '${distUrl}';`,
|
|
83
|
-
`export const createApp = _cjs.createApp;`,
|
|
84
|
-
`export const getQueueCondition = _cjs.getQueueCondition;`,
|
|
85
|
-
`export const clearQueueCondition = _cjs.clearQueueCondition;`,
|
|
86
84
|
`export const customPolicies = _cjs.customPolicies;`,
|
|
85
|
+
`export const getCustomHooks = _cjs.getCustomHooks;`,
|
|
86
|
+
`export const clearCustomHooks = _cjs.clearCustomHooks;`,
|
|
87
87
|
`export const allow = _cjs.allow;`,
|
|
88
88
|
`export const deny = _cjs.deny;`,
|
|
89
89
|
`export const instruct = _cjs.instruct;`,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { execSync } from "node:child_process";
|
|
5
5
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
|
|
6
|
-
import { resolve, dirname } from "node:path";
|
|
6
|
+
import { resolve, dirname, basename } from "node:path";
|
|
7
7
|
import { homedir, platform, arch, release, hostname } from "node:os";
|
|
8
8
|
import {
|
|
9
9
|
HOOK_EVENT_TYPES,
|
|
@@ -15,10 +15,10 @@ import {
|
|
|
15
15
|
type ClaudeSettings,
|
|
16
16
|
} from "./types";
|
|
17
17
|
import { promptPolicySelection } from "./install-prompt";
|
|
18
|
-
import {
|
|
18
|
+
import { readMergedHooksConfig, readScopedHooksConfig, writeScopedHooksConfig } from "./hooks-config";
|
|
19
19
|
import type { HooksConfig } from "./policy-types";
|
|
20
20
|
import { BUILTIN_POLICIES } from "./builtin-policies";
|
|
21
|
-
import { loadCustomHooks } from "./custom-hooks-loader";
|
|
21
|
+
import { loadCustomHooks, discoverPolicyFiles } from "./custom-hooks-loader";
|
|
22
22
|
import { trackHookEvent } from "./hook-telemetry";
|
|
23
23
|
import { getInstanceId, hashToId } from "../../lib/telemetry-id";
|
|
24
24
|
import { CliError } from "../cli-error";
|
|
@@ -203,7 +203,7 @@ export async function installHooks(
|
|
|
203
203
|
const binaryPath = resolveFailproofaiBinary();
|
|
204
204
|
|
|
205
205
|
// Capture existing config before overwriting (used for telemetry diff)
|
|
206
|
-
const previousConfig =
|
|
206
|
+
const previousConfig = readScopedHooksConfig(scope, cwd);
|
|
207
207
|
const previousEnabled = new Set(previousConfig.enabledPolicies);
|
|
208
208
|
|
|
209
209
|
let selectedPolicies: string[];
|
|
@@ -251,7 +251,7 @@ export async function installHooks(
|
|
|
251
251
|
`\nValidated ${validatedHooks.length} custom hook(s): ${validatedHooks.map((h) => h.name).join(", ")}`,
|
|
252
252
|
);
|
|
253
253
|
}
|
|
254
|
-
|
|
254
|
+
writeScopedHooksConfig(configToWrite, scope, cwd);
|
|
255
255
|
console.log(`\nEnabled ${selectedPolicies.length} policy(ies): ${selectedPolicies.join(", ")}`);
|
|
256
256
|
if (removeCustomHooks) {
|
|
257
257
|
console.log("Custom hooks path cleared.");
|
|
@@ -267,7 +267,9 @@ export async function installHooks(
|
|
|
267
267
|
}
|
|
268
268
|
|
|
269
269
|
for (const eventType of HOOK_EVENT_TYPES) {
|
|
270
|
-
const command =
|
|
270
|
+
const command = scope === "project"
|
|
271
|
+
? `npx -y failproofai --hook ${eventType}`
|
|
272
|
+
: `"${binaryPath}" --hook ${eventType}`;
|
|
271
273
|
const hookEntry: ClaudeHookEntry = {
|
|
272
274
|
type: "command",
|
|
273
275
|
command,
|
|
@@ -323,6 +325,7 @@ export async function installHooks(
|
|
|
323
325
|
has_custom_hooks_path: !!(configToWrite.customPoliciesPath),
|
|
324
326
|
has_policy_params: !!(configToWrite.policyParams && Object.keys(configToWrite.policyParams).length > 0),
|
|
325
327
|
param_policy_names: configToWrite.policyParams ? Object.keys(configToWrite.policyParams) : [],
|
|
328
|
+
command_format: scope === "project" ? "npx" : "absolute",
|
|
326
329
|
});
|
|
327
330
|
} catch {
|
|
328
331
|
// Telemetry is best-effort — never block the operation
|
|
@@ -330,7 +333,12 @@ export async function installHooks(
|
|
|
330
333
|
|
|
331
334
|
console.log(`Failproof AI hooks installed for all ${HOOK_EVENT_TYPES.length} event types (scope: ${scope}).`);
|
|
332
335
|
console.log(`Settings: ${settingsPath}`);
|
|
333
|
-
|
|
336
|
+
if (scope === "project") {
|
|
337
|
+
console.log(`Command: npx -y failproofai`);
|
|
338
|
+
console.log(`\nThis file can be committed to git — no machine-specific paths.`);
|
|
339
|
+
} else {
|
|
340
|
+
console.log(`Binary: ${binaryPath}`);
|
|
341
|
+
}
|
|
334
342
|
|
|
335
343
|
// Warn about duplicate-scope installations
|
|
336
344
|
const otherScopes = deduplicateScopes(HOOK_SCOPES, cwd).filter((s) => s !== scope);
|
|
@@ -355,18 +363,21 @@ export async function installHooks(
|
|
|
355
363
|
* @param opts.betaOnly — set to true when removing only beta policies (adds beta_only flag to telemetry)
|
|
356
364
|
*/
|
|
357
365
|
export async function removeHooks(policyNames?: string[], scope: HookScope | "all" = "user", cwd?: string, opts?: { betaOnly?: boolean; source?: string; removeCustomHooks?: boolean }): Promise<void> {
|
|
366
|
+
// Resolve the effective config scope ("all" falls back to "user" for config reads/writes)
|
|
367
|
+
const configScope: HookScope = scope === "all" ? "user" : scope;
|
|
368
|
+
|
|
358
369
|
// Clear custom hooks path if requested
|
|
359
370
|
if (opts?.removeCustomHooks) {
|
|
360
|
-
const config =
|
|
371
|
+
const config = readScopedHooksConfig(configScope, cwd);
|
|
361
372
|
delete config.customPoliciesPath;
|
|
362
|
-
|
|
373
|
+
writeScopedHooksConfig(config, configScope, cwd);
|
|
363
374
|
console.log("Custom hooks path cleared.");
|
|
364
375
|
}
|
|
365
376
|
|
|
366
377
|
// Remove specific policies from config (keep hooks installed)
|
|
367
378
|
if (policyNames && policyNames.length > 0 && !(policyNames.length === 1 && policyNames[0] === "all")) {
|
|
368
379
|
validatePolicyNames(policyNames);
|
|
369
|
-
const config =
|
|
380
|
+
const config = readScopedHooksConfig(configScope, cwd);
|
|
370
381
|
const removeSet = new Set(policyNames);
|
|
371
382
|
const remaining = config.enabledPolicies.filter((p) => !removeSet.has(p));
|
|
372
383
|
const notEnabled = policyNames.filter((p) => !config.enabledPolicies.includes(p));
|
|
@@ -382,7 +393,7 @@ export async function removeHooks(policyNames?: string[], scope: HookScope | "al
|
|
|
382
393
|
enabledPolicies: remaining,
|
|
383
394
|
...(filteredParams && Object.keys(filteredParams).length > 0 ? { policyParams: filteredParams } : {}),
|
|
384
395
|
};
|
|
385
|
-
|
|
396
|
+
writeScopedHooksConfig(updatedConfig, configScope, cwd);
|
|
386
397
|
|
|
387
398
|
// Telemetry: track policy-only removal from config
|
|
388
399
|
try {
|
|
@@ -410,7 +421,7 @@ export async function removeHooks(policyNames?: string[], scope: HookScope | "al
|
|
|
410
421
|
}
|
|
411
422
|
|
|
412
423
|
// Capture enabled policies before clearing (used for accurate telemetry below)
|
|
413
|
-
const configBeforeRemoval =
|
|
424
|
+
const configBeforeRemoval = readScopedHooksConfig(configScope, cwd);
|
|
414
425
|
|
|
415
426
|
// Remove all failproofai hooks from Claude Code settings
|
|
416
427
|
const scopesToRemove: HookScope[] = scope === "all" ? [...HOOK_SCOPES] : [scope];
|
|
@@ -472,10 +483,19 @@ export async function removeHooks(policyNames?: string[], scope: HookScope | "al
|
|
|
472
483
|
}
|
|
473
484
|
|
|
474
485
|
// Clear policy config when removing from all scopes, or when no hooks remain in any scope
|
|
475
|
-
if (scope === "all"
|
|
476
|
-
|
|
477
|
-
const
|
|
478
|
-
|
|
486
|
+
if (scope === "all") {
|
|
487
|
+
// Clear config across all three scopes
|
|
488
|
+
for (const s of HOOK_SCOPES) {
|
|
489
|
+
const existing = readScopedHooksConfig(s, cwd);
|
|
490
|
+
if (existing.enabledPolicies.length > 0 || existing.customPoliciesPath || existing.policyParams) {
|
|
491
|
+
const { customPoliciesPath: _drop, policyParams: _dropParams, ...rest } = existing;
|
|
492
|
+
writeScopedHooksConfig({ ...rest, enabledPolicies: [] }, s, cwd);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
} else if (!HOOK_SCOPES.some((s) => hooksInstalledInSettings(s, cwd))) {
|
|
496
|
+
const existing = readScopedHooksConfig(configScope, cwd);
|
|
497
|
+
const { customPoliciesPath: _drop, policyParams: _dropParams, ...rest } = existing;
|
|
498
|
+
writeScopedHooksConfig({ ...rest, enabledPolicies: [] }, configScope, cwd);
|
|
479
499
|
}
|
|
480
500
|
}
|
|
481
501
|
|
|
@@ -638,4 +658,35 @@ export async function listHooks(cwd?: string): Promise<void> {
|
|
|
638
658
|
}
|
|
639
659
|
console.log();
|
|
640
660
|
}
|
|
661
|
+
|
|
662
|
+
// Convention Policies section (.failproofai/policies/*policies.{js,mjs,ts})
|
|
663
|
+
const base = cwd ? resolve(cwd) : process.cwd();
|
|
664
|
+
const conventionDirs: { label: string; dir: string }[] = [
|
|
665
|
+
{ label: "Project", dir: resolve(base, ".failproofai", "policies") },
|
|
666
|
+
{ label: "User", dir: resolve(homedir(), ".failproofai", "policies") },
|
|
667
|
+
];
|
|
668
|
+
|
|
669
|
+
for (const { label, dir } of conventionDirs) {
|
|
670
|
+
const files = discoverPolicyFiles(dir);
|
|
671
|
+
if (files.length === 0) continue;
|
|
672
|
+
|
|
673
|
+
console.log(`\n \u2500\u2500 Convention Policies \u2014 ${label} (${dir}) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`);
|
|
674
|
+
for (const file of files) {
|
|
675
|
+
try {
|
|
676
|
+
const hooks = await loadCustomHooks(file);
|
|
677
|
+
if (hooks.length === 0) {
|
|
678
|
+
const filename = basename(file);
|
|
679
|
+
console.log(` \x1B[31m\u2717\x1B[0m ${filename.padEnd(nameColWidth)}\x1B[31mfailed to load\x1B[0m`);
|
|
680
|
+
} else {
|
|
681
|
+
const filename = basename(file);
|
|
682
|
+
const hookSummary = hooks.map((h) => h.name).join(", ");
|
|
683
|
+
console.log(` \x1B[32m\u2713\x1B[0m ${filename.padEnd(nameColWidth)}${hooks.length} hook(s): ${hookSummary}`);
|
|
684
|
+
}
|
|
685
|
+
} catch {
|
|
686
|
+
const filename = basename(file);
|
|
687
|
+
console.log(` \x1B[31m\u2717\x1B[0m ${filename.padEnd(nameColWidth)}\x1B[31merror\x1B[0m`);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
console.log();
|
|
691
|
+
}
|
|
641
692
|
}
|