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,68 @@
|
|
|
1
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
2
|
+
import { DO_NOT_TRANSLATE } from "./config";
|
|
3
|
+
|
|
4
|
+
let client: Anthropic | null = null;
|
|
5
|
+
|
|
6
|
+
function getClient(): Anthropic {
|
|
7
|
+
if (!client) {
|
|
8
|
+
client = new Anthropic();
|
|
9
|
+
}
|
|
10
|
+
return client;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const SYSTEM_PROMPT = `You are a professional technical documentation translator. Your task is to translate documentation content precisely and naturally into the target language.
|
|
14
|
+
|
|
15
|
+
## Rules
|
|
16
|
+
|
|
17
|
+
1. **Preserve all code blocks exactly as-is** — never translate content inside backtick-fenced code blocks (\`\`\`...\`\`\`) or inline code (\`...\`).
|
|
18
|
+
2. **Preserve MDX component syntax** — tags like <Card>, <CardGroup>, <CodeGroup>, <Steps>, <Step>, <Note>, <Tip>, <Tabs>, <Tab>, <Warning> must remain unchanged. Their attribute names (title, icon, href, cols) must remain in English. Only translate the text content of the \`title\` attribute and the text body between tags.
|
|
19
|
+
3. **Preserve YAML frontmatter keys** — only translate the string values of \`title\` and \`description\`. Keep the \`icon\` value unchanged.
|
|
20
|
+
4. **Preserve all URLs and paths** — never modify href values, image paths, or links.
|
|
21
|
+
5. **Preserve Markdown structure** — headers (#, ##), lists (-, *), tables (|), bold (**), italic (*), links ([text](url)) must keep their Markdown formatting.
|
|
22
|
+
6. **Preserve badge/shield URLs** — any [](url) pattern must remain completely unchanged.
|
|
23
|
+
|
|
24
|
+
## Do-not-translate list
|
|
25
|
+
|
|
26
|
+
The following terms must NEVER be translated — keep them exactly as-is in the output:
|
|
27
|
+
${DO_NOT_TRANSLATE.map((t) => `- ${t}`).join("\n")}
|
|
28
|
+
|
|
29
|
+
## Translation quality
|
|
30
|
+
|
|
31
|
+
- Use natural, idiomatic phrasing in the target language — do NOT produce word-for-word literal translations.
|
|
32
|
+
- Technical documentation should read as if originally written in the target language by a native-speaking developer.
|
|
33
|
+
- Maintain the same level of formality and tone as the source.
|
|
34
|
+
- For languages that distinguish formal/informal registers, use a professional but approachable tone.
|
|
35
|
+
|
|
36
|
+
## Output
|
|
37
|
+
|
|
38
|
+
Return ONLY the translated content. Do not add explanations, notes, or commentary.`;
|
|
39
|
+
|
|
40
|
+
export async function translateContent(
|
|
41
|
+
content: string,
|
|
42
|
+
targetLang: string,
|
|
43
|
+
targetLangName: string,
|
|
44
|
+
model: string = "claude-sonnet-4-6",
|
|
45
|
+
): Promise<{ translated: string; inputTokens: number; outputTokens: number }> {
|
|
46
|
+
const anthropic = getClient();
|
|
47
|
+
|
|
48
|
+
const response = await anthropic.messages.create({
|
|
49
|
+
model,
|
|
50
|
+
max_tokens: 16384,
|
|
51
|
+
system: [{ type: "text", text: SYSTEM_PROMPT, cache_control: { type: "ephemeral" } }],
|
|
52
|
+
messages: [
|
|
53
|
+
{
|
|
54
|
+
role: "user",
|
|
55
|
+
content: `Translate the following documentation content into ${targetLangName} (${targetLang}).\n\n---\n\n${content}`,
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const translated =
|
|
61
|
+
response.content[0].type === "text" ? response.content[0].text : "";
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
translated,
|
|
65
|
+
inputTokens: response.usage.input_tokens,
|
|
66
|
+
outputTokens: response.usage.output_tokens,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export interface LanguageConfig {
|
|
2
|
+
code: string;
|
|
3
|
+
name: string;
|
|
4
|
+
nativeName: string;
|
|
5
|
+
tier: 1 | 2 | 3;
|
|
6
|
+
rtl?: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface CacheEntry {
|
|
10
|
+
sourceHash: string;
|
|
11
|
+
targetLang: string;
|
|
12
|
+
translatedAt: string;
|
|
13
|
+
inputTokens: number;
|
|
14
|
+
outputTokens: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface TranslationCache {
|
|
18
|
+
sourceHash: string;
|
|
19
|
+
lastUpdated: string;
|
|
20
|
+
translations: Record<string, CacheEntry>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface TranslateOptions {
|
|
24
|
+
languages: string[];
|
|
25
|
+
tier?: number;
|
|
26
|
+
pagesFilter?: string[];
|
|
27
|
+
readmeOnly?: boolean;
|
|
28
|
+
docsOnly?: boolean;
|
|
29
|
+
dryRun?: boolean;
|
|
30
|
+
force?: boolean;
|
|
31
|
+
updateNav?: boolean;
|
|
32
|
+
validate?: boolean;
|
|
33
|
+
model?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface TranslationResult {
|
|
37
|
+
lang: string;
|
|
38
|
+
sourcePath: string;
|
|
39
|
+
outputPath: string;
|
|
40
|
+
inputTokens: number;
|
|
41
|
+
outputTokens: number;
|
|
42
|
+
cached: boolean;
|
|
43
|
+
}
|
|
@@ -9,7 +9,7 @@ const currentPort = parseInt(process.env.PORT, 10) || 3000
|
|
|
9
9
|
const hostname = process.env.HOSTNAME || '0.0.0.0'
|
|
10
10
|
|
|
11
11
|
let keepAliveTimeout = parseInt(process.env.KEEP_ALIVE_TIMEOUT, 10)
|
|
12
|
-
const nextConfig = {"env":{"NEXT_PUBLIC_APP_VERSION":"0.0.2-beta.
|
|
12
|
+
const nextConfig = {"env":{"NEXT_PUBLIC_APP_VERSION":"0.0.2-beta.9"},"typescript":{"ignoreBuildErrors":false},"typedRoutes":false,"distDir":"./.next","cleanDistDir":true,"assetPrefix":"","cacheMaxMemorySize":52428800,"configOrigin":"next.config.ts","useFileSystemPublicRoutes":true,"generateEtags":true,"pageExtensions":["tsx","ts","jsx","js"],"poweredByHeader":true,"compress":true,"images":{"deviceSizes":[640,750,828,1080,1200,1920,2048,3840],"imageSizes":[32,48,64,96,128,256,384],"path":"/_next/image","loader":"default","loaderFile":"","domains":[],"disableStaticImages":false,"minimumCacheTTL":14400,"formats":["image/webp"],"maximumRedirects":3,"maximumResponseBody":50000000,"dangerouslyAllowLocalIP":false,"dangerouslyAllowSVG":false,"contentSecurityPolicy":"script-src 'none'; frame-src 'none'; sandbox;","contentDispositionType":"attachment","localPatterns":[{"pathname":"**","search":""}],"remotePatterns":[],"qualities":[75],"unoptimized":true,"customCacheHandler":false},"devIndicators":{"position":"bottom-left"},"onDemandEntries":{"maxInactiveAge":60000,"pagesBufferLength":5},"basePath":"","sassOptions":{},"trailingSlash":false,"i18n":null,"productionBrowserSourceMaps":false,"excludeDefaultMomentLocales":true,"reactProductionProfiling":false,"reactStrictMode":null,"reactMaxHeadersLength":6000,"httpAgentOptions":{"keepAlive":true},"logging":{"serverFunctions":true,"browserToTerminal":"warn"},"compiler":{},"expireTime":31536000,"staticPageGenerationTimeout":60,"output":"standalone","modularizeImports":{"@mui/icons-material":{"transform":"@mui/icons-material/{{member}}"},"lodash":{"transform":"lodash/{{member}}"}},"outputFileTracingRoot":"/home/runner/work/failproofai/failproofai","cacheComponents":false,"cacheLife":{"default":{"stale":300,"revalidate":900,"expire":4294967294},"seconds":{"stale":30,"revalidate":1,"expire":60},"minutes":{"stale":300,"revalidate":60,"expire":3600},"hours":{"stale":300,"revalidate":3600,"expire":86400},"days":{"stale":300,"revalidate":86400,"expire":604800},"weeks":{"stale":300,"revalidate":604800,"expire":2592000},"max":{"stale":300,"revalidate":2592000,"expire":31536000}},"cacheHandlers":{},"experimental":{"appNewScrollHandler":false,"useSkewCookie":false,"cssChunking":true,"multiZoneDraftMode":false,"appNavFailHandling":false,"prerenderEarlyExit":true,"serverMinification":true,"linkNoTouchStart":false,"caseSensitiveRoutes":false,"cachedNavigations":false,"partialFallbacks":false,"dynamicOnHover":false,"varyParams":false,"prefetchInlining":false,"preloadEntriesOnStart":true,"clientRouterFilter":true,"clientRouterFilterRedirects":false,"fetchCacheKeyPrefix":"","proxyPrefetch":"flexible","optimisticClientCache":true,"manualClientBasePath":false,"cpus":3,"memoryBasedWorkersCount":false,"imgOptConcurrency":null,"imgOptTimeoutInSeconds":7,"imgOptMaxInputPixels":268402689,"imgOptSequentialRead":null,"imgOptSkipMetadata":null,"isrFlushToDisk":true,"workerThreads":false,"optimizeCss":false,"nextScriptWorkers":false,"scrollRestoration":false,"externalDir":false,"disableOptimizedLoading":false,"gzipSize":true,"craCompat":false,"esmExternals":true,"fullySpecified":false,"swcTraceProfiling":false,"forceSwcTransforms":false,"largePageDataBytes":128000,"typedEnv":false,"parallelServerCompiles":false,"parallelServerBuildTraces":false,"ppr":false,"authInterrupts":false,"webpackMemoryOptimizations":false,"optimizeServerReact":true,"strictRouteTypes":false,"viewTransition":false,"removeUncaughtErrorAndRejectionListeners":false,"validateRSCRequestHeaders":false,"staleTimes":{"dynamic":0,"static":300},"reactDebugChannel":true,"serverComponentsHmrCache":true,"staticGenerationMaxConcurrency":8,"staticGenerationMinPagesPerWorker":25,"transitionIndicator":false,"gestureTransition":false,"inlineCss":false,"useCache":false,"globalNotFound":false,"browserDebugInfoInTerminal":"warn","lockDistDir":true,"proxyClientMaxBodySize":10485760,"hideLogsAfterAbort":false,"mcpServer":true,"turbopackFileSystemCacheForDev":true,"turbopackFileSystemCacheForBuild":false,"turbopackInferModuleSideEffects":true,"turbopackPluginRuntimeStrategy":"childProcesses","optimizePackageImports":["lucide-react","date-fns","lodash-es","ramda","antd","react-bootstrap","ahooks","@ant-design/icons","@headlessui/react","@headlessui-float/react","@heroicons/react/20/solid","@heroicons/react/24/solid","@heroicons/react/24/outline","@visx/visx","@tremor/react","rxjs","@mui/material","@mui/icons-material","recharts","react-use","effect","@effect/schema","@effect/platform","@effect/platform-node","@effect/platform-browser","@effect/platform-bun","@effect/sql","@effect/sql-mssql","@effect/sql-mysql2","@effect/sql-pg","@effect/sql-sqlite-node","@effect/sql-sqlite-bun","@effect/sql-sqlite-wasm","@effect/sql-sqlite-react-native","@effect/rpc","@effect/rpc-http","@effect/typeclass","@effect/experimental","@effect/opentelemetry","@material-ui/core","@material-ui/icons","@tabler/icons-react","mui-core","react-icons/ai","react-icons/bi","react-icons/bs","react-icons/cg","react-icons/ci","react-icons/di","react-icons/fa","react-icons/fa6","react-icons/fc","react-icons/fi","react-icons/gi","react-icons/go","react-icons/gr","react-icons/hi","react-icons/hi2","react-icons/im","react-icons/io","react-icons/io5","react-icons/lia","react-icons/lib","react-icons/lu","react-icons/md","react-icons/pi","react-icons/ri","react-icons/rx","react-icons/si","react-icons/sl","react-icons/tb","react-icons/tfi","react-icons/ti","react-icons/vsc","react-icons/wi"],"trustHostHeader":false,"isExperimentalCompile":false},"htmlLimitedBots":"[\\w-]+-Google|Google-[\\w-]+|Chrome-Lighthouse|Slurp|DuckDuckBot|baiduspider|yandex|sogou|bitlybot|tumblr|vkShare|quora link preview|redditbot|ia_archiver|Bingbot|BingPreview|applebot|facebookexternalhit|facebookcatalog|Twitterbot|LinkedInBot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview|Yeti|googleweblight","bundlePagesRouterDependencies":false,"configFileName":"next.config.ts","turbopack":{"root":"/home/runner/work/failproofai/failproofai"},"distDirRoot":".next"}
|
|
13
13
|
|
|
14
14
|
process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(nextConfig)
|
|
15
15
|
|
|
@@ -116,7 +116,7 @@ export interface LoadAllResult {
|
|
|
116
116
|
* 3. User convention: ~/.failproofai/policies/*policies.{js,mjs,ts} (alphabetical)
|
|
117
117
|
*
|
|
118
118
|
* Each file is loaded independently (fail-open per file).
|
|
119
|
-
* Convention hooks are tagged with
|
|
119
|
+
* Convention hooks are tagged with __conventionScope so the handler can build scoped prefixes.
|
|
120
120
|
*/
|
|
121
121
|
export async function loadAllCustomHooks(
|
|
122
122
|
customPoliciesPath: string | undefined,
|
|
@@ -181,16 +181,23 @@ export async function loadAllCustomHooks(
|
|
|
181
181
|
);
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
// Tag convention hooks so the handler can
|
|
185
|
-
//
|
|
186
|
-
//
|
|
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
|
+
}
|
|
187
193
|
const conventionHookRefs = new Set<CustomHook>();
|
|
188
194
|
for (const hook of allHooks.slice(hooksBeforeConvention)) {
|
|
189
195
|
conventionHookRefs.add(hook);
|
|
190
196
|
}
|
|
191
197
|
for (const hook of allHooks) {
|
|
192
198
|
if (conventionHookRefs.has(hook)) {
|
|
193
|
-
(hook as CustomHook & {
|
|
199
|
+
(hook as CustomHook & { __conventionScope?: string }).__conventionScope =
|
|
200
|
+
hookNameToScope.get(hook.name) ?? "project";
|
|
194
201
|
}
|
|
195
202
|
}
|
|
196
203
|
|
|
@@ -78,8 +78,9 @@ export async function handleHookEvent(eventType: string): Promise<number> {
|
|
|
78
78
|
|
|
79
79
|
for (const hook of customHooksList) {
|
|
80
80
|
const hookName = hook.name;
|
|
81
|
-
const
|
|
82
|
-
const
|
|
81
|
+
const conventionScope = (hook as CustomHook & { __conventionScope?: string }).__conventionScope;
|
|
82
|
+
const isConvention = !!conventionScope;
|
|
83
|
+
const prefix = isConvention ? `.failproofai-${conventionScope}` : "custom";
|
|
83
84
|
const fn: PolicyFunction = async (ctx): Promise<PolicyResult> => {
|
|
84
85
|
try {
|
|
85
86
|
const result = await Promise.race([
|
|
@@ -98,6 +99,7 @@ export async function handleHookEvent(eventType: string): Promise<number> {
|
|
|
98
99
|
error_type: isTimeout ? "timeout" : "exception",
|
|
99
100
|
event_type: eventType,
|
|
100
101
|
is_convention_policy: isConvention,
|
|
102
|
+
convention_scope: conventionScope ?? null,
|
|
101
103
|
});
|
|
102
104
|
return { decision: "allow" };
|
|
103
105
|
}
|
|
@@ -170,7 +172,10 @@ export async function handleHookEvent(eventType: string): Promise<number> {
|
|
|
170
172
|
if (result.decision === "deny" || result.decision === "instruct") {
|
|
171
173
|
try {
|
|
172
174
|
const isCustomHook = result.policyName?.startsWith("custom/") ?? false;
|
|
173
|
-
const isConventionPolicy = result.policyName?.startsWith("
|
|
175
|
+
const isConventionPolicy = result.policyName?.startsWith(".failproofai-") ?? false;
|
|
176
|
+
const conventionScope = isConventionPolicy
|
|
177
|
+
? result.policyName!.match(/^\.failproofai-(project|user)\//)?.[1] ?? null
|
|
178
|
+
: null;
|
|
174
179
|
const hasCustomParams =
|
|
175
180
|
!isCustomHook && !isConventionPolicy && !!(result.policyName && config.policyParams?.[result.policyName]);
|
|
176
181
|
const paramKeysOverridden = hasCustomParams
|
|
@@ -184,6 +189,7 @@ export async function handleHookEvent(eventType: string): Promise<number> {
|
|
|
184
189
|
decision: result.decision,
|
|
185
190
|
is_custom_hook: isCustomHook,
|
|
186
191
|
is_convention_policy: isConventionPolicy,
|
|
192
|
+
convention_scope: conventionScope,
|
|
187
193
|
has_custom_params: hasCustomParams,
|
|
188
194
|
param_keys_overridden: paramKeysOverridden,
|
|
189
195
|
});
|
|
@@ -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);
|
|
@@ -56,9 +56,8 @@ export async function evaluatePolicies(
|
|
|
56
56
|
session,
|
|
57
57
|
};
|
|
58
58
|
|
|
59
|
-
// Track
|
|
60
|
-
|
|
61
|
-
let instructReason: string | null = null;
|
|
59
|
+
// Track all instruct results (accumulated, does not short-circuit)
|
|
60
|
+
const instructEntries: Array<{ policyName: string; reason: string }> = [];
|
|
62
61
|
|
|
63
62
|
// Track informational messages from allow decisions (with policy attribution)
|
|
64
63
|
const allowEntries: Array<{ policyName: string; reason: string }> = [];
|
|
@@ -142,14 +141,14 @@ export async function evaluatePolicies(
|
|
|
142
141
|
};
|
|
143
142
|
}
|
|
144
143
|
|
|
145
|
-
// Accumulate
|
|
146
|
-
if (result.decision === "instruct"
|
|
147
|
-
|
|
148
|
-
instructReason = appendHint(
|
|
144
|
+
// Accumulate all instruct results (does not short-circuit — later policies can still deny)
|
|
145
|
+
if (result.decision === "instruct") {
|
|
146
|
+
const reason = appendHint(
|
|
149
147
|
result.reason ?? `Instruction from policy: ${policy.name}`,
|
|
150
148
|
config?.policyParams?.[policy.name]?.hint,
|
|
151
149
|
);
|
|
152
|
-
|
|
150
|
+
instructEntries.push({ policyName: policy.name, reason });
|
|
151
|
+
hookLogInfo(`instruct by "${policy.name}": ${reason}`);
|
|
153
152
|
}
|
|
154
153
|
|
|
155
154
|
// Accumulate informational messages from allow decisions
|
|
@@ -158,17 +157,21 @@ export async function evaluatePolicies(
|
|
|
158
157
|
}
|
|
159
158
|
}
|
|
160
159
|
|
|
161
|
-
// No deny — check if we accumulated
|
|
162
|
-
if (
|
|
160
|
+
// No deny — check if we accumulated any instructs
|
|
161
|
+
if (instructEntries.length > 0) {
|
|
162
|
+
const combined = instructEntries.map((e) => e.reason).join("\n");
|
|
163
|
+
const policyNames = instructEntries.map((e) => e.policyName);
|
|
164
|
+
|
|
163
165
|
if (eventType === "Stop") {
|
|
164
166
|
// Stop hook: exitCode 2 blocks Claude from stopping.
|
|
165
167
|
// Reason goes to stderr so Claude Code receives it as context.
|
|
166
168
|
return {
|
|
167
169
|
exitCode: 2,
|
|
168
170
|
stdout: "",
|
|
169
|
-
stderr:
|
|
170
|
-
policyName:
|
|
171
|
-
|
|
171
|
+
stderr: combined,
|
|
172
|
+
policyName: policyNames[0],
|
|
173
|
+
policyNames,
|
|
174
|
+
reason: combined,
|
|
172
175
|
decision: "instruct",
|
|
173
176
|
};
|
|
174
177
|
}
|
|
@@ -176,15 +179,16 @@ export async function evaluatePolicies(
|
|
|
176
179
|
const response = {
|
|
177
180
|
hookSpecificOutput: {
|
|
178
181
|
hookEventName: eventType,
|
|
179
|
-
additionalContext: `Instruction from failproofai: ${
|
|
182
|
+
additionalContext: `Instruction from failproofai: ${combined}`,
|
|
180
183
|
},
|
|
181
184
|
};
|
|
182
185
|
return {
|
|
183
186
|
exitCode: 0,
|
|
184
187
|
stdout: JSON.stringify(response),
|
|
185
188
|
stderr: "",
|
|
186
|
-
policyName:
|
|
187
|
-
|
|
189
|
+
policyName: policyNames[0],
|
|
190
|
+
policyNames,
|
|
191
|
+
reason: combined,
|
|
188
192
|
decision: "instruct",
|
|
189
193
|
};
|
|
190
194
|
}
|
package/README.md
CHANGED
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
[](https://github.com/exospherehost/failproofai/actions)
|
|
16
16
|
[](https://join.slack.com/t/failproofai/shared_invite/zt-3v63b7k5e-O3NBHmj8X6n9gZSGDx6ggQ)
|
|
17
17
|
|
|
18
|
+
**Translations**: [简体中文](docs/i18n/README.zh.md) | [日本語](docs/i18n/README.ja.md) | [한국어](docs/i18n/README.ko.md) | [Español](docs/i18n/README.es.md) | [Português](docs/i18n/README.pt-br.md) | [Deutsch](docs/i18n/README.de.md) | [Français](docs/i18n/README.fr.md) | [Русский](docs/i18n/README.ru.md) | [हिन्दी](docs/i18n/README.hi.md) | [Türkçe](docs/i18n/README.tr.md) | [Tiếng Việt](docs/i18n/README.vi.md) | [Italiano](docs/i18n/README.it.md) | [العربية](docs/i18n/README.ar.md) | [עברית](docs/i18n/README.he.md)
|
|
19
|
+
|
|
18
20
|
The easiest way to manage policies that keep your AI agents reliable, on-task, and running autonomously - for **Claude Code** & the **Agents SDK**.
|
|
19
21
|
|
|
20
22
|
- **30 Built-in Policies** - Catch common agent failure modes out of the box. Block destructive commands, prevent secret leakage, keep agents inside project boundaries, detect loops, and more.
|
|
@@ -274,6 +276,16 @@ docker run --rm -p 3000:3000 -v $(pwd)/docs:/app/docs failproofai-docs
|
|
|
274
276
|
|
|
275
277
|
---
|
|
276
278
|
|
|
279
|
+
## Note for failproofai contributors
|
|
280
|
+
|
|
281
|
+
This repo's `.claude/settings.json` uses `bun ./bin/failproofai.mjs --hook <EventType>` instead of the standard `npx -y failproofai` command. This is because running `npx -y failproofai` inside the failproofai project itself creates a self-referencing conflict.
|
|
282
|
+
|
|
283
|
+
For all other repos, the recommended approach is `npx -y failproofai`, installed via:
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
failproofai policies --install --scope project
|
|
287
|
+
```
|
|
288
|
+
|
|
277
289
|
## Contributing
|
|
278
290
|
|
|
279
291
|
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
@@ -283,3 +295,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
|
283
295
|
## License
|
|
284
296
|
|
|
285
297
|
See [LICENSE](LICENSE).
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
Built and Maintained by **ExosphereHost: Reliability Research Lab for Your Agents**. We help enterprises and startups improve the reliability of their AI agents through our own agents, software, and expertise. Learn more at [exosphere.host](https://exosphere.host).
|
package/dist/cli.mjs
CHANGED
|
@@ -1402,8 +1402,7 @@ async function evaluatePolicies(eventType, payload, session, config) {
|
|
|
1402
1402
|
toolInput,
|
|
1403
1403
|
session
|
|
1404
1404
|
};
|
|
1405
|
-
|
|
1406
|
-
let instructReason = null;
|
|
1405
|
+
const instructEntries = [];
|
|
1407
1406
|
const allowEntries = [];
|
|
1408
1407
|
for (const policy of policies) {
|
|
1409
1408
|
const schema = POLICY_PARAMS_MAP.get(policy.name);
|
|
@@ -1471,38 +1470,43 @@ async function evaluatePolicies(eventType, payload, session, config) {
|
|
|
1471
1470
|
decision: "deny"
|
|
1472
1471
|
};
|
|
1473
1472
|
}
|
|
1474
|
-
if (result.decision === "instruct"
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
hookLogInfo(`instruct by "${policy.name}": ${
|
|
1473
|
+
if (result.decision === "instruct") {
|
|
1474
|
+
const reason = appendHint(result.reason ?? `Instruction from policy: ${policy.name}`, config?.policyParams?.[policy.name]?.hint);
|
|
1475
|
+
instructEntries.push({ policyName: policy.name, reason });
|
|
1476
|
+
hookLogInfo(`instruct by "${policy.name}": ${reason}`);
|
|
1478
1477
|
}
|
|
1479
1478
|
if (result.decision === "allow" && result.reason) {
|
|
1480
1479
|
allowEntries.push({ policyName: policy.name, reason: result.reason });
|
|
1481
1480
|
}
|
|
1482
1481
|
}
|
|
1483
|
-
if (
|
|
1482
|
+
if (instructEntries.length > 0) {
|
|
1483
|
+
const combined = instructEntries.map((e) => e.reason).join(`
|
|
1484
|
+
`);
|
|
1485
|
+
const policyNames = instructEntries.map((e) => e.policyName);
|
|
1484
1486
|
if (eventType === "Stop") {
|
|
1485
1487
|
return {
|
|
1486
1488
|
exitCode: 2,
|
|
1487
1489
|
stdout: "",
|
|
1488
|
-
stderr:
|
|
1489
|
-
policyName:
|
|
1490
|
-
|
|
1490
|
+
stderr: combined,
|
|
1491
|
+
policyName: policyNames[0],
|
|
1492
|
+
policyNames,
|
|
1493
|
+
reason: combined,
|
|
1491
1494
|
decision: "instruct"
|
|
1492
1495
|
};
|
|
1493
1496
|
}
|
|
1494
1497
|
const response = {
|
|
1495
1498
|
hookSpecificOutput: {
|
|
1496
1499
|
hookEventName: eventType,
|
|
1497
|
-
additionalContext: `Instruction from failproofai: ${
|
|
1500
|
+
additionalContext: `Instruction from failproofai: ${combined}`
|
|
1498
1501
|
}
|
|
1499
1502
|
};
|
|
1500
1503
|
return {
|
|
1501
1504
|
exitCode: 0,
|
|
1502
1505
|
stdout: JSON.stringify(response),
|
|
1503
1506
|
stderr: "",
|
|
1504
|
-
policyName:
|
|
1505
|
-
|
|
1507
|
+
policyName: policyNames[0],
|
|
1508
|
+
policyNames,
|
|
1509
|
+
reason: combined,
|
|
1506
1510
|
decision: "instruct"
|
|
1507
1511
|
};
|
|
1508
1512
|
}
|
|
@@ -1762,13 +1766,19 @@ async function loadAllCustomHooks(customPoliciesPath, opts) {
|
|
|
1762
1766
|
if (projectFiles.length > 0 || userFiles.length > 0) {
|
|
1763
1767
|
hookLogInfo(`convention policies: ${projectFiles.length} project file(s), ${userFiles.length} user file(s), ${conventionCount} hook(s)`);
|
|
1764
1768
|
}
|
|
1769
|
+
const hookNameToScope = new Map;
|
|
1770
|
+
for (const source of conventionSources) {
|
|
1771
|
+
for (const name of source.hookNames) {
|
|
1772
|
+
hookNameToScope.set(name, source.scope);
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1765
1775
|
const conventionHookRefs = new Set;
|
|
1766
1776
|
for (const hook of allHooks.slice(hooksBeforeConvention)) {
|
|
1767
1777
|
conventionHookRefs.add(hook);
|
|
1768
1778
|
}
|
|
1769
1779
|
for (const hook of allHooks) {
|
|
1770
1780
|
if (conventionHookRefs.has(hook)) {
|
|
1771
|
-
hook.
|
|
1781
|
+
hook.__conventionScope = hookNameToScope.get(hook.name) ?? "project";
|
|
1772
1782
|
}
|
|
1773
1783
|
}
|
|
1774
1784
|
return { hooks: allHooks, conventionSources };
|
|
@@ -1904,7 +1914,7 @@ var init_hook_activity_store = __esm(() => {
|
|
|
1904
1914
|
});
|
|
1905
1915
|
|
|
1906
1916
|
// package.json
|
|
1907
|
-
var version2 = "0.0.2-beta.
|
|
1917
|
+
var version2 = "0.0.2-beta.9";
|
|
1908
1918
|
var init_package = () => {};
|
|
1909
1919
|
|
|
1910
1920
|
// src/posthog-key.ts
|
|
@@ -2071,8 +2081,9 @@ async function handleHookEvent(eventType) {
|
|
|
2071
2081
|
const conventionHookNames = new Set(loadResult.conventionSources.flatMap((s) => s.hookNames));
|
|
2072
2082
|
for (const hook of customHooksList) {
|
|
2073
2083
|
const hookName = hook.name;
|
|
2074
|
-
const
|
|
2075
|
-
const
|
|
2084
|
+
const conventionScope = hook.__conventionScope;
|
|
2085
|
+
const isConvention = !!conventionScope;
|
|
2086
|
+
const prefix = isConvention ? `.failproofai-${conventionScope}` : "custom";
|
|
2076
2087
|
const fn = async (ctx) => {
|
|
2077
2088
|
try {
|
|
2078
2089
|
const result2 = await Promise.race([
|
|
@@ -2088,7 +2099,8 @@ async function handleHookEvent(eventType) {
|
|
|
2088
2099
|
hook_name: hookName,
|
|
2089
2100
|
error_type: isTimeout ? "timeout" : "exception",
|
|
2090
2101
|
event_type: eventType,
|
|
2091
|
-
is_convention_policy: isConvention
|
|
2102
|
+
is_convention_policy: isConvention,
|
|
2103
|
+
convention_scope: conventionScope ?? null
|
|
2092
2104
|
});
|
|
2093
2105
|
return { decision: "allow" };
|
|
2094
2106
|
}
|
|
@@ -2143,7 +2155,8 @@ async function handleHookEvent(eventType) {
|
|
|
2143
2155
|
if (result.decision === "deny" || result.decision === "instruct") {
|
|
2144
2156
|
try {
|
|
2145
2157
|
const isCustomHook = result.policyName?.startsWith("custom/") ?? false;
|
|
2146
|
-
const isConventionPolicy = result.policyName?.startsWith("
|
|
2158
|
+
const isConventionPolicy = result.policyName?.startsWith(".failproofai-") ?? false;
|
|
2159
|
+
const conventionScope = isConventionPolicy ? result.policyName.match(/^\.failproofai-(project|user)\//)?.[1] ?? null : null;
|
|
2147
2160
|
const hasCustomParams = !isCustomHook && !isConventionPolicy && !!(result.policyName && config.policyParams?.[result.policyName]);
|
|
2148
2161
|
const paramKeysOverridden = hasCustomParams ? Object.keys(config.policyParams[result.policyName]) : [];
|
|
2149
2162
|
const distinctId = getInstanceId();
|
|
@@ -2154,6 +2167,7 @@ async function handleHookEvent(eventType) {
|
|
|
2154
2167
|
decision: result.decision,
|
|
2155
2168
|
is_custom_hook: isCustomHook,
|
|
2156
2169
|
is_convention_policy: isConventionPolicy,
|
|
2170
|
+
convention_scope: conventionScope,
|
|
2157
2171
|
has_custom_params: hasCustomParams,
|
|
2158
2172
|
param_keys_overridden: paramKeysOverridden
|
|
2159
2173
|
});
|
|
@@ -2667,7 +2681,7 @@ Enabled ${selectedPolicies.length} policy(ies): ${selectedPolicies.join(", ")}`)
|
|
|
2667
2681
|
settings.hooks = {};
|
|
2668
2682
|
}
|
|
2669
2683
|
for (const eventType of HOOK_EVENT_TYPES) {
|
|
2670
|
-
const command = `"${binaryPath}" --hook ${eventType}`;
|
|
2684
|
+
const command = scope === "project" ? `npx -y failproofai --hook ${eventType}` : `"${binaryPath}" --hook ${eventType}`;
|
|
2671
2685
|
const hookEntry = {
|
|
2672
2686
|
type: "command",
|
|
2673
2687
|
command,
|
|
@@ -2712,12 +2726,19 @@ Enabled ${selectedPolicies.length} policy(ies): ${selectedPolicies.join(", ")}`)
|
|
|
2712
2726
|
hostname_hash: hashToId(hostname()),
|
|
2713
2727
|
has_custom_hooks_path: !!configToWrite.customPoliciesPath,
|
|
2714
2728
|
has_policy_params: !!(configToWrite.policyParams && Object.keys(configToWrite.policyParams).length > 0),
|
|
2715
|
-
param_policy_names: configToWrite.policyParams ? Object.keys(configToWrite.policyParams) : []
|
|
2729
|
+
param_policy_names: configToWrite.policyParams ? Object.keys(configToWrite.policyParams) : [],
|
|
2730
|
+
command_format: scope === "project" ? "npx" : "absolute"
|
|
2716
2731
|
});
|
|
2717
2732
|
} catch {}
|
|
2718
2733
|
console.log(`Failproof AI hooks installed for all ${HOOK_EVENT_TYPES.length} event types (scope: ${scope}).`);
|
|
2719
2734
|
console.log(`Settings: ${settingsPath}`);
|
|
2720
|
-
|
|
2735
|
+
if (scope === "project") {
|
|
2736
|
+
console.log(`Command: npx -y failproofai`);
|
|
2737
|
+
console.log(`
|
|
2738
|
+
This file can be committed to git — no machine-specific paths.`);
|
|
2739
|
+
} else {
|
|
2740
|
+
console.log(`Binary: ${binaryPath}`);
|
|
2741
|
+
}
|
|
2721
2742
|
const otherScopes = deduplicateScopes(HOOK_SCOPES, cwd).filter((s) => s !== scope);
|
|
2722
2743
|
const duplicates = otherScopes.filter((s) => hooksInstalledInSettings(s, cwd));
|
|
2723
2744
|
if (duplicates.length > 0) {
|
|
@@ -3185,7 +3206,7 @@ import { realpathSync as realpathSync2 } from "fs";
|
|
|
3185
3206
|
import { dirname as dirname5, resolve as resolve8 } from "path";
|
|
3186
3207
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3187
3208
|
// package.json
|
|
3188
|
-
var version = "0.0.2-beta.
|
|
3209
|
+
var version = "0.0.2-beta.9";
|
|
3189
3210
|
|
|
3190
3211
|
// bin/failproofai.mjs
|
|
3191
3212
|
if (!process.env.FAILPROOFAI_PACKAGE_ROOT) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "failproofai",
|
|
3
|
-
"version": "0.0.2-beta.
|
|
3
|
+
"version": "0.0.2-beta.9",
|
|
4
4
|
"description": "The easiest way to manage policies that keep your AI agents reliable, on-task, and running autonomously — for Claude Code & the Agents SDK",
|
|
5
5
|
"bin": {
|
|
6
6
|
"failproofai": "./dist/cli.mjs"
|
|
@@ -32,7 +32,12 @@
|
|
|
32
32
|
"preuninstall": "node scripts/preuninstall.mjs",
|
|
33
33
|
"prepare": "bun run build",
|
|
34
34
|
"test:e2e": "vitest run --config vitest.config.e2e.mts",
|
|
35
|
-
"test:e2e:watch": "vitest --config vitest.config.e2e.mts"
|
|
35
|
+
"test:e2e:watch": "vitest --config vitest.config.e2e.mts",
|
|
36
|
+
"translate": "bun scripts/translate-docs/cli.ts",
|
|
37
|
+
"translate:readme": "bun scripts/translate-docs/cli.ts --readme-only",
|
|
38
|
+
"translate:docs": "bun scripts/translate-docs/cli.ts --docs-only",
|
|
39
|
+
"translate:dry-run": "bun scripts/translate-docs/cli.ts --dry-run",
|
|
40
|
+
"translate:validate": "bun scripts/translate-docs/cli.ts --validate"
|
|
36
41
|
},
|
|
37
42
|
"keywords": [
|
|
38
43
|
"claude",
|
|
@@ -85,6 +90,7 @@
|
|
|
85
90
|
"tailwind-merge": "^3.4.0",
|
|
86
91
|
"tailwindcss": "^4.1.18",
|
|
87
92
|
"typescript": "^6.0.2",
|
|
93
|
+
"@anthropic-ai/sdk": "^0.39.0",
|
|
88
94
|
"vitest": "^4.0.18"
|
|
89
95
|
},
|
|
90
96
|
"dependencies": {
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import type { CacheEntry, TranslationCache } from "./types";
|
|
6
|
+
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const CACHE_FILE = join(__dirname, ".translation-cache.json");
|
|
9
|
+
|
|
10
|
+
export function contentHash(content: string): string {
|
|
11
|
+
return createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function readCache(): TranslationCache {
|
|
15
|
+
if (!existsSync(CACHE_FILE)) {
|
|
16
|
+
return { sourceHash: "", lastUpdated: "", translations: {} };
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
return JSON.parse(readFileSync(CACHE_FILE, "utf-8"));
|
|
20
|
+
} catch {
|
|
21
|
+
return { sourceHash: "", lastUpdated: "", translations: {} };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function writeCache(cache: TranslationCache): void {
|
|
26
|
+
cache.lastUpdated = new Date().toISOString();
|
|
27
|
+
writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function getCacheKey(sourcePath: string, lang: string): string {
|
|
31
|
+
return `${sourcePath}::${lang}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function isCached(
|
|
35
|
+
cache: TranslationCache,
|
|
36
|
+
sourcePath: string,
|
|
37
|
+
lang: string,
|
|
38
|
+
sourceContent: string,
|
|
39
|
+
): boolean {
|
|
40
|
+
const key = getCacheKey(sourcePath, lang);
|
|
41
|
+
const entry = cache.translations[key];
|
|
42
|
+
if (!entry) return false;
|
|
43
|
+
return entry.sourceHash === contentHash(sourceContent);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function setCacheEntry(
|
|
47
|
+
cache: TranslationCache,
|
|
48
|
+
sourcePath: string,
|
|
49
|
+
lang: string,
|
|
50
|
+
sourceContent: string,
|
|
51
|
+
inputTokens: number,
|
|
52
|
+
outputTokens: number,
|
|
53
|
+
): void {
|
|
54
|
+
const key = getCacheKey(sourcePath, lang);
|
|
55
|
+
cache.translations[key] = {
|
|
56
|
+
sourceHash: contentHash(sourceContent),
|
|
57
|
+
targetLang: lang,
|
|
58
|
+
translatedAt: new Date().toISOString(),
|
|
59
|
+
inputTokens,
|
|
60
|
+
outputTokens,
|
|
61
|
+
};
|
|
62
|
+
}
|