failproofai 0.0.2-beta.7 → 0.0.2-beta.9
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 +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/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/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/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/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/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/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/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/package_json_[json]_cjs_0z7w.hh._.js +1 -1
- 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]__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]__05zi2mt._.js → [root-of-the-server]__0vn1ciw._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0w6l33k._.js +2 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0kkt_9z._.js → [root-of-the-server]__0z-n~~r._.js} +2 -2
- 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/_0x..fj-._.js +1 -1
- 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/middleware-build-manifest.js +3 -3
- 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/{0ltx5i0xv85_s.js → 04wavch6dsfes.js} +1 -1
- package/.next/standalone/.next/static/chunks/{13jdpvk~s2da8.js → 0drr--vxs_m-c.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0jf9lx3rkmqx_.css → 0gu_a.a80ritd.css} +1 -1
- package/.next/standalone/.next/static/chunks/{0e76l4~hq_sei.js → 0i1ilz5554nv9.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0suauczjqzn07.js → 0keqg6-cjs8aa.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0w.rtg9.m8dk-.js → 0myzx7y.rqqi3.js} +2 -2
- package/.next/standalone/.next/static/chunks/{02u4v.k5amfah.js → 0zfrusm~j404v.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0bkizbynk9via.js → 10xhknzfyigcu.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0q7atesxo-36k.js → 16yg3xhkmdb9v.js} +1 -1
- package/.next/standalone/CHANGELOG.md +27 -0
- package/.next/standalone/CLAUDE.md +14 -0
- package/.next/standalone/README.md +16 -0
- package/.next/standalone/bun.lock +45 -0
- package/.next/standalone/dist/cli.mjs +44 -23
- 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/built-in-policies.mdx +17 -1
- package/.next/standalone/docs/configuration.mdx +1 -1
- package/.next/standalone/docs/custom-policies.mdx +3 -3
- 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 +922 -35
- 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/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/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/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/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/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/package.json +8 -2
- 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/src/hooks/custom-hooks-loader.ts +12 -5
- package/.next/standalone/src/hooks/handler.ts +9 -3
- package/.next/standalone/src/hooks/manager.ts +10 -2
- package/.next/standalone/src/hooks/policy-evaluator.ts +20 -16
- package/README.md +16 -0
- package/dist/cli.mjs +44 -23
- package/package.json +8 -2
- 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/custom-hooks-loader.ts +12 -5
- package/src/hooks/handler.ts +9 -3
- package/src/hooks/manager.ts +10 -2
- package/src/hooks/policy-evaluator.ts +20 -16
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__02nt~6d._.js +0 -3
- /package/.next/standalone/.next/static/{Opbai6exOQP2W488FWmr6 → XqGmAwGDuJ6fEQgD-8y60}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{Opbai6exOQP2W488FWmr6 → XqGmAwGDuJ6fEQgD-8y60}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{Opbai6exOQP2W488FWmr6 → XqGmAwGDuJ6fEQgD-8y60}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 패키지 별칭
|
|
3
|
+
description: "등록된 오타 방지 별칭과 그 작동 방식"
|
|
4
|
+
icon: copy
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 공식 패키지
|
|
8
|
+
|
|
9
|
+
npm의 정식 패키지명은 **`failproofai`**입니다:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install -g failproofai
|
|
13
|
+
# or
|
|
14
|
+
bun add -g failproofai
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 별칭 이름을 직접 소유하는 이유
|
|
20
|
+
|
|
21
|
+
타이포스쿼팅(typosquatting)은 공급망 공격의 일반적인 유형으로, 악의적인 공격자가 인기 패키지명에서 한 글자만 다른 패키지를 등록합니다. 설치 명령어를 잘못 입력한 사용자는 자신도 모르게 공격자가 제어하는 코드를 전체 시스템 접근 권한으로 실행하게 됩니다. 이는 바로 Failproof AI가 막아내고자 하는 위협입니다.
|
|
22
|
+
|
|
23
|
+
이 공격 표면을 없애기 위해, **npm에서 `failproofai`의 모든 일반적인 오타 및 표기 변형을 선제적으로 소유**하고 있습니다. 이 이름들은 제3자가 등록할 수 없으며, 각각은 실제 `failproofai` 패키지를 설치하고 위임하는 얇은 프록시입니다.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 등록된 별칭
|
|
28
|
+
|
|
29
|
+
**표기 변형** - "failproof ai"를 작성하는 다양한 방식:
|
|
30
|
+
|
|
31
|
+
| 패키지 | 상태 |
|
|
32
|
+
|---------|--------|
|
|
33
|
+
| `failproof` | ✅ 게시됨 |
|
|
34
|
+
| `failproof-ai` | ⏳ npm 승인 대기 중 |
|
|
35
|
+
| `fail-proof-ai` | ⏳ npm 승인 대기 중 |
|
|
36
|
+
| `failproof_ai` | ⏳ npm 승인 대기 중 |
|
|
37
|
+
| `fail_proof_ai` | ⏳ npm 승인 대기 중 |
|
|
38
|
+
| `fail-proofai` | ⏳ npm 승인 대기 중 |
|
|
39
|
+
|
|
40
|
+
**`failprof*` 오타** - "proof"에서 `o` 하나가 빠진 경우:
|
|
41
|
+
|
|
42
|
+
| 패키지 | 상태 |
|
|
43
|
+
|---------|--------|
|
|
44
|
+
| `failprof` | ✅ 게시됨 |
|
|
45
|
+
| `failprof-ai` | ✅ 게시됨 |
|
|
46
|
+
| `failprofai` | ⏳ npm 승인 대기 중 |
|
|
47
|
+
| `fail-prof-ai` | ⏳ npm 승인 대기 중 |
|
|
48
|
+
| `failprof_ai` | ⏳ npm 승인 대기 중 |
|
|
49
|
+
|
|
50
|
+
**`faliproof*` 오타** - `a`와 `i`가 뒤바뀐 경우:
|
|
51
|
+
|
|
52
|
+
| 패키지 | 상태 |
|
|
53
|
+
|---------|--------|
|
|
54
|
+
| `faliproof` | ✅ 게시됨 |
|
|
55
|
+
| `faliproof-ai` | ✅ 게시됨 |
|
|
56
|
+
| `faliproofai` | ⏳ npm 승인 대기 중 |
|
|
57
|
+
|
|
58
|
+
> **왜 대기 중인가요?** npm의 스팸 방지 정책은 구두점을 제거하고 유사도 검사를 수행한 후 기존 패키지와 동일한 문자열로 정규화되는 이름의 등록을 차단합니다. 현재 스쿼팅 방지 목적으로 이 이름들을 예약하기 위해 npm 지원팀에 문의한 상태이며, 승인 후 활성화될 예정입니다.
|
|
59
|
+
|
|
60
|
+
게시된 별칭이 저희 소유인지 다음 명령어로 확인할 수 있습니다:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npm info failproof
|
|
64
|
+
# Look for: "ExosphereHost Inc." in the maintainers field
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 별칭의 작동 방식
|
|
70
|
+
|
|
71
|
+
각 별칭 패키지는:
|
|
72
|
+
|
|
73
|
+
1. `failproofai`를 의존성으로 등록하여, 설치 시 실제 패키지(및 해당 `postinstall` 훅 설정)가 실행됩니다.
|
|
74
|
+
2. 자체 이름(예: `failprof-ai`)에 해당하는 바이너리를 노출하며, 모든 인수를 `failproofai` 바이너리로 프록시합니다.
|
|
75
|
+
|
|
76
|
+
프록시는 두 줄짜리 Node 스크립트로, 로직도 없고 네트워크 호출도 없으며, `failproofai` 자체가 수행하는 것 이상의 데이터 수집도 없습니다.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 누락된 이름을 발견했다면
|
|
81
|
+
|
|
82
|
+
[exospherehost/failproofai](https://github.com/exospherehost/failproofai/issues)에 이슈를 등록해 주시면 등록하겠습니다.
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 테스트
|
|
3
|
+
description: "유닛 테스트, E2E 테스트, 테스트 헬퍼"
|
|
4
|
+
icon: flask-vial
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
failproofai에는 두 가지 테스트 스위트가 있습니다: **유닛 테스트** (빠르고 모킹 사용)와 **엔드투엔드 테스트** (실제 서브프로세스 실행).
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 테스트 실행
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# 유닛 테스트를 한 번 실행
|
|
15
|
+
bun run test:run
|
|
16
|
+
|
|
17
|
+
# 유닛 테스트를 워치 모드로 실행
|
|
18
|
+
bun run test
|
|
19
|
+
|
|
20
|
+
# E2E 테스트 실행 (설정 필요 - 아래 참고)
|
|
21
|
+
bun run test:e2e
|
|
22
|
+
|
|
23
|
+
# 빌드 없이 타입 검사
|
|
24
|
+
bunx tsc --noEmit
|
|
25
|
+
|
|
26
|
+
# 린트
|
|
27
|
+
bun run lint
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 유닛 테스트
|
|
33
|
+
|
|
34
|
+
유닛 테스트는 `__tests__/` 디렉터리에 위치하며 `happy-dom`과 함께 [Vitest](https://vitest.dev)를 사용합니다.
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
__tests__/
|
|
38
|
+
hooks/
|
|
39
|
+
builtin-policies.test.ts # 각 내장 정책의 로직
|
|
40
|
+
hooks-config.test.ts # 설정 로딩 및 스코프 병합
|
|
41
|
+
policy-evaluator.test.ts # 파라미터 주입과 평가 순서
|
|
42
|
+
custom-hooks-registry.test.ts # globalThis 레지스트리 add/get/clear
|
|
43
|
+
custom-hooks-loader.test.ts # ESM 로더, 전이적 임포트, 오류 처리
|
|
44
|
+
manager.test.ts # install/remove/list 작업
|
|
45
|
+
components/
|
|
46
|
+
sessions-list.test.tsx # 세션 목록 컴포넌트
|
|
47
|
+
project-list.test.tsx # 프로젝트 목록 컴포넌트
|
|
48
|
+
...
|
|
49
|
+
lib/
|
|
50
|
+
logger.test.ts
|
|
51
|
+
paths.test.ts
|
|
52
|
+
date-filters.test.ts
|
|
53
|
+
telemetry.test.ts
|
|
54
|
+
...
|
|
55
|
+
actions/
|
|
56
|
+
get-hooks-config.test.ts
|
|
57
|
+
get-hook-activity.test.ts
|
|
58
|
+
...
|
|
59
|
+
contexts/
|
|
60
|
+
ThemeContext.test.tsx
|
|
61
|
+
AutoRefreshContext.test.tsx
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 정책 유닛 테스트 작성하기
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { describe, it, expect, beforeEach } from "vitest";
|
|
68
|
+
import { getBuiltinPolicies } from "../../src/hooks/builtin-policies";
|
|
69
|
+
import { allow, deny } from "../../src/hooks/policy-types";
|
|
70
|
+
|
|
71
|
+
describe("block-sudo", () => {
|
|
72
|
+
const policy = getBuiltinPolicies().find((p) => p.name === "block-sudo")!;
|
|
73
|
+
|
|
74
|
+
it("denies sudo commands", () => {
|
|
75
|
+
const ctx = {
|
|
76
|
+
eventType: "PreToolUse" as const,
|
|
77
|
+
payload: {},
|
|
78
|
+
toolName: "Bash",
|
|
79
|
+
toolInput: { command: "sudo apt install nodejs" },
|
|
80
|
+
params: { allowPatterns: [] },
|
|
81
|
+
};
|
|
82
|
+
expect(policy.fn(ctx)).toEqual(deny("sudo command blocked by failproofai"));
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("allows non-sudo commands", () => {
|
|
86
|
+
const ctx = {
|
|
87
|
+
eventType: "PreToolUse" as const,
|
|
88
|
+
payload: {},
|
|
89
|
+
toolName: "Bash",
|
|
90
|
+
toolInput: { command: "ls -la" },
|
|
91
|
+
params: { allowPatterns: [] },
|
|
92
|
+
};
|
|
93
|
+
expect(policy.fn(ctx)).toEqual(allow());
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("allows patterns in allowPatterns", () => {
|
|
97
|
+
const ctx = {
|
|
98
|
+
eventType: "PreToolUse" as const,
|
|
99
|
+
payload: {},
|
|
100
|
+
toolName: "Bash",
|
|
101
|
+
toolInput: { command: "sudo systemctl status nginx" },
|
|
102
|
+
params: { allowPatterns: ["sudo systemctl status"] },
|
|
103
|
+
};
|
|
104
|
+
expect(policy.fn(ctx)).toEqual(allow());
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 엔드투엔드 테스트
|
|
112
|
+
|
|
113
|
+
E2E 테스트는 실제 `failproofai` 바이너리를 서브프로세스로 실행하고, JSON 페이로드를 stdin으로 파이핑한 뒤, stdout 출력과 종료 코드를 검증합니다. 이를 통해 Claude Code가 실제로 사용하는 전체 통합 경로를 테스트합니다.
|
|
114
|
+
|
|
115
|
+
### 설정
|
|
116
|
+
|
|
117
|
+
E2E 테스트는 저장소 소스에서 바이너리를 직접 실행합니다. 최초 실행 전에, 커스텀 훅 파일이 `'failproofai'`에서 임포트할 때 사용하는 CJS 번들을 빌드하세요:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
bun build src/index.ts --outdir dist --target node --format cjs
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
그 다음 테스트를 실행합니다:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
bun run test:e2e
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
공개 훅 API(`src/hooks/custom-hooks-registry.ts`, `src/hooks/policy-helpers.ts`, `src/hooks/policy-types.ts`)를 변경할 때마다 `dist/`를 다시 빌드하세요.
|
|
130
|
+
|
|
131
|
+
### E2E 테스트 구조
|
|
132
|
+
|
|
133
|
+
```text
|
|
134
|
+
__tests__/e2e/
|
|
135
|
+
helpers/
|
|
136
|
+
hook-runner.ts # 바이너리 실행, 페이로드 JSON 파이핑, 종료 코드 + stdout + stderr 캡처
|
|
137
|
+
fixture-env.ts # 테스트별 격리된 임시 디렉터리와 설정 파일
|
|
138
|
+
payloads.ts # 각 이벤트 타입에 대한 Claude 형식의 페이로드 팩토리
|
|
139
|
+
hooks/
|
|
140
|
+
builtin-policies.e2e.test.ts # 실제 서브프로세스로 각 내장 정책 테스트
|
|
141
|
+
custom-hooks.e2e.test.ts # 커스텀 훅 로딩 및 평가
|
|
142
|
+
config-scopes.e2e.test.ts # 프로젝트/로컬/글로벌 간 설정 병합
|
|
143
|
+
policy-params.e2e.test.ts # 파라미터화된 정책별 파라미터 주입
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### E2E 헬퍼 사용하기
|
|
147
|
+
|
|
148
|
+
**`FixtureEnv`** - 테스트별 격리 환경:
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
import { createFixtureEnv } from "../helpers/fixture-env";
|
|
152
|
+
|
|
153
|
+
const env = createFixtureEnv();
|
|
154
|
+
// env.cwd - 임시 디렉터리; payload.cwd로 전달하면 .failproofai/policies-config.json을 읽음
|
|
155
|
+
// env.home - 격리된 홈 디렉터리; 실제 ~/.failproofai가 누출되지 않음
|
|
156
|
+
|
|
157
|
+
env.writeConfig({
|
|
158
|
+
enabledPolicies: ["block-sudo"],
|
|
159
|
+
policyParams: {
|
|
160
|
+
"block-sudo": { allowPatterns: ["sudo systemctl status"] },
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
`createFixtureEnv()`는 `afterEach` 정리를 자동으로 등록합니다.
|
|
166
|
+
|
|
167
|
+
**`runHook`** - 바이너리 실행:
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import { runHook } from "../helpers/hook-runner";
|
|
171
|
+
import { Payloads } from "../helpers/payloads";
|
|
172
|
+
|
|
173
|
+
const result = await runHook(
|
|
174
|
+
"PreToolUse",
|
|
175
|
+
Payloads.preToolUse.bash("sudo apt install nodejs", env.cwd),
|
|
176
|
+
{ homeDir: env.home }
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
expect(result.exitCode).toBe(0);
|
|
180
|
+
expect(result.parsed?.hookSpecificOutput?.permissionDecision).toBe("deny");
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**`Payloads`** - 미리 준비된 페이로드 팩토리:
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
Payloads.preToolUse.bash(command, cwd)
|
|
187
|
+
Payloads.preToolUse.write(filePath, content, cwd)
|
|
188
|
+
Payloads.preToolUse.read(filePath, cwd)
|
|
189
|
+
Payloads.postToolUse.bash(command, output, cwd)
|
|
190
|
+
Payloads.postToolUse.read(filePath, content, cwd)
|
|
191
|
+
Payloads.notification(message, cwd)
|
|
192
|
+
Payloads.stop(cwd)
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### E2E 테스트 작성하기
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
import { describe, it, expect } from "vitest";
|
|
199
|
+
import { createFixtureEnv } from "../helpers/fixture-env";
|
|
200
|
+
import { runHook } from "../helpers/hook-runner";
|
|
201
|
+
import { Payloads } from "../helpers/payloads";
|
|
202
|
+
|
|
203
|
+
describe("block-rm-rf (E2E)", () => {
|
|
204
|
+
it("denies rm -rf", async () => {
|
|
205
|
+
const env = createFixtureEnv();
|
|
206
|
+
env.writeConfig({ enabledPolicies: ["block-rm-rf"] });
|
|
207
|
+
|
|
208
|
+
const result = await runHook(
|
|
209
|
+
"PreToolUse",
|
|
210
|
+
Payloads.preToolUse.bash("rm -rf /", env.cwd),
|
|
211
|
+
{ homeDir: env.home }
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
expect(result.exitCode).toBe(0);
|
|
215
|
+
expect(result.parsed?.hookSpecificOutput?.permissionDecision).toBe("deny");
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it("allows non-recursive rm", async () => {
|
|
219
|
+
const env = createFixtureEnv();
|
|
220
|
+
env.writeConfig({ enabledPolicies: ["block-rm-rf"] });
|
|
221
|
+
|
|
222
|
+
const result = await runHook(
|
|
223
|
+
"PreToolUse",
|
|
224
|
+
Payloads.preToolUse.bash("rm /tmp/file.txt", env.cwd),
|
|
225
|
+
{ homeDir: env.home }
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
expect(result.exitCode).toBe(0);
|
|
229
|
+
expect(result.stdout).toBe(""); // allow → 빈 stdout
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### E2E 응답 형식
|
|
235
|
+
|
|
236
|
+
| 결정 | 종료 코드 | stdout |
|
|
237
|
+
|----------|-----------|--------|
|
|
238
|
+
| `PreToolUse` deny | `0` | `{"hookSpecificOutput":{"permissionDecision":"deny","permissionDecisionReason":"..."}}` |
|
|
239
|
+
| `PostToolUse` deny | `0` | `{"hookSpecificOutput":{"additionalContext":"Blocked ... because: ..."}}` |
|
|
240
|
+
| Instruct (Stop 제외) | `0` | `{"hookSpecificOutput":{"additionalContext":"Instruction from failproofai: ..."}}` |
|
|
241
|
+
| Stop instruct | `2` | 빈 stdout; 이유는 stderr에 기록 |
|
|
242
|
+
| Allow | `0` | 빈 문자열 |
|
|
243
|
+
|
|
244
|
+
### Vitest 설정
|
|
245
|
+
|
|
246
|
+
E2E 테스트는 다음 설정으로 `vitest.config.e2e.mts`를 사용합니다:
|
|
247
|
+
|
|
248
|
+
- `environment: "node"` - 브라우저 전역 객체 불필요
|
|
249
|
+
- `pool: "forks"` - 진정한 프로세스 격리 (테스트가 서브프로세스를 생성)
|
|
250
|
+
- `testTimeout: 20_000` - 테스트당 20초 (바이너리 시작 + 훅 평가)
|
|
251
|
+
|
|
252
|
+
`forks` 풀이 중요한 이유: 스레드 기반 워커는 `globalThis`를 공유하므로, 서브프로세스를 생성하는 테스트에 영향을 줄 수 있습니다. 프로세스 기반 포크는 이를 방지합니다.
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## CI
|
|
257
|
+
|
|
258
|
+
머지 전에 전체 CI 실행(`bun run lint && bunx tsc --noEmit && bun run test:run && bun run build`)이 통과되어야 합니다. E2E 스위트는 별도의 CI 작업으로 병렬 실행됩니다.
|
|
259
|
+
|
|
260
|
+
완전한 머지 전 체크리스트는 [Contributing](../CONTRIBUTING.md)을 참고하세요.
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Arquitetura
|
|
3
|
+
description: "Como o handler de hooks, o carregamento de configuração e a avaliação de políticas funcionam internamente"
|
|
4
|
+
icon: sitemap
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Este documento explica como o failproofai funciona internamente: como o sistema de hooks intercepta chamadas de ferramentas do agente, como a configuração é carregada e mesclada, como as políticas são avaliadas e como o dashboard monitora a atividade do agente.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Visão geral
|
|
12
|
+
|
|
13
|
+
O failproofai possui dois subsistemas independentes:
|
|
14
|
+
|
|
15
|
+
1. **Hook handler** - Um subprocesso CLI rápido que o Claude Code invoca a cada chamada de ferramenta do agente. Avalia as políticas e retorna uma decisão.
|
|
16
|
+
2. **Monitor de Agentes (Dashboard)** - Uma aplicação web Next.js para monitorar sessões de agentes e gerenciar políticas.
|
|
17
|
+
|
|
18
|
+
Ambos os subsistemas compartilham arquivos de configuração em `~/.failproofai/` e no diretório `.failproofai/` do projeto, mas são executados como processos separados e se comunicam apenas pelo sistema de arquivos.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Hook handler
|
|
23
|
+
|
|
24
|
+
### Integração com o Claude Code
|
|
25
|
+
|
|
26
|
+
Quando você executa `failproofai policies --install`, ele escreve entradas como esta em `~/.claude/settings.json`:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"hooks": {
|
|
31
|
+
"PreToolUse": [
|
|
32
|
+
{
|
|
33
|
+
"matcher": "",
|
|
34
|
+
"hooks": [
|
|
35
|
+
{
|
|
36
|
+
"type": "command",
|
|
37
|
+
"command": "failproofai --hook PreToolUse"
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
"PostToolUse": [ ... ]
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
O Claude Code então invoca `failproofai --hook PreToolUse` como subprocesso antes de cada chamada de ferramenta, passando um payload JSON via stdin.
|
|
48
|
+
|
|
49
|
+
### Formato do payload
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"session_id": "abc123",
|
|
54
|
+
"transcript_path": "/home/user/.claude/projects/myproject/sessions/abc123.jsonl",
|
|
55
|
+
"cwd": "/home/user/myproject",
|
|
56
|
+
"permission_mode": "default",
|
|
57
|
+
"hook_event_name": "PreToolUse",
|
|
58
|
+
"tool_name": "Bash",
|
|
59
|
+
"tool_input": { "command": "sudo apt install nodejs" }
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Para eventos `PostToolUse`, o payload também contém `tool_result` com a saída da ferramenta.
|
|
64
|
+
|
|
65
|
+
O handler impõe um limite de 1 MB para stdin. Payloads que excedam esse tamanho são descartados e todas as políticas permitem implicitamente.
|
|
66
|
+
|
|
67
|
+
### Formato da resposta
|
|
68
|
+
|
|
69
|
+
**Deny (PreToolUse):**
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"hookSpecificOutput": {
|
|
73
|
+
"permissionDecision": "deny",
|
|
74
|
+
"permissionDecisionReason": "Blocked by failproofai: sudo command blocked"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Deny (PostToolUse):**
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"hookSpecificOutput": {
|
|
83
|
+
"additionalContext": "Blocked by failproofai because: API key detected in output"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Instruct (qualquer evento exceto Stop):**
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"hookSpecificOutput": {
|
|
92
|
+
"additionalContext": "Instruction from failproofai: Verify tests pass before committing."
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Instruct para evento Stop:**
|
|
98
|
+
- Código de saída: `2`
|
|
99
|
+
- Motivo escrito em stderr (não em stdout)
|
|
100
|
+
|
|
101
|
+
**Allow:**
|
|
102
|
+
- Código de saída: `0`
|
|
103
|
+
- stdout vazio
|
|
104
|
+
|
|
105
|
+
**Allow com mensagem (beta):**
|
|
106
|
+
|
|
107
|
+
Desde a v0.0.2-beta.3, `allow(message)` permite que uma política envie contexto informativo de volta ao Claude mesmo quando a operação é permitida. O hook handler escreve o seguinte JSON em **stdout** (não em um arquivo de configuração — esta é a resposta do handler ao Claude Code, assim como as respostas de deny e instruct acima):
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
// Written to stdout by the hook handler process
|
|
111
|
+
{
|
|
112
|
+
"hookSpecificOutput": {
|
|
113
|
+
"additionalContext": "All CI checks passed on branch 'feat/my-feature'."
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
- Código de saída: `0` (a operação é permitida)
|
|
118
|
+
- Quando múltiplas políticas retornam `allow` com uma mensagem, suas mensagens são unidas com quebras de linha em uma única string `additionalContext`
|
|
119
|
+
- Se nenhuma política fornecer uma mensagem, stdout fica vazio (igual ao comportamento anterior)
|
|
120
|
+
|
|
121
|
+
### Pipeline de processamento
|
|
122
|
+
|
|
123
|
+
`src/hooks/handler.ts` implementa o pipeline completo:
|
|
124
|
+
|
|
125
|
+
```text
|
|
126
|
+
stdin JSON
|
|
127
|
+
→ parse payload (max 1 MB)
|
|
128
|
+
→ extract session metadata (session_id, cwd, tool_name, tool_input, etc.)
|
|
129
|
+
→ readMergedHooksConfig(cwd) ← merges project + local + global config
|
|
130
|
+
→ register enabled builtin policies with resolved params
|
|
131
|
+
→ load custom policies from customPoliciesPath (if set)
|
|
132
|
+
→ register custom policies into policy registry
|
|
133
|
+
→ evaluate all policies (builtins first, then custom)
|
|
134
|
+
→ first deny short-circuits
|
|
135
|
+
→ instruct decisions accumulate
|
|
136
|
+
→ allow messages accumulate
|
|
137
|
+
→ write JSON decision to stdout
|
|
138
|
+
→ persist event to ~/.failproofai/hook-activity.jsonl
|
|
139
|
+
→ exit
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Todo o processo é executado em menos de 100ms para payloads típicos, sem nenhuma chamada a LLMs.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Carregamento de configuração
|
|
147
|
+
|
|
148
|
+
`src/hooks/hooks-config.ts` implementa o carregamento de configuração em três escopos.
|
|
149
|
+
|
|
150
|
+
```text
|
|
151
|
+
[1] {cwd}/.failproofai/policies-config.json ← projeto (maior prioridade)
|
|
152
|
+
[2] {cwd}/.failproofai/policies-config.local.json ← local
|
|
153
|
+
[3] ~/.failproofai/policies-config.json ← global (menor prioridade)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Lógica de mesclagem:
|
|
157
|
+
- `enabledPolicies` - união sem duplicatas entre os três arquivos
|
|
158
|
+
- `policyParams` - por chave de política, o primeiro arquivo que a define vence inteiramente
|
|
159
|
+
- `customPoliciesPath` - o primeiro arquivo que a define vence
|
|
160
|
+
- `llm` - o primeiro arquivo que a define vence
|
|
161
|
+
|
|
162
|
+
O dashboard web utiliza `readHooksConfig()` (somente global) para leitura e escrita, pois não é invocado com um cwd de projeto.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Avaliação de políticas
|
|
167
|
+
|
|
168
|
+
`src/hooks/policy-evaluator.ts` executa as políticas em ordem.
|
|
169
|
+
|
|
170
|
+
Para cada política:
|
|
171
|
+
|
|
172
|
+
1. Busca o esquema de `params` da política (se houver).
|
|
173
|
+
2. Lê `policyParams[policy.name]` da configuração mesclada.
|
|
174
|
+
3. Mescla os valores fornecidos pelo usuário sobre os padrões do esquema para produzir `ctx.params`.
|
|
175
|
+
4. Chama `policy.fn(ctx)` com o contexto resolvido.
|
|
176
|
+
5. Se o resultado for `deny`, interrompe imediatamente e retorna essa decisão.
|
|
177
|
+
6. Se o resultado for `instruct`, acumula a mensagem e continua.
|
|
178
|
+
7. Se o resultado for `allow`, continua para a próxima política.
|
|
179
|
+
|
|
180
|
+
Após todas as políticas serem executadas:
|
|
181
|
+
- Se algum `deny` foi retornado, emite a resposta de deny.
|
|
182
|
+
- Se algum retorno `instruct` foi coletado, emite uma única resposta instruct com todas as mensagens unidas.
|
|
183
|
+
- Caso contrário, emite uma resposta allow (stdout vazio, saída 0).
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Políticas embutidas
|
|
188
|
+
|
|
189
|
+
`src/hooks/builtin-policies.ts` define todas as 26 políticas embutidas como objetos `BuiltinPolicyDefinition`:
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
interface BuiltinPolicyDefinition {
|
|
193
|
+
name: string;
|
|
194
|
+
description: string;
|
|
195
|
+
fn: (ctx: PolicyContext) => PolicyResult;
|
|
196
|
+
match: {
|
|
197
|
+
events: HookEventType[];
|
|
198
|
+
tools?: string[];
|
|
199
|
+
};
|
|
200
|
+
defaultEnabled: boolean;
|
|
201
|
+
category: string;
|
|
202
|
+
beta?: boolean;
|
|
203
|
+
params?: PolicyParamsSchema;
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Políticas que aceitam `params` declaram um `PolicyParamsSchema` com tipos e valores padrão para cada parâmetro. O avaliador de políticas injeta os valores resolvidos em `ctx.params` antes de chamar `fn`. As funções de política leem `ctx.params` sem verificações de nulo porque os padrões são sempre aplicados primeiro.
|
|
208
|
+
|
|
209
|
+
A correspondência de padrões dentro das políticas usa tokens de comando analisados (argv), não correspondência de strings brutas. Isso evita bypass por injeção de operadores shell (por exemplo, um padrão para `sudo systemctl status *` não pode ser ignorado anexando `; rm -rf /` ao comando).
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Políticas personalizadas
|
|
214
|
+
|
|
215
|
+
`src/hooks/custom-hooks-registry.ts` implementa um registro baseado em `globalThis`:
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
const REGISTRY_KEY = "__failproofai_custom_hooks__";
|
|
219
|
+
|
|
220
|
+
export const customPolicies = {
|
|
221
|
+
add(hook: CustomHook): void { ... }
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
export function getCustomHooks(): CustomHook[] { ... }
|
|
225
|
+
export function clearCustomHooks(): void { ... } // used in tests
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
`src/hooks/custom-hooks-loader.ts` carrega o arquivo de políticas do usuário:
|
|
229
|
+
|
|
230
|
+
1. Lê `customPoliciesPath` da configuração; ignora se ausente.
|
|
231
|
+
2. Resolve para caminho absoluto; verifica se o arquivo existe.
|
|
232
|
+
3. Reescreve todas as importações `from "failproofai"` para o caminho real do dist, de modo que `customPolicies` resolva para o mesmo registro `globalThis`.
|
|
233
|
+
4. Reescreve recursivamente importações locais transitivas para garantir compatibilidade ESM.
|
|
234
|
+
5. Grava arquivos `.mjs` temporários e realiza `import()` do arquivo de entrada.
|
|
235
|
+
6. Chama `getCustomHooks()` para recuperar os hooks registrados.
|
|
236
|
+
7. Limpa todos os arquivos temporários em um bloco `finally`.
|
|
237
|
+
|
|
238
|
+
Em caso de qualquer erro (arquivo não encontrado, erro de sintaxe, falha na importação), o erro é registrado em `~/.failproofai/hook.log` e o loader retorna um array vazio. As políticas embutidas não são afetadas.
|
|
239
|
+
|
|
240
|
+
As políticas personalizadas são avaliadas após todas as políticas embutidas. Um `deny` de política personalizada ainda interrompe as demais políticas personalizadas (mas todos os embutidos já terão sido executados nesse ponto).
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Log de atividade
|
|
245
|
+
|
|
246
|
+
Após cada evento de hook, o handler anexa uma linha JSONL em `~/.failproofai/hook-activity.jsonl`:
|
|
247
|
+
|
|
248
|
+
```json
|
|
249
|
+
{
|
|
250
|
+
"timestamp": "2026-04-06T12:34:56.789Z",
|
|
251
|
+
"sessionId": "abc123",
|
|
252
|
+
"eventType": "PreToolUse",
|
|
253
|
+
"toolName": "Bash",
|
|
254
|
+
"policyName": "block-sudo",
|
|
255
|
+
"decision": "deny",
|
|
256
|
+
"reason": "sudo command blocked by failproofai",
|
|
257
|
+
"durationMs": 12
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Uma linha por política que tomou uma decisão diferente de allow. Decisões allow não são registradas (para manter o arquivo pequeno).
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Arquitetura do dashboard
|
|
266
|
+
|
|
267
|
+
O dashboard é uma aplicação **Next.js 16** usando o App Router com React Server Components e Server Actions.
|
|
268
|
+
|
|
269
|
+
```text
|
|
270
|
+
app/
|
|
271
|
+
layout.tsx ← Layout raiz (tema, telemetria, navegação)
|
|
272
|
+
projects/page.tsx ← Server component: lista todos os projetos Claude
|
|
273
|
+
project/[name]/page.tsx ← Server component: lista sessões em um projeto
|
|
274
|
+
project/[name]/session/
|
|
275
|
+
[sessionId]/page.tsx ← Server component: renderiza o visualizador de sessão
|
|
276
|
+
policies/page.tsx ← Client component: gerenciamento de políticas + log de atividade
|
|
277
|
+
actions/
|
|
278
|
+
get-hooks-config.ts ← Lê configuração + lista de políticas
|
|
279
|
+
update-hooks-config.ts ← Ativa/desativa política
|
|
280
|
+
update-policy-params.ts ← Atualiza parâmetros da política
|
|
281
|
+
get-hook-activity.ts ← Paginação/busca no log de atividade
|
|
282
|
+
install-hooks-web.ts ← Instala/remove hooks pelo navegador
|
|
283
|
+
api/
|
|
284
|
+
download/[project]/[session]/route.ts ← Exporta sessão como ZIP/JSONL
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
**Fluxo de dados:**
|
|
288
|
+
|
|
289
|
+
- Os componentes de página chamam `lib/projects.ts` e `lib/log-entries.ts` para ler dados de projeto/sessão diretamente do sistema de arquivos (sem camada de API para leituras).
|
|
290
|
+
- A página de Políticas usa Server Actions para todas as mutações (alternar, atualizar parâmetros, instalar/remover).
|
|
291
|
+
- O visualizador de sessão analisa o formato de transcrição JSONL do Claude e renderiza uma linha do tempo de mensagens e chamadas de ferramentas.
|
|
292
|
+
|
|
293
|
+
**Principais decisões de design:**
|
|
294
|
+
|
|
295
|
+
- Sem banco de dados - todo estado persistente está em arquivos simples (`~/.failproofai/`, `~/.claude/projects/`).
|
|
296
|
+
- Server Actions para mutações - sem necessidade de API REST para operações CRUD.
|
|
297
|
+
- React Server Components para páginas de leitura - carregamento inicial mais rápido, sem bundle no cliente para busca de dados.
|
|
298
|
+
- Client components apenas onde interatividade é necessária (alternância de políticas, busca de atividade, visualizador de log).
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## Estrutura de arquivos
|
|
303
|
+
|
|
304
|
+
```text
|
|
305
|
+
failproofai/
|
|
306
|
+
├── bin/
|
|
307
|
+
│ └── failproofai.mjs # Roteador CLI (hook / dashboard / install / etc.)
|
|
308
|
+
├── src/hooks/
|
|
309
|
+
│ ├── handler.ts # Pipeline de eventos de hook
|
|
310
|
+
│ ├── builtin-policies.ts # 26 definições de políticas
|
|
311
|
+
│ ├── policy-evaluator.ts # Motor de execução de políticas
|
|
312
|
+
│ ├── policy-registry.ts # Registro e busca de políticas
|
|
313
|
+
│ ├── policy-types.ts # Interfaces TypeScript
|
|
314
|
+
│ ├── hooks-config.ts # Carregamento de configuração multi-escopo
|
|
315
|
+
│ ├── custom-hooks-registry.ts # Registro de hooks baseado em globalThis
|
|
316
|
+
│ ├── custom-hooks-loader.ts # Carregador ESM para hooks JS do usuário
|
|
317
|
+
│ ├── manager.ts # Operações de instalação / remoção / listagem
|
|
318
|
+
│ ├── install-prompt.ts # Prompt interativo de seleção de políticas
|
|
319
|
+
│ ├── hook-logger.ts # Registro em hook.log
|
|
320
|
+
│ ├── hook-activity-store.ts # Persiste atividade em hook-activity.jsonl
|
|
321
|
+
│ └── llm-client.ts # Cliente de API LLM (para políticas com IA)
|
|
322
|
+
├── app/ # Dashboard Next.js (páginas + server actions)
|
|
323
|
+
├── lib/ # Utilitários compartilhados
|
|
324
|
+
│ ├── projects.ts # Enumera projetos Claude do sistema de arquivos
|
|
325
|
+
│ ├── log-entries.ts # Analisa o formato JSONL de transcrição do Claude
|
|
326
|
+
│ ├── paths.ts # Resolve caminhos do sistema
|
|
327
|
+
│ └── ...
|
|
328
|
+
├── components/ # Componentes React de UI compartilhados
|
|
329
|
+
├── contexts/ # Provedores de contexto React (tema, atualização automática, telemetria)
|
|
330
|
+
├── examples/ # Exemplos de arquivos de hooks personalizados
|
|
331
|
+
└── __tests__/ # Testes unitários e E2E
|
|
332
|
+
```
|