failproofai 1.0.1 → 1.0.2-beta.1

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.
Files changed (390) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +3 -3
  3. package/.next/standalone/.next/prerender-manifest.json +6 -6
  4. package/.next/standalone/.next/required-server-files.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  6. package/.next/standalone/.next/server/app/_global-error/page.js +2 -2
  7. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  11. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
  12. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  13. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page.js +2 -2
  16. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  17. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  18. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  19. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  20. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  21. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -14
  22. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  23. package/.next/standalone/.next/server/app/api/audit/invite/route.js +3 -2
  24. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/audit/run/route.js +5 -4
  26. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/auth/login-request/route.js +2 -2
  29. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +4 -3
  31. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/api/auth/logout/route.js +4 -4
  33. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/api/auth/status/route.js +4 -4
  35. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  38. package/.next/standalone/.next/server/app/audit/page.js +2 -2
  39. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  41. package/.next/standalone/.next/server/app/index.html +1 -1
  42. package/.next/standalone/.next/server/app/index.rsc +15 -15
  43. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +14 -14
  44. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  45. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  46. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  47. package/.next/standalone/.next/server/app/page.js +2 -2
  48. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  49. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  50. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +66 -22
  51. package/.next/standalone/.next/server/app/policies/page.js +5 -4
  52. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  53. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  54. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  55. package/.next/standalone/.next/server/app/project/[name]/page.js +2 -2
  56. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  57. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  58. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  59. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  60. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +2 -2
  61. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  62. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  63. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  64. package/.next/standalone/.next/server/app/projects/page.js +2 -2
  65. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  66. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  67. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +4 -4
  68. package/.next/standalone/.next/server/app/settings/page.js +1 -1
  69. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  70. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  71. package/.next/standalone/.next/server/chunks/{[externals]__1qzqcio._.js → [externals]__0e32-7c._.js} +1 -1
  72. package/.next/standalone/.next/server/chunks/[externals]__1s462yl._.js +3 -0
  73. package/.next/standalone/.next/server/chunks/[root-of-the-server]__01eqny5._.js +3 -0
  74. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_0xu5z._.js +1 -1
  75. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1p8poxd._.js → [root-of-the-server]__0igxt32._.js} +2 -2
  76. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0neqlu-._.js +3 -0
  77. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +3 -0
  78. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t9oqnn._.js +3 -0
  79. package/.next/standalone/.next/server/chunks/_0bs-v8p._.js +3 -0
  80. package/.next/standalone/.next/server/chunks/_0tovk6q._.js +3 -0
  81. package/.next/standalone/.next/server/chunks/_0trp3yc._.js +3 -0
  82. package/.next/standalone/.next/server/chunks/_185gyk9._.js +3 -0
  83. package/.next/standalone/.next/server/chunks/_1ek68ln._.js +5 -6
  84. package/.next/standalone/.next/server/chunks/lib_telemetry-id_ts_1k8gj9o._.js +3 -0
  85. package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_09d5c79._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_04op_ou._.js} +1 -1
  86. package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_1d2g73o._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_0dr20uz._.js} +1 -1
  87. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  88. package/.next/standalone/.next/server/chunks/src_hooks_0xbw3bu._.js +12 -0
  89. package/.next/standalone/.next/server/chunks/src_hooks_fp-home_ts_09kv0bn._.js +1 -1
  90. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013jr2b._.js +4 -0
  91. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01wy8d-._.js +4 -0
  92. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02npjtd._.js +4 -0
  93. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0spkm68._.js → [root-of-the-server]__07gm3zl._.js} +21 -20
  94. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0da85px._.js +4 -0
  95. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ftmoxc._.js +4 -0
  96. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0l4748x._.js +3 -0
  97. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oa1lav._.js +1 -1
  98. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0p-5p8u._.js +4 -0
  99. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s740oi._.js +6 -0
  100. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__192nhvh._.js +5 -0
  101. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1p2otjt._.js +4 -0
  102. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  103. package/.next/standalone/.next/server/chunks/ssr/_0bwu160._.js +23 -0
  104. package/.next/standalone/.next/server/chunks/ssr/{_0u5zauv._.js → _0ns6k3a._.js} +1 -1
  105. package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.js +1 -1
  106. package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
  107. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +13 -13
  108. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  109. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
  110. package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +1 -1
  111. package/.next/standalone/.next/server/chunks/ssr/src_hooks_08o7bqo._.js +10 -0
  112. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +1 -1
  113. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
  114. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  115. package/.next/standalone/.next/server/middleware.js +1 -1
  116. package/.next/standalone/.next/server/pages/404.html +1 -1
  117. package/.next/standalone/.next/server/pages/500.html +1 -1
  118. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  119. package/.next/standalone/.next/server/server-reference-manifest.json +71 -27
  120. package/.next/standalone/.next/static/chunks/{3c808qrfcq0im.js → 01u1cf8js2yd6.js} +1 -1
  121. package/.next/standalone/.next/static/chunks/{0k5050ezjvv49.js → 0izgu7nqh2zp-.js} +1 -1
  122. package/.next/standalone/.next/static/chunks/0u4-org_e7zde.js +1 -0
  123. package/.next/standalone/.next/static/chunks/1mfzsja6ftim5.css +2 -0
  124. package/.next/standalone/.next/static/chunks/{2zpp1we2jv6tb.js → 1tynnrrh711lr.js} +1 -1
  125. package/.next/standalone/.next/static/chunks/{1ide1wl2f7zi1.js → 22rqvlr7p_1mv.js} +13 -13
  126. package/.next/standalone/.next/static/chunks/{31s1smp-g7gks.js → 2whxqyskpirbk.js} +1 -1
  127. package/.next/standalone/.next/static/chunks/31mwk8k0q3_3g.js +6 -0
  128. package/.next/standalone/.next/static/chunks/3ms6gxfm82t6s.js +1 -0
  129. package/.next/standalone/.next/static/chunks/{37fcpc36x9gpe.js → 3tbbs_d8xrvyp.js} +1 -1
  130. package/.next/standalone/.next/static/chunks/43nlc236oo898.js +1 -0
  131. package/.next/standalone/SECURITY.md +5 -4
  132. package/.next/standalone/app/actions/get-hooks-config.ts +108 -17
  133. package/.next/standalone/app/actions/pack-actions.ts +163 -0
  134. package/.next/standalone/app/audit/_components/run-progress.tsx +1 -1
  135. package/.next/standalone/app/audit/_components/share-templates.ts +13 -13
  136. package/.next/standalone/app/policies/hooks-client.tsx +320 -15
  137. package/.next/standalone/components/navbar.tsx +2 -28
  138. package/.next/standalone/components/reach-developers.tsx +8 -1
  139. package/.next/standalone/docs-old/agenteye/python-sdk-skill.mdx +1 -1
  140. package/.next/standalone/docs-old/agenteye/python-sdk.mdx +59 -35
  141. package/.next/standalone/docs-old/i18n/README.ar.md +1 -0
  142. package/.next/standalone/docs-old/i18n/README.de.md +1 -0
  143. package/.next/standalone/docs-old/i18n/README.es.md +1 -0
  144. package/.next/standalone/docs-old/i18n/README.fr.md +1 -0
  145. package/.next/standalone/docs-old/i18n/README.he.md +1 -0
  146. package/.next/standalone/docs-old/i18n/README.hi.md +1 -0
  147. package/.next/standalone/docs-old/i18n/README.it.md +1 -0
  148. package/.next/standalone/docs-old/i18n/README.ja.md +1 -0
  149. package/.next/standalone/docs-old/i18n/README.ko.md +1 -0
  150. package/.next/standalone/docs-old/i18n/README.pt-br.md +1 -0
  151. package/.next/standalone/docs-old/i18n/README.ru.md +1 -0
  152. package/.next/standalone/docs-old/i18n/README.tr.md +1 -0
  153. package/.next/standalone/docs-old/i18n/README.vi.md +1 -0
  154. package/.next/standalone/docs-old/i18n/README.zh.md +1 -0
  155. package/.next/standalone/fp-cloud-cli/CHANGELOG.md +431 -0
  156. package/.next/standalone/fp-cloud-cli/LICENSE +42 -0
  157. package/.next/standalone/fp-cloud-cli/MANIFEST.in +10 -0
  158. package/.next/standalone/fp-cloud-cli/README.md +259 -0
  159. package/.next/standalone/fp-cloud-cli/fp_cli/__init__.py +10 -0
  160. package/.next/standalone/fp-cloud-cli/fp_cli/__main__.py +4 -0
  161. package/.next/standalone/fp-cloud-cli/fp_cli/_click_compat.py +64 -0
  162. package/.next/standalone/fp-cloud-cli/fp_cli/_context.py +332 -0
  163. package/.next/standalone/fp-cloud-cli/fp_cli/_version.py +1 -0
  164. package/.next/standalone/fp-cloud-cli/fp_cli/analytics.py +432 -0
  165. package/.next/standalone/fp-cloud-cli/fp_cli/analytics_config.py +77 -0
  166. package/.next/standalone/fp-cloud-cli/fp_cli/analytics_registry.py +83 -0
  167. package/.next/standalone/fp-cloud-cli/fp_cli/app.py +492 -0
  168. package/.next/standalone/fp-cloud-cli/fp_cli/auth.py +160 -0
  169. package/.next/standalone/fp-cloud-cli/fp_cli/client.py +1694 -0
  170. package/.next/standalone/fp-cloud-cli/fp_cli/commands/__init__.py +0 -0
  171. package/.next/standalone/fp-cloud-cli/fp_cli/commands/_write.py +214 -0
  172. package/.next/standalone/fp-cloud-cli/fp_cli/commands/agent_cmds.py +407 -0
  173. package/.next/standalone/fp-cloud-cli/fp_cli/commands/alerts_cmds.py +445 -0
  174. package/.next/standalone/fp-cloud-cli/fp_cli/commands/audits_cmds.py +1054 -0
  175. package/.next/standalone/fp-cloud-cli/fp_cli/commands/auth_cmds.py +512 -0
  176. package/.next/standalone/fp-cloud-cli/fp_cli/commands/errors_cmds.py +190 -0
  177. package/.next/standalone/fp-cloud-cli/fp_cli/commands/evals_cmds.py +161 -0
  178. package/.next/standalone/fp-cloud-cli/fp_cli/commands/events_cmds.py +159 -0
  179. package/.next/standalone/fp-cloud-cli/fp_cli/commands/fleet_cmds.py +416 -0
  180. package/.next/standalone/fp-cloud-cli/fp_cli/commands/guardrails_cmds.py +148 -0
  181. package/.next/standalone/fp-cloud-cli/fp_cli/commands/incidents_cmds.py +472 -0
  182. package/.next/standalone/fp-cloud-cli/fp_cli/commands/keys_cmds.py +407 -0
  183. package/.next/standalone/fp-cloud-cli/fp_cli/commands/list_cmds.py +63 -0
  184. package/.next/standalone/fp-cloud-cli/fp_cli/commands/orgs_cmds.py +319 -0
  185. package/.next/standalone/fp-cloud-cli/fp_cli/commands/policies_cmds.py +499 -0
  186. package/.next/standalone/fp-cloud-cli/fp_cli/commands/queries_cmds.py +378 -0
  187. package/.next/standalone/fp-cloud-cli/fp_cli/commands/sessions_cmds.py +151 -0
  188. package/.next/standalone/fp-cloud-cli/fp_cli/commands/settings_cmds.py +150 -0
  189. package/.next/standalone/fp-cloud-cli/fp_cli/commands/usage_cmds.py +35 -0
  190. package/.next/standalone/fp-cloud-cli/fp_cli/commands/users_cmds.py +404 -0
  191. package/.next/standalone/fp-cloud-cli/fp_cli/config.py +330 -0
  192. package/.next/standalone/fp-cloud-cli/fp_cli/dates.py +78 -0
  193. package/.next/standalone/fp-cloud-cli/fp_cli/enforcement.py +345 -0
  194. package/.next/standalone/fp-cloud-cli/fp_cli/errors.py +98 -0
  195. package/.next/standalone/fp-cloud-cli/fp_cli/models.py +891 -0
  196. package/.next/standalone/fp-cloud-cli/fp_cli/orgs.py +30 -0
  197. package/.next/standalone/fp-cloud-cli/fp_cli/output.py +6593 -0
  198. package/.next/standalone/fp-cloud-cli/fp_cli/permissions.py +208 -0
  199. package/.next/standalone/fp-cloud-cli/fp_cli/policy_check.py +290 -0
  200. package/.next/standalone/fp-cloud-cli/fp_cli/py.typed +0 -0
  201. package/.next/standalone/fp-cloud-cli/fp_cli/select.py +322 -0
  202. package/.next/standalone/fp-cloud-cli/fp_cli/theme.py +53 -0
  203. package/.next/standalone/fp-cloud-cli/pyproject.toml +106 -0
  204. package/.next/standalone/fp-cloud-cli/skill/SKILL.md +302 -0
  205. package/.next/standalone/fp-cloud-cli/skill/agents/openai.yaml +8 -0
  206. package/.next/standalone/fp-cloud-cli/skill/references/commands.md +254 -0
  207. package/.next/standalone/fp-cloud-cli/tests/__init__.py +0 -0
  208. package/.next/standalone/fp-cloud-cli/tests/conftest.py +92 -0
  209. package/.next/standalone/fp-cloud-cli/tests/test_alerting.py +644 -0
  210. package/.next/standalone/fp-cloud-cli/tests/test_analytics.py +385 -0
  211. package/.next/standalone/fp-cloud-cli/tests/test_audits.py +950 -0
  212. package/.next/standalone/fp-cloud-cli/tests/test_auth.py +98 -0
  213. package/.next/standalone/fp-cloud-cli/tests/test_auth_mode.py +272 -0
  214. package/.next/standalone/fp-cloud-cli/tests/test_click_compat.py +118 -0
  215. package/.next/standalone/fp-cloud-cli/tests/test_client.py +299 -0
  216. package/.next/standalone/fp-cloud-cli/tests/test_commands.py +814 -0
  217. package/.next/standalone/fp-cloud-cli/tests/test_config.py +99 -0
  218. package/.next/standalone/fp-cloud-cli/tests/test_dashboards_agent.py +340 -0
  219. package/.next/standalone/fp-cloud-cli/tests/test_dates.py +76 -0
  220. package/.next/standalone/fp-cloud-cli/tests/test_enforcement_logic.py +481 -0
  221. package/.next/standalone/fp-cloud-cli/tests/test_facets.py +170 -0
  222. package/.next/standalone/fp-cloud-cli/tests/test_failproofai_home.py +722 -0
  223. package/.next/standalone/fp-cloud-cli/tests/test_fp_home_contract.py +198 -0
  224. package/.next/standalone/fp-cloud-cli/tests/test_hardening.py +186 -0
  225. package/.next/standalone/fp-cloud-cli/tests/test_help_table_coverage.py +127 -0
  226. package/.next/standalone/fp-cloud-cli/tests/test_keys_queries.py +496 -0
  227. package/.next/standalone/fp-cloud-cli/tests/test_list.py +59 -0
  228. package/.next/standalone/fp-cloud-cli/tests/test_multivalue.py +183 -0
  229. package/.next/standalone/fp-cloud-cli/tests/test_no_customer_identifiers.py +168 -0
  230. package/.next/standalone/fp-cloud-cli/tests/test_operator.py +492 -0
  231. package/.next/standalone/fp-cloud-cli/tests/test_orgs.py +692 -0
  232. package/.next/standalone/fp-cloud-cli/tests/test_output.py +1732 -0
  233. package/.next/standalone/fp-cloud-cli/tests/test_policy_check.py +191 -0
  234. package/.next/standalone/fp-cloud-cli/tests/test_readme_matches_reality.py +125 -0
  235. package/.next/standalone/fp-cloud-cli/tests/test_review_fixes.py +161 -0
  236. package/.next/standalone/fp-cloud-cli/tests/test_telemetry_completeness.py +90 -0
  237. package/.next/standalone/fp-cloud-cli/tests/test_usage.py +115 -0
  238. package/.next/standalone/fp-cloud-cli/tests/test_v1_origin_diagnostic.py +70 -0
  239. package/.next/standalone/fp-cloud-cli/tests/test_v1_routing.py +214 -0
  240. package/.next/standalone/fp-cloud-cli/tests/test_whoami.py +104 -0
  241. package/.next/standalone/fp-cloud-cli/uv.lock +552 -0
  242. package/.next/standalone/package.json +27 -21
  243. package/.next/standalone/sdk/python/CHANGELOG.md +70 -0
  244. package/.next/standalone/sdk/python/LICENSE +42 -0
  245. package/.next/standalone/sdk/python/MANIFEST.in +21 -0
  246. package/.next/standalone/sdk/python/README.md +466 -0
  247. package/.next/standalone/sdk/python/docs/README.md +249 -0
  248. package/.next/standalone/sdk/python/docs/_shared/README.md +43 -0
  249. package/.next/standalone/sdk/python/docs/_shared/__init__.py +195 -0
  250. package/.next/standalone/sdk/python/docs/crewai/README.md +328 -0
  251. package/.next/standalone/sdk/python/docs/crewai/examples/quickstart.py +61 -0
  252. package/.next/standalone/sdk/python/docs/crewai/examples/research_crew.py +92 -0
  253. package/.next/standalone/sdk/python/docs/langgraph/README.md +481 -0
  254. package/.next/standalone/sdk/python/docs/langgraph/examples/quickstart.py +51 -0
  255. package/.next/standalone/sdk/python/docs/langgraph/examples/research_agent.py +86 -0
  256. package/.next/standalone/sdk/python/docs/langgraph/examples/supervisor_handoff.py +83 -0
  257. package/.next/standalone/sdk/python/docs/llama_index/README.md +332 -0
  258. package/.next/standalone/sdk/python/docs/llama_index/examples/quickstart.py +62 -0
  259. package/.next/standalone/sdk/python/docs/llama_index/examples/research_agent.py +93 -0
  260. package/.next/standalone/sdk/python/docs/manual/README.md +491 -0
  261. package/.next/standalone/sdk/python/docs/manual/examples/quickstart.py +57 -0
  262. package/.next/standalone/sdk/python/docs/manual/examples/research_agent.py +133 -0
  263. package/.next/standalone/sdk/python/docs/pydantic_ai/README.md +323 -0
  264. package/.next/standalone/sdk/python/docs/pydantic_ai/examples/quickstart.py +48 -0
  265. package/.next/standalone/sdk/python/docs/pydantic_ai/examples/research_agent.py +94 -0
  266. package/.next/standalone/sdk/python/failproofai_sdk/__init__.py +131 -0
  267. package/.next/standalone/sdk/python/failproofai_sdk/_context.py +218 -0
  268. package/.next/standalone/sdk/python/failproofai_sdk/_environment.py +78 -0
  269. package/.next/standalone/sdk/python/failproofai_sdk/_events.py +752 -0
  270. package/.next/standalone/sdk/python/failproofai_sdk/_resolver.py +118 -0
  271. package/.next/standalone/sdk/python/failproofai_sdk/_runtime.py +21 -0
  272. package/.next/standalone/sdk/python/failproofai_sdk/_schema.py +317 -0
  273. package/.next/standalone/sdk/python/failproofai_sdk/_scopes.py +422 -0
  274. package/.next/standalone/sdk/python/failproofai_sdk/_version.py +1 -0
  275. package/.next/standalone/sdk/python/failproofai_sdk/_writer.py +750 -0
  276. package/.next/standalone/sdk/python/failproofai_sdk/integrations/__init__.py +274 -0
  277. package/.next/standalone/sdk/python/failproofai_sdk/integrations/_compat.py +247 -0
  278. package/.next/standalone/sdk/python/failproofai_sdk/integrations/_core.py +1076 -0
  279. package/.next/standalone/sdk/python/failproofai_sdk/integrations/crewai.py +1669 -0
  280. package/.next/standalone/sdk/python/failproofai_sdk/integrations/langchain.py +2151 -0
  281. package/.next/standalone/sdk/python/failproofai_sdk/integrations/llama_index.py +1588 -0
  282. package/.next/standalone/sdk/python/failproofai_sdk/integrations/pydantic_ai.py +977 -0
  283. package/.next/standalone/sdk/python/failproofai_sdk/py.typed +0 -0
  284. package/.next/standalone/sdk/python/pyproject.toml +92 -0
  285. package/.next/standalone/sdk/python/skill/SKILL.md +399 -0
  286. package/.next/standalone/sdk/python/skill/agents/openai.yaml +8 -0
  287. package/.next/standalone/sdk/python/skill/references/events.md +234 -0
  288. package/.next/standalone/sdk/python/skill/references/frameworks.md +314 -0
  289. package/.next/standalone/sdk/python/skill/references/install.md +100 -0
  290. package/.next/standalone/sdk/python/skill/references/integration.md +352 -0
  291. package/.next/standalone/sdk/python/tests/__init__.py +0 -0
  292. package/.next/standalone/sdk/python/tests/conftest.py +169 -0
  293. package/.next/standalone/sdk/python/tests/integrations/__init__.py +6 -0
  294. package/.next/standalone/sdk/python/tests/integrations/test_crewai.py +1299 -0
  295. package/.next/standalone/sdk/python/tests/integrations/test_langchain.py +2338 -0
  296. package/.next/standalone/sdk/python/tests/integrations/test_llama_index.py +1576 -0
  297. package/.next/standalone/sdk/python/tests/integrations/test_pydantic_ai.py +1102 -0
  298. package/.next/standalone/sdk/python/tests/test_context.py +410 -0
  299. package/.next/standalone/sdk/python/tests/test_docs.py +411 -0
  300. package/.next/standalone/sdk/python/tests/test_durability.py +1352 -0
  301. package/.next/standalone/sdk/python/tests/test_encoding.py +571 -0
  302. package/.next/standalone/sdk/python/tests/test_integrations.py +1127 -0
  303. package/.next/standalone/sdk/python/tests/test_no_customer_identifiers.py +214 -0
  304. package/.next/standalone/sdk/python/tests/test_packaging.py +185 -0
  305. package/.next/standalone/sdk/python/tests/test_resolver_umbrella.py +178 -0
  306. package/.next/standalone/sdk/python/tests/test_scopes.py +487 -0
  307. package/.next/standalone/sdk/python/tests/test_sdk.py +923 -0
  308. package/.next/standalone/sdk/python/tests/test_server_contract.py +650 -0
  309. package/.next/standalone/sdk/python/tests/test_site_docs.py +371 -0
  310. package/.next/standalone/sdk/python/tests/test_skill_snippets.py +165 -0
  311. package/.next/standalone/sdk/python/tests/test_spool_contract.py +287 -0
  312. package/.next/standalone/sdk/python/tests/test_spool_creation.py +360 -0
  313. package/.next/standalone/sdk/python/tests/test_wire_format.py +279 -0
  314. package/.next/standalone/sdk/python/tests/test_zero_dependencies.py +378 -0
  315. package/.next/standalone/sdk/python/uv.lock +6005 -0
  316. package/.next/standalone/server.js +1 -1
  317. package/README.md +77 -21
  318. package/bin/failproofai.mjs +579 -306
  319. package/dist/cli.mjs +6499 -3662
  320. package/dist/index.js +5 -5
  321. package/dist/worker.mjs +2390 -1978
  322. package/package.json +27 -21
  323. package/scripts/build-policy-pack.mjs +121 -0
  324. package/scripts/changelog-section.py +77 -0
  325. package/scripts/prune-standalone.mjs +3 -0
  326. package/scripts/python-version.py +232 -0
  327. package/scripts/translate-docs/cli.ts +21 -0
  328. package/scripts/translate-docs/mintlify-nav.ts +85 -13
  329. package/scripts/translate-docs/translator.ts +66 -11
  330. package/src/audit/cache.ts +40 -3
  331. package/src/audit/cli.ts +1 -1
  332. package/src/audit/index.ts +1 -1
  333. package/src/audit/replay.ts +89 -3
  334. package/src/audit/report.ts +5 -5
  335. package/src/audit/schedule-cli.ts +49 -53
  336. package/src/hooks/builtin-policies.ts +217 -579
  337. package/src/hooks/cloud-enrollment-cli.ts +66 -27
  338. package/src/hooks/cloud-managed-policies.ts +6 -1
  339. package/src/hooks/configure-wizard.ts +56 -369
  340. package/src/hooks/custom-hooks-loader.ts +89 -6
  341. package/src/hooks/fp-home.ts +92 -4
  342. package/src/hooks/fp-reset.ts +34 -2
  343. package/src/hooks/handler.ts +181 -11
  344. package/src/hooks/harness-cli.ts +79 -25
  345. package/src/hooks/hook-activity-store.ts +13 -3
  346. package/src/hooks/install-prompt.ts +25 -3
  347. package/src/hooks/manager.ts +424 -172
  348. package/src/hooks/migrations.ts +2 -2
  349. package/src/hooks/pack-cli.ts +885 -0
  350. package/src/hooks/pack-failclosed.ts +189 -0
  351. package/src/hooks/pack-manifest.ts +352 -0
  352. package/src/hooks/pack-store.ts +891 -0
  353. package/src/hooks/policy-catalog.ts +535 -0
  354. package/src/hooks/policy-evaluator.ts +24 -16
  355. package/src/hooks/policy-registry.ts +8 -2
  356. package/src/hooks/policy-types.ts +26 -0
  357. package/src/hooks/session-pause-cli.ts +33 -9
  358. package/src/hooks/tui.ts +695 -39
  359. package/src/hooks/types.ts +15 -1
  360. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_usx0j._.js +0 -3
  361. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_zk340._.js +0 -3
  362. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0agdw2a._.js +0 -3
  363. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d1u_na._.js +0 -3
  364. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0oy4kxb._.js +0 -3
  365. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zf034w._.js +0 -3
  366. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tvn4wf._.js +0 -3
  367. package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +0 -3
  368. package/.next/standalone/.next/server/chunks/_1ger0a2._.js +0 -3
  369. package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +0 -3
  370. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_1iiwm5e._.js +0 -3
  371. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__07tbbf3._.js +0 -3
  372. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0kc8_v5._.js +0 -4
  373. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0kgy9da._.js +0 -4
  374. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0mhqk5a._.js +0 -4
  375. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0pltpn8._.js +0 -4
  376. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qkcyf-._.js +0 -4
  377. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0w0x_ok._.js +0 -4
  378. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1_dfocn._.js +0 -4
  379. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1bfex62._.js +0 -5
  380. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1kzapg5._.js +0 -6
  381. package/.next/standalone/.next/server/chunks/ssr/_0lvyuv4._.js +0 -23
  382. package/.next/standalone/.next/static/chunks/2_2lhuojq2xop.js +0 -1
  383. package/.next/standalone/.next/static/chunks/36fw6yk1s6x_f.js +0 -1
  384. package/.next/standalone/.next/static/chunks/3k7mxbp9hiom0.js +0 -1
  385. package/.next/standalone/.next/static/chunks/3tzq0260n17ae.js +0 -6
  386. package/.next/standalone/.next/static/chunks/3wq9x0c-7ld5d.css +0 -2
  387. package/src/hooks/policy-presets.ts +0 -135
  388. /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → I5kEb9kSgYS63j4iqfVLO}/_buildManifest.js +0 -0
  389. /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → I5kEb9kSgYS63j4iqfVLO}/_clientMiddlewareManifest.js +0 -0
  390. /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → I5kEb9kSgYS63j4iqfVLO}/_ssgManifest.js +0 -0
@@ -6,7 +6,13 @@ import { statSync } from "node:fs";
6
6
  import { readFile, writeFile } from "node:fs/promises";
7
7
  import { execSync, execFileSync } from "node:child_process";
8
8
  import { homedir } from "node:os";
9
- import type { BuiltinPolicyDefinition, PolicyContext, PolicyResult, PolicyParamsSchema } from "./policy-types";
9
+ import type {
10
+ BuiltinPolicyDefinition,
11
+ PolicyContext,
12
+ PolicyFunction,
13
+ PolicyResult,
14
+ } from "./policy-types";
15
+ import { POLICY_CATALOG } from "./policy-catalog";
10
16
  import { allow, deny, instruct } from "./policy-helpers";
11
17
  import { normalizePolicyName, registerPolicy } from "./policy-registry";
12
18
  import { hookLogWarn } from "./hook-logger";
@@ -254,7 +260,7 @@ const SEGMENT_SEPARATORS = /[;&|\n\r(){}`]+/;
254
260
  * `/usr/bin/env` and `env` behave identically.
255
261
  */
256
262
  const COMMAND_PREFIX_TOKENS = new Set([
257
- "npx", "bunx", "pnpx", "npm", "pnpm", "yarn", "dlx", "exec", "run",
263
+ "npx", "bunx", "pnpx", "npm", "pnpm", "yarn", "dlx", "exec", "run", "eval",
258
264
  "node", "bun", "deno", "env", "command", "builtin", "nohup", "setsid",
259
265
  "time", "timeout", "nice", "stdbuf", "xargs", "sudo", "doas",
260
266
  "sh", "bash", "zsh", "dash", "ksh", "fish", "ash",
@@ -265,6 +271,15 @@ const COMMAND_PREFIX_TOKENS = new Set([
265
271
  * `./node_modules/.bin/failproofai`, `.../failproofai/bin/failproofai.mjs`. */
266
272
  const SELF_BINARY_TOKEN_RE = /(?:^|\/)failproofai[^/]*$/;
267
273
 
274
+ /**
275
+ * The same CLI, reached by path rather than by name.
276
+ *
277
+ * `node <pkg>/dist/cli.mjs config --pause` put `node` in command position, so
278
+ * the walk above settled on a path the binary regex did not match — and it
279
+ * paused enforcement. Verified as a live bypass.
280
+ */
281
+ const SELF_ENTRY_PATH_RE = /failproofai\/(?:dist\/(?:cli|index)\.mjs|bin\/failproofai\.mjs)$/;
282
+
268
283
  /** `config`, and the two aliases the entrypoint normalizes to it. */
269
284
  const CONFIG_SUBCOMMAND_RE = /^(?:config|configure|setup)$/;
270
285
 
@@ -290,7 +305,36 @@ const RUNNER_OPERAND_RE = /^\d+[a-z]*$/i;
290
305
  * and denies. That is a far narrower miss than matching every mention, and it
291
306
  * errs toward refusing rather than toward silently suspending enforcement.
292
307
  */
293
- function namesSelfPause(command: string): boolean {
308
+ type SelfInvocation = "pause" | "cli";
309
+
310
+ /**
311
+ * Classify a command by what it does to failproofai itself, or null when it
312
+ * does nothing to failproofai at all.
313
+ *
314
+ * `pause` outranks `cli` wherever both appear, because the pause verdict is the
315
+ * one whose message has to explain that suspending enforcement is a human call.
316
+ */
317
+ function classifySelfInvocation(raw: string): SelfInvocation | null {
318
+ // `${X}` before anything else looks at it: braces are SEGMENT SEPARATORS, so
319
+ // the reference was being split into `$` and `X` and matched nothing, while
320
+ // the shell ran it perfectly well.
321
+ const command = raw.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g, "$$$1");
322
+ let found: SelfInvocation | null = null;
323
+ // Variables assigned the binary earlier in the SAME command.
324
+ //
325
+ // `x=failproofai; $x config --pause` put `$x` in command position, matched
326
+ // nothing, and paused enforcement — verified as a live bypass. A shell would
327
+ // have to be re-implemented to resolve this in general; what is cheap and
328
+ // covers the actual trick is remembering what was assigned right here.
329
+ const selfVars = new Set<string>();
330
+ for (const [, name, value] of command.matchAll(/(?:^|[\s;&|])([A-Za-z_][A-Za-z0-9_]*)=("[^"]*"|'[^']*'|[^\s;&|]+)/g)) {
331
+ const bare = value.replace(/^["']|["']$/g, "");
332
+ if (SELF_BINARY_TOKEN_RE.test(bare) || SELF_ENTRY_PATH_RE.test(bare)) selfVars.add(name);
333
+ }
334
+ const isSelfVarRef = (token: string): boolean => {
335
+ const m = /^\$\{?([A-Za-z_][A-Za-z0-9_]*)\}?$/.exec(token);
336
+ return m ? selfVars.has(m[1]) : false;
337
+ };
294
338
  for (const segment of command.split(SEGMENT_SEPARATORS)) {
295
339
  const tokens = segment.split(/\s+/).filter(Boolean);
296
340
  let i = 0;
@@ -309,16 +353,24 @@ function namesSelfPause(command: string): boolean {
309
353
  i++;
310
354
  }
311
355
  if (i >= tokens.length) continue;
312
- if (!SELF_BINARY_TOKEN_RE.test(tokens[i])) continue;
356
+ if (
357
+ !SELF_BINARY_TOKEN_RE.test(tokens[i]) &&
358
+ !SELF_ENTRY_PATH_RE.test(tokens[i]) &&
359
+ !isSelfVarRef(tokens[i])
360
+ ) {
361
+ continue;
362
+ }
313
363
 
314
- // The binary IS the command here. Now require `config … --pause` in the
315
- // argument order the CLI actually accepts.
364
+ // The binary IS the command here. `config … --pause` is singled out only for
365
+ // its message; every other subcommand is denied just the same.
316
366
  const args = tokens.slice(i + 1);
317
367
  const configAt = args.findIndex((a) => CONFIG_SUBCOMMAND_RE.test(a));
318
- if (configAt === -1) continue;
319
- if (args.slice(configAt + 1).some((a) => PAUSE_FLAG_RE.test(a))) return true;
368
+ if (configAt !== -1 && args.slice(configAt + 1).some((a) => PAUSE_FLAG_RE.test(a))) {
369
+ return "pause";
370
+ }
371
+ found = "cli";
320
372
  }
321
- return false;
373
+ return found;
322
374
  }
323
375
 
324
376
  /**
@@ -400,7 +452,15 @@ const SECRET_FILE_CREDENTIALS_RE = /credentials/;
400
452
  const GIT_COMMIT_MERGE_RE = /git\s+(commit|merge|rebase|cherry-pick)\b/;
401
453
 
402
454
  // blockFailproofaiCommands
403
- const FAILPROOFAI_CLI_RE = /(?:^|;|&&|\|\||\|)\s*failproofai(?:\s|$)/;
455
+ /**
456
+ * A command that removes or moves failproofai's own state.
457
+ *
458
+ * Named separately from the binary walk because it never mentions the binary:
459
+ * the target is a path, and the verb is an ordinary file command.
460
+ */
461
+ const FAILPROOFAI_STATE_WRITE_RE =
462
+ /\b(?:rm|unlink|shred|mv|truncate)\b[^;&|]*\.failproofai(?:\/|\b)/;
463
+
404
464
  const FAILPROOFAI_UNINSTALL_RE = /(?:npm\s+(?:uninstall|remove|un|r)\s.*failproofai|bun\s+remove\s.*failproofai|yarn\s+global\s+remove\s+failproofai|pnpm\s+(?:remove|uninstall|un)\s.*failproofai)/;
405
465
 
406
466
  // warnGitAmend
@@ -968,20 +1028,6 @@ function blockSudo(ctx: PolicyContext): PolicyResult {
968
1028
  * can run `failproofai audit`. Neither gap should leave pausing reachable, so
969
1029
  * this stays narrow, matches the runner forms, and survives that one being off.
970
1030
  */
971
- function blockSelfPause(ctx: PolicyContext): PolicyResult {
972
- if (ctx.toolName !== "Bash") return allow();
973
- const cmd = getCommand(ctx);
974
- // The raw command AND its shell-unescaped form: a shell strips quotes and
975
- // backslashes before running the binary, so `fail\proofai config --pause`
976
- // reaches the pause CLI even though the literal name is broken.
977
- if (namesSelfPause(cmd) || namesSelfPause(stripShellQuoting(cmd))) {
978
- return deny(
979
- "Pausing failproofai enforcement is a human action, not an agent one. " +
980
- "If a policy is blocking legitimate work, say so and let the operator decide.",
981
- );
982
- }
983
- return allow();
984
- }
985
1031
 
986
1032
  function blockCurlPipeSh(ctx: PolicyContext): PolicyResult {
987
1033
  if (ctx.toolName !== "Bash") return allow();
@@ -1386,20 +1432,60 @@ function blockWorkOnMain(ctx: PolicyContext): PolicyResult {
1386
1432
  return allow();
1387
1433
  }
1388
1434
 
1435
+ /**
1436
+ * The one policy that cannot be turned off — see `alwaysOn` on its definition.
1437
+ *
1438
+ * Merged from the former `block-self-pause` and `block-failproofai-commands`,
1439
+ * which were two halves of one guard that disagreed with each other.
1440
+ *
1441
+ * `block-self-pause` had the hardened matcher: it walks off runner prefixes and
1442
+ * re-checks the shell-unescaped form, so `sudo failproofai …`, `npx failproofai
1443
+ * …` and `fail\proofai …` do not get through. But it only ever looked for
1444
+ * `config --pause`. `block-failproofai-commands` had the whole surface — any CLI
1445
+ * call, plus package-manager uninstall — on a regex a single `sudo` defeated.
1446
+ * Keeping the broad surface and dropping the weak matcher is the only
1447
+ * combination stronger than either half.
1448
+ *
1449
+ * They also contradicted each other: `block-self-pause` deliberately ALLOWED
1450
+ * `config --resume`, `config --status` and `policies --install`, while
1451
+ * `block-failproofai-commands` denied them. Both were `defaultEnabled`, so the
1452
+ * deny is what actually happened on every machine and the allow never ran. The
1453
+ * merge keeps the behaviour users have.
1454
+ */
1389
1455
  function blockFailproofaiCommands(ctx: PolicyContext): PolicyResult {
1390
1456
  if (ctx.toolName !== "Bash") return allow();
1391
1457
  const cmd = getCommand(ctx);
1458
+ // The raw command AND its shell-unescaped form: a shell strips quotes and
1459
+ // backslashes before running the binary, so `fail\proofai config --pause`
1460
+ // reaches the pause CLI even though the literal name is broken.
1461
+ const unescaped = stripShellQuoting(cmd);
1462
+ const kind = classifySelfInvocation(cmd) ?? classifySelfInvocation(unescaped);
1392
1463
 
1393
- // Block direct failproofai CLI invocations
1394
- if (FAILPROOFAI_CLI_RE.test(cmd)) {
1464
+ if (kind === "pause") {
1465
+ return deny(
1466
+ "Pausing failproofai enforcement is a human action, not an agent one. " +
1467
+ "If a policy is blocking legitimate work, say so and let the operator decide.",
1468
+ );
1469
+ }
1470
+ if (kind === "cli") {
1395
1471
  return deny("Running failproofai CLI commands is blocked");
1396
1472
  }
1397
-
1398
- // Block package-manager uninstallation of failproofai
1399
- if (FAILPROOFAI_UNINSTALL_RE.test(cmd)) {
1473
+ // Package-manager removal puts the manager in command position, not the
1474
+ // binary, so the walk above never reaches it.
1475
+ if (FAILPROOFAI_UNINSTALL_RE.test(cmd) || FAILPROOFAI_UNINSTALL_RE.test(unescaped)) {
1400
1476
  return deny("Uninstalling failproofai is blocked");
1401
1477
  }
1402
-
1478
+ // Deleting the state IS disabling enforcement, without ever naming the binary.
1479
+ // `rm ~/.failproofai/policies/packs/installed.json` switched off every pack
1480
+ // policy on the machine and fail-closed did NOT fire, because a missing store
1481
+ // reads as a fresh machine rather than a broken one — so nothing anywhere
1482
+ // reported it.
1483
+ if (FAILPROOFAI_STATE_WRITE_RE.test(cmd) || FAILPROOFAI_STATE_WRITE_RE.test(unescaped)) {
1484
+ return deny(
1485
+ "Deleting or moving failproofai's own state would switch enforcement off. " +
1486
+ "If a policy is blocking legitimate work, say so and let the operator decide.",
1487
+ );
1488
+ }
1403
1489
  return allow();
1404
1490
  }
1405
1491
 
@@ -2061,561 +2147,113 @@ function requireCiGreenBeforeStop(ctx: PolicyContext): PolicyResult {
2061
2147
 
2062
2148
  // -- Registry --
2063
2149
 
2064
- export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
2065
- {
2066
- name: "sanitize-jwt",
2067
- description: "Stop Claude from reading JWTs in tool responses",
2068
- displayTitle: "Redacted JWT tokens from tool output",
2069
- impact: "Stops the agent from echoing auth tokens it saw in command output.",
2070
- fn: sanitizeJwt,
2071
- match: { events: ["PostToolUse"] },
2072
- defaultEnabled: true,
2073
- category: "Sanitize",
2074
- },
2075
- {
2076
- name: "sanitize-api-keys",
2077
- description: "Stop Claude from reading API keys (OpenAI, Anthropic, GitHub, AWS, Stripe, Google) in tool responses",
2078
- displayTitle: "Redacted API keys from tool output",
2079
- impact: "Catches OpenAI / Anthropic / GitHub / AWS / Stripe / Google keys before the model sees them.",
2080
- fn: sanitizeApiKeys,
2081
- match: { events: ["PostToolUse"] },
2082
- defaultEnabled: true,
2083
- category: "Sanitize",
2084
- params: {
2085
- additionalPatterns: {
2086
- type: "pattern[]",
2087
- description: "Additional API key patterns to scrub, each with { regex, label }",
2088
- default: [],
2089
- },
2090
- } satisfies PolicyParamsSchema,
2091
- },
2092
- {
2093
- name: "sanitize-connection-strings",
2094
- description: "Stop Claude from reading database connection strings with embedded credentials in tool responses",
2095
- displayTitle: "Redacted database connection strings from tool output",
2096
- impact: "Strips embedded DB credentials before they reach the model context.",
2097
- fn: sanitizeConnectionStrings,
2098
- match: { events: ["PostToolUse"] },
2099
- defaultEnabled: true,
2100
- category: "Sanitize",
2101
- },
2102
- {
2103
- name: "sanitize-private-key-content",
2104
- description: "Stop Claude from reading PEM private key content in tool responses",
2105
- displayTitle: "Redacted PEM private keys from tool output",
2106
- impact: "Prevents private key bodies from being echoed into chat context.",
2107
- fn: sanitizePrivateKeyContent,
2108
- match: { events: ["PostToolUse"] },
2109
- defaultEnabled: true,
2110
- category: "Sanitize",
2111
- },
2112
- {
2113
- name: "sanitize-bearer-tokens",
2114
- displayTitle: "Redacted bearer tokens from tool output",
2115
- impact: "Strips Authorization: Bearer values before they hit the model.",
2116
- description: "Stop Claude from reading Authorization Bearer tokens in tool responses",
2117
- fn: sanitizeBearerTokens,
2118
- match: { events: ["PostToolUse"] },
2119
- defaultEnabled: true,
2120
- category: "Sanitize",
2121
- },
2122
- {
2123
- name: "protect-env-vars",
2124
- displayTitle: "Tried to dump environment variables to chat",
2125
- impact: "Env vars often contain secrets; blocking `env` / `printenv` keeps them out of the model context.",
2126
- description: "Prevent commands that read environment variables",
2127
- fn: protectEnvVars,
2128
- match: { events: ["PreToolUse"], toolNames: ["Bash"] },
2129
- defaultEnabled: true,
2130
- category: "Environment",
2131
- },
2132
- {
2133
- name: "block-env-files",
2134
- displayTitle: "Tried to read or write a .env file",
2135
- impact: "`.env` files routinely contain API keys and DB credentials.",
2136
- description: "Block reading/writing .env files",
2137
- fn: blockEnvFiles,
2138
- match: { events: ["PreToolUse"] },
2139
- defaultEnabled: true,
2140
- category: "Environment",
2141
- },
2142
- {
2143
- name: "block-read-outside-cwd",
2144
- displayTitle: "Tried to read files outside your project directory",
2145
- impact: "Stops the agent from peeking at neighboring repos or your home directory.",
2146
- description: "Block file reads outside the session working directory",
2147
- fn: blockReadOutsideCwd,
2148
- match: { events: ["PreToolUse"], toolNames: ["Read", "Glob", "Grep", "Bash"] },
2149
- defaultEnabled: false,
2150
- category: "Environment",
2151
- params: {
2152
- allowPaths: {
2153
- type: "string[]",
2154
- description: "Absolute paths outside cwd that are allowed to be read",
2155
- default: [],
2156
- },
2157
- } satisfies PolicyParamsSchema,
2158
- },
2159
- {
2160
- name: "block-self-pause",
2161
- displayTitle: "Tried to pause failproofai enforcement",
2162
- impact: "An agent that can pause enforcement can switch off every other policy.",
2163
- description: "Block agents from pausing failproofai enforcement",
2164
- fn: blockSelfPause,
2165
- match: { events: ["PreToolUse", "PermissionRequest"], toolNames: ["Bash"] },
2166
- defaultEnabled: true,
2167
- category: "Dangerous Commands",
2168
- },
2169
- {
2170
- name: "block-sudo",
2171
- displayTitle: "Tried to run a command with sudo",
2172
- impact: "Sudo gives the agent root — blocked unless explicitly allow-listed.",
2173
- description: "Block sudo commands",
2174
- fn: blockSudo,
2175
- // PermissionRequest is Codex's escalation-approval event; fire the same
2176
- // sudo guard there so Codex sandbox bypasses are blocked too.
2177
- match: { events: ["PreToolUse", "PermissionRequest"], toolNames: ["Bash"] },
2178
- defaultEnabled: true,
2179
- category: "Dangerous Commands",
2180
- params: {
2181
- allowPatterns: {
2182
- type: "string[]",
2183
- description: "Sudo command patterns to allow, matched token-by-token (e.g. 'sudo systemctl status')",
2184
- default: [],
2185
- },
2186
- } satisfies PolicyParamsSchema,
2187
- },
2188
- {
2189
- name: "block-curl-pipe-sh",
2190
- displayTitle: "Tried to pipe a downloaded script straight to a shell",
2191
- impact: "`curl ... | sh` runs unverified remote code on your machine.",
2192
- description: "Block piping downloads to shell",
2193
- fn: blockCurlPipeSh,
2194
- match: { events: ["PreToolUse"], toolNames: ["Bash"] },
2195
- defaultEnabled: true,
2196
- category: "Dangerous Commands",
2197
- },
2198
- {
2199
- name: "block-rm-rf",
2200
- displayTitle: "Tried to recursively delete a system path",
2201
- impact: "Catches catastrophic `rm -rf /` and Windows equivalents.",
2202
- description: "Prevent catastrophic deletions",
2203
- fn: blockRmRf,
2204
- match: { events: ["PreToolUse"], toolNames: ["Bash"] },
2205
- defaultEnabled: false,
2206
- category: "Dangerous Commands",
2207
- params: {
2208
- allowPaths: {
2209
- type: "string[]",
2210
- description: "Paths that are allowed to be recursively deleted",
2211
- default: [],
2212
- },
2213
- } satisfies PolicyParamsSchema,
2214
- },
2215
- {
2216
- name: "block-failproofai-commands",
2217
- displayTitle: "Tried to disable or modify failproofai itself",
2218
- impact: "Prevents the agent from turning off the policies that protect you.",
2219
- description: "Block failproofai CLI commands and uninstallation",
2220
- fn: blockFailproofaiCommands,
2221
- match: { events: ["PreToolUse"], toolNames: ["Bash"] },
2222
- defaultEnabled: true,
2223
- category: "Dangerous Commands",
2224
- },
2225
- {
2226
- name: "block-kubectl",
2227
- displayTitle: "Tried to run a Kubernetes command",
2228
- impact: "kubectl can change live cluster state — gated unless allow-listed.",
2229
- description: "Block kubectl commands (Kubernetes cluster mutations)",
2230
- fn: blockKubectl,
2231
- match: { events: ["PreToolUse"], toolNames: ["Bash"] },
2232
- defaultEnabled: false,
2233
- category: "Infra Commands",
2234
- params: {
2235
- allowPatterns: {
2236
- type: "string[]",
2237
- description: "kubectl command patterns to allow, matched token-by-token (e.g. 'kubectl get *', 'kubectl describe *')",
2238
- default: [],
2239
- },
2240
- } satisfies PolicyParamsSchema,
2241
- },
2242
- {
2243
- name: "block-terraform",
2244
- displayTitle: "Tried to run a Terraform/OpenTofu command",
2245
- impact: "Terraform mutates real infrastructure — gated unless allow-listed.",
2246
- description: "Block terraform and tofu (OpenTofu) commands",
2247
- fn: blockTerraform,
2248
- match: { events: ["PreToolUse"], toolNames: ["Bash"] },
2249
- defaultEnabled: false,
2250
- category: "Infra Commands",
2251
- params: {
2252
- allowPatterns: {
2253
- type: "string[]",
2254
- description: "terraform/tofu command patterns to allow (e.g. 'terraform plan', 'terraform validate')",
2255
- default: [],
2256
- },
2257
- } satisfies PolicyParamsSchema,
2258
- },
2259
- {
2260
- name: "block-aws-cli",
2261
- displayTitle: "Tried to run an AWS CLI command",
2262
- impact: "AWS CLI can spend money or break prod — gated.",
2263
- description: "Block aws CLI commands",
2264
- fn: blockAwsCli,
2265
- match: { events: ["PreToolUse"], toolNames: ["Bash"] },
2266
- defaultEnabled: false,
2267
- category: "Infra Commands",
2268
- params: {
2269
- allowPatterns: {
2270
- type: "string[]",
2271
- description: "aws CLI command patterns to allow (e.g. 'aws s3 ls *', 'aws sts get-caller-identity')",
2272
- default: [],
2273
- },
2274
- } satisfies PolicyParamsSchema,
2275
- },
2276
- {
2277
- name: "block-gcloud",
2278
- displayTitle: "Tried to run a Google Cloud command",
2279
- impact: "gcloud can spend money or break prod — gated.",
2280
- description: "Block gcloud (Google Cloud) CLI commands",
2281
- fn: blockGcloud,
2282
- match: { events: ["PreToolUse"], toolNames: ["Bash"] },
2283
- defaultEnabled: false,
2284
- category: "Infra Commands",
2285
- params: {
2286
- allowPatterns: {
2287
- type: "string[]",
2288
- description: "gcloud command patterns to allow (e.g. 'gcloud auth list', 'gcloud config list')",
2289
- default: [],
2290
- },
2291
- } satisfies PolicyParamsSchema,
2292
- },
2293
- {
2294
- name: "block-az-cli",
2295
- displayTitle: "Tried to run an Azure CLI command",
2296
- impact: "az can spend money or break prod — gated.",
2297
- description: "Block az (Azure) CLI commands",
2298
- fn: blockAzCli,
2299
- match: { events: ["PreToolUse"], toolNames: ["Bash"] },
2300
- defaultEnabled: false,
2301
- category: "Infra Commands",
2302
- params: {
2303
- allowPatterns: {
2304
- type: "string[]",
2305
- description: "az CLI command patterns to allow (e.g. 'az account show', 'az group list')",
2306
- default: [],
2307
- },
2308
- } satisfies PolicyParamsSchema,
2309
- },
2310
- {
2311
- name: "block-helm",
2312
- displayTitle: "Tried to run a Helm command",
2313
- impact: "Helm releases mutate cluster state — gated.",
2314
- description: "Block helm commands",
2315
- fn: blockHelm,
2316
- match: { events: ["PreToolUse"], toolNames: ["Bash"] },
2317
- defaultEnabled: false,
2318
- category: "Infra Commands",
2319
- params: {
2320
- allowPatterns: {
2321
- type: "string[]",
2322
- description: "helm command patterns to allow (e.g. 'helm list', 'helm status *')",
2323
- default: [],
2324
- },
2325
- } satisfies PolicyParamsSchema,
2326
- },
2327
- {
2328
- name: "block-gh-pipeline",
2329
- displayTitle: "Tried to run a privileged GitHub CLI pipeline command",
2330
- impact: "Catches `gh workflow run`, `gh pr merge`, `gh secret set`, etc.",
2331
- description: "Block gh CLI pipeline-trigger subcommands (workflow run, run rerun/cancel, pr merge, release create/delete, cache delete, secret set/delete)",
2332
- fn: blockGhPipeline,
2333
- match: { events: ["PreToolUse"], toolNames: ["Bash"] },
2334
- defaultEnabled: false,
2335
- category: "Infra Commands",
2336
- params: {
2337
- allowPatterns: {
2338
- type: "string[]",
2339
- description: "gh pipeline command patterns to allow (e.g. specific scripted invocations); read-only gh subcommands like 'gh pr view' and 'gh run list' are not matched by this policy",
2340
- default: [],
2341
- },
2342
- } satisfies PolicyParamsSchema,
2343
- },
2344
- {
2345
- name: "block-secrets-write",
2346
- displayTitle: "Tried to write a secret-key file",
2347
- impact: "Stops the agent from creating `.pem`, `id_rsa`, `credentials.json`, etc.",
2348
- description: "Block writing secret key files",
2349
- fn: blockSecretsWrite,
2350
- match: { events: ["PreToolUse"], toolNames: ["Write"] },
2351
- defaultEnabled: false,
2352
- category: "Dangerous Commands",
2353
- params: {
2354
- additionalPatterns: {
2355
- type: "string[]",
2356
- description: "Additional filename patterns (substrings) to block",
2357
- default: [],
2358
- },
2359
- } satisfies PolicyParamsSchema,
2360
- },
2361
- {
2362
- name: "block-push-master",
2363
- displayTitle: "Tried to push directly to main/master",
2364
- impact: "Direct pushes to a protected branch bypass review.",
2365
- description: "Block pushing to main/master",
2366
- fn: blockPushMaster,
2367
- match: { events: ["PreToolUse"], toolNames: ["Bash"] },
2368
- defaultEnabled: true,
2369
- category: "Git",
2370
- params: {
2371
- protectedBranches: {
2372
- type: "string[]",
2373
- description: "Branch names to protect from direct pushes",
2374
- default: ["main", "master"],
2375
- },
2376
- } satisfies PolicyParamsSchema,
2377
- },
2378
- {
2379
- name: "block-force-push",
2380
- displayTitle: "Tried to force-push",
2381
- impact: "Force-pushes rewrite history and can clobber teammates' work.",
2382
- description: "Prevent force-pushing to any branch",
2383
- fn: blockForcePush,
2384
- match: { events: ["PreToolUse"], toolNames: ["Bash"] },
2385
- defaultEnabled: false,
2386
- category: "Git",
2387
- },
2388
- {
2389
- name: "block-work-on-main",
2390
- displayTitle: "Tried to commit or merge on main/master",
2391
- impact: "Work should land via PR — direct commits skip review.",
2392
- description: "Block git commits and merges on main/master branch",
2393
- fn: blockWorkOnMain,
2394
- match: { events: ["PreToolUse"], toolNames: ["Bash"] },
2395
- defaultEnabled: false,
2396
- category: "Git",
2397
- params: {
2398
- protectedBranches: {
2399
- type: "string[]",
2400
- description: "Branch names where commits/merges are blocked",
2401
- default: ["main", "master"],
2402
- },
2403
- } satisfies PolicyParamsSchema,
2404
- },
2405
- {
2406
- name: "warn-git-amend",
2407
- displayTitle: "Used git commit --amend",
2408
- impact: "Amending after a push rewrites history that others may have pulled.",
2409
- description: "Warns before amending git commits, which rewrites history",
2410
- fn: warnGitAmend,
2411
- match: { events: ["PreToolUse"], toolNames: ["Bash"] },
2412
- defaultEnabled: false,
2413
- category: "Git",
2414
- },
2415
- {
2416
- name: "warn-git-stash-drop",
2417
- displayTitle: "Tried to drop or clear git stash",
2418
- impact: "Stash deletions are permanent and silent.",
2419
- description: "Warns before permanently deleting stashed changes",
2420
- fn: warnGitStashDrop,
2421
- match: { events: ["PreToolUse"], toolNames: ["Bash"] },
2422
- defaultEnabled: false,
2423
- category: "Git",
2424
- },
2425
- {
2426
- name: "warn-all-files-staged",
2427
- displayTitle: "Staged all files with git add -A / .",
2428
- impact: "Wide stages routinely catch generated files or secrets you didn't intend to commit.",
2429
- description: "Warns before staging all working tree files with git add -A / . / --all",
2430
- fn: warnAllFilesStaged,
2431
- match: { events: ["PreToolUse"], toolNames: ["Bash"] },
2432
- defaultEnabled: false,
2433
- category: "Git",
2434
- },
2435
- {
2436
- name: "warn-destructive-sql",
2437
- displayTitle: "Ran destructive SQL (DROP / TRUNCATE / DELETE without WHERE)",
2438
- impact: "Easy way to wipe a table by accident.",
2439
- description: "Warn before executing destructive SQL (DROP/TRUNCATE/DELETE without WHERE) via database clients",
2440
- fn: warnDestructiveSql,
2441
- match: { events: ["PreToolUse"], toolNames: ["Bash"] },
2442
- defaultEnabled: false,
2443
- category: "Database",
2444
- },
2445
- {
2446
- name: "warn-schema-alteration",
2447
- displayTitle: "Altered a database schema column",
2448
- impact: "ALTER TABLE operations can lock tables and break readers.",
2449
- description: "Warns before SQL schema changes (ALTER TABLE with column or rename operations)",
2450
- fn: warnSchemaAlteration,
2451
- match: { events: ["PreToolUse"], toolNames: ["Bash"] },
2452
- defaultEnabled: false,
2453
- category: "Database",
2454
- },
2455
- {
2456
- name: "warn-package-publish",
2457
- displayTitle: "Tried to publish a package",
2458
- impact: "Publishes are irreversible — `npm publish` / `cargo publish` shouldn't happen without intent.",
2459
- description: "Warn before publishing packages to public registries (npm, PyPI, crates.io, RubyGems, etc.)",
2460
- fn: warnPackagePublish,
2461
- match: { events: ["PreToolUse"], toolNames: ["Bash"] },
2462
- defaultEnabled: false,
2463
- category: "Packages & System",
2464
- },
2465
- {
2466
- name: "warn-global-package-install",
2467
- displayTitle: "Installed a package globally",
2468
- impact: "`npm i -g`, `cargo install`, `pip --user` pollute your machine outside the project.",
2469
- description: "Warns before installing packages globally (npm -g, cargo install, etc.)",
2470
- fn: warnGlobalPackageInstall,
2471
- match: { events: ["PreToolUse"], toolNames: ["Bash"] },
2472
- defaultEnabled: false,
2473
- category: "Packages & System",
2474
- },
2475
- {
2476
- name: "prefer-package-manager",
2477
- displayTitle: "Used a non-preferred package manager",
2478
- impact: "Mixing package managers creates lockfile churn for your team.",
2479
- description: "Blocks non-preferred package managers and tells Claude to use an allowed one (e.g., uv instead of pip)",
2480
- fn: preferPackageManager,
2481
- match: { events: ["PreToolUse"], toolNames: ["Bash"] },
2482
- defaultEnabled: false,
2483
- category: "Packages & System",
2484
- params: {
2485
- allowed: {
2486
- type: "string[]",
2487
- description: "Allowed package manager names (e.g. ['uv', 'bun']). Any detected manager not in this list is blocked.",
2488
- default: [],
2489
- },
2490
- blocked: {
2491
- type: "string[]",
2492
- description: "Additional manager names to block beyond the built-in list (e.g. ['pdm', 'pipx']).",
2493
- default: [],
2494
- },
2495
- } satisfies PolicyParamsSchema,
2496
- },
2497
- {
2498
- name: "warn-large-file-write",
2499
- displayTitle: "Wrote a file larger than the configured threshold",
2500
- impact: "Catches accidentally large file writes (logs, binaries, model dumps).",
2501
- description: "Warn before writing files larger than 1MB (configurable via thresholdKb param)",
2502
- fn: warnLargeFileWrite,
2503
- match: { events: ["PreToolUse"], toolNames: ["Write"] },
2504
- defaultEnabled: false,
2505
- category: "Packages & System",
2506
- params: {
2507
- thresholdKb: {
2508
- type: "number",
2509
- description: "File size threshold in KB above which a warning is issued",
2510
- default: 1024,
2511
- },
2512
- } satisfies PolicyParamsSchema,
2513
- },
2514
- {
2515
- name: "warn-background-process",
2516
- displayTitle: "Started a long-lived background process",
2517
- impact: "Catches `nohup` / `&` / `screen` / `tmux` / `disown` patterns that the agent often forgets to clean up.",
2518
- description: "Warns before starting detached or background processes",
2519
- fn: warnBackgroundProcess,
2520
- match: { events: ["PreToolUse"], toolNames: ["Bash"] },
2521
- defaultEnabled: false,
2522
- category: "Packages & System",
2523
- },
2524
- {
2525
- name: "warn-repeated-tool-calls",
2526
- displayTitle: "Called the same tool 3+ times with identical arguments",
2527
- impact: "Usually a sign of a stuck loop burning tokens.",
2528
- description: "Warn when the same tool is called 3+ times with identical parameters",
2529
- fn: warnRepeatedToolCalls,
2530
- match: { events: ["PreToolUse"] },
2531
- defaultEnabled: false,
2532
- category: "AI Behavior",
2533
- },
2534
- {
2535
- name: "require-commit-before-stop",
2536
- displayTitle: "Stopped with uncommitted changes",
2537
- impact: "Work not in a commit is invisible to teammates and easy to lose.",
2538
- description: "Require all changes to be committed before Claude stops",
2539
- fn: requireCommitBeforeStop,
2540
- match: { events: ["Stop"] },
2541
- defaultEnabled: false,
2542
- category: "Workflow",
2543
- },
2544
- {
2545
- name: "require-push-before-stop",
2546
- displayTitle: "Stopped with unpushed commits",
2547
- impact: "Local-only commits won't trigger CI or be reviewable.",
2548
- description: "Require all commits to be pushed to remote before Claude stops",
2549
- fn: requirePushBeforeStop,
2550
- match: { events: ["Stop"] },
2551
- defaultEnabled: false,
2552
- category: "Workflow",
2553
- params: {
2554
- remote: {
2555
- type: "string",
2556
- description: "Remote name to push to (default: origin)",
2557
- default: "origin",
2558
- },
2559
- baseBranch: {
2560
- type: "string",
2561
- description: "Base branch to compare against (default: main)",
2562
- default: "main",
2563
- },
2564
- } satisfies PolicyParamsSchema,
2565
- },
2566
- {
2567
- name: "require-pr-before-stop",
2568
- displayTitle: "Stopped without a PR for the branch",
2569
- impact: "Branches without PRs don't get reviewed.",
2570
- description: "Require a pull request to exist for the current branch before Claude stops",
2571
- fn: requirePrBeforeStop,
2572
- match: { events: ["Stop"] },
2573
- defaultEnabled: false,
2574
- category: "Workflow",
2575
- params: {
2576
- baseBranch: {
2577
- type: "string",
2578
- description: "Base branch to compare against (default: main)",
2579
- default: "main",
2580
- },
2581
- } satisfies PolicyParamsSchema,
2582
- },
2583
- {
2584
- name: "require-no-conflicts-before-stop",
2585
- displayTitle: "Stopped with a branch that conflicts with main",
2586
- impact: "Conflicting branches can't merge — surface them early.",
2587
- description: "Require the current branch to merge cleanly with the base branch before Claude stops",
2588
- fn: requireNoConflictsBeforeStop,
2589
- match: { events: ["Stop"] },
2590
- defaultEnabled: false,
2591
- category: "Workflow",
2592
- params: {
2593
- baseBranch: {
2594
- type: "string",
2595
- description: "Base branch to check for conflicts against (default: main)",
2596
- default: "main",
2597
- },
2598
- } satisfies PolicyParamsSchema,
2599
- },
2600
- {
2601
- name: "require-ci-green-before-stop",
2602
- displayTitle: "Stopped with failing CI",
2603
- impact: "Failing CI blocks deploy.",
2604
- description: "Require CI checks to pass on the current HEAD commit before Claude stops (ignores stale runs on prior commits)",
2605
- fn: requireCiGreenBeforeStop,
2606
- match: { events: ["Stop"] },
2607
- defaultEnabled: false,
2608
- category: "Workflow",
2609
- },
2610
- ];
2150
+ /**
2151
+ * Name → implementation. The other half of {@link POLICY_CATALOG}.
2152
+ *
2153
+ * Each value is the identical hoisted function object, never a wrapper. Two
2154
+ * things depend on that and neither fails loudly: `audit/cache.ts` hashes
2155
+ * `fn.toString()` into the audit cache's `engineVersion`, so wrapping every
2156
+ * entry would collapse 39 distinct hashes into one and freeze the key — stale
2157
+ * audit results would then be served for the full 30-day TTL with no symptom;
2158
+ * and `gitBranchCache` is module-scoped, so a per-call factory would silently
2159
+ * reset it on every hook event.
2160
+ */
2161
+ const POLICY_IMPLEMENTATIONS: Record<string, PolicyFunction> = {
2162
+ "sanitize-jwt": sanitizeJwt,
2163
+ "sanitize-api-keys": sanitizeApiKeys,
2164
+ "sanitize-connection-strings": sanitizeConnectionStrings,
2165
+ "sanitize-private-key-content": sanitizePrivateKeyContent,
2166
+ "sanitize-bearer-tokens": sanitizeBearerTokens,
2167
+ "protect-env-vars": protectEnvVars,
2168
+ "block-env-files": blockEnvFiles,
2169
+ "block-read-outside-cwd": blockReadOutsideCwd,
2170
+ "block-sudo": blockSudo,
2171
+ "block-curl-pipe-sh": blockCurlPipeSh,
2172
+ "block-rm-rf": blockRmRf,
2173
+ "block-failproofai-commands": blockFailproofaiCommands,
2174
+ "block-kubectl": blockKubectl,
2175
+ "block-terraform": blockTerraform,
2176
+ "block-aws-cli": blockAwsCli,
2177
+ "block-gcloud": blockGcloud,
2178
+ "block-az-cli": blockAzCli,
2179
+ "block-helm": blockHelm,
2180
+ "block-gh-pipeline": blockGhPipeline,
2181
+ "block-secrets-write": blockSecretsWrite,
2182
+ "block-push-master": blockPushMaster,
2183
+ "block-force-push": blockForcePush,
2184
+ "block-work-on-main": blockWorkOnMain,
2185
+ "warn-git-amend": warnGitAmend,
2186
+ "warn-git-stash-drop": warnGitStashDrop,
2187
+ "warn-all-files-staged": warnAllFilesStaged,
2188
+ "warn-destructive-sql": warnDestructiveSql,
2189
+ "warn-schema-alteration": warnSchemaAlteration,
2190
+ "warn-package-publish": warnPackagePublish,
2191
+ "warn-global-package-install": warnGlobalPackageInstall,
2192
+ "prefer-package-manager": preferPackageManager,
2193
+ "warn-large-file-write": warnLargeFileWrite,
2194
+ "warn-background-process": warnBackgroundProcess,
2195
+ "warn-repeated-tool-calls": warnRepeatedToolCalls,
2196
+ "require-commit-before-stop": requireCommitBeforeStop,
2197
+ "require-push-before-stop": requirePushBeforeStop,
2198
+ "require-pr-before-stop": requirePrBeforeStop,
2199
+ "require-no-conflicts-before-stop": requireNoConflictsBeforeStop,
2200
+ "require-ci-green-before-stop": requireCiGreenBeforeStop,
2201
+ };
2202
+
2203
+ /**
2204
+ * Catalog and implementations must be in BIJECTION, and this throws rather than
2205
+ * warns because the failure is otherwise invisible in the worst direction: a
2206
+ * name present here but not there yields `fn: undefined`, `registerPolicy`
2207
+ * stores it unvalidated, and the `TypeError` at `await policy.fn(ctx)` is
2208
+ * swallowed by `policy-evaluator.ts` (warn, count, `continue`). The hook then
2209
+ * ALLOWS, exits 0, and still lists the policy in `matchedPolicies` — a machine
2210
+ * reporting that a guard ran when it never did.
2211
+ */
2212
+ function assertCatalogBijection(): void {
2213
+ const implNames = new Set(Object.keys(POLICY_IMPLEMENTATIONS));
2214
+ const missing = POLICY_CATALOG.filter((e) => !implNames.has(e.name)).map((e) => e.name);
2215
+ if (missing.length > 0) {
2216
+ throw new Error(
2217
+ `failproofai: builtin policies missing an implementation: ${missing.join(", ")}`,
2218
+ );
2219
+ }
2220
+ const catalogNames = new Set(POLICY_CATALOG.map((e) => e.name));
2221
+ const orphaned = [...implNames].filter((n) => !catalogNames.has(n));
2222
+ if (orphaned.length > 0) {
2223
+ throw new Error(
2224
+ `failproofai: policy implementations with no catalog entry: ${orphaned.join(", ")}`,
2225
+ );
2226
+ }
2227
+ }
2228
+ assertCatalogBijection();
2229
+
2230
+ /**
2231
+ * The joined view, and the shape every consumer has always seen.
2232
+ *
2233
+ * Deliberately a positional, spread-only, eager `.map()`: it preserves catalog
2234
+ * order, adds no fields, fills no defaults, drops no rows and calls no factory.
2235
+ * Each of those alternatives changes observable behaviour — see the rules on
2236
+ * {@link POLICY_CATALOG} and the invariants in
2237
+ * `__tests__/hooks/policy-catalog.test.ts`.
2238
+ */
2239
+ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = POLICY_CATALOG.map((entry) => ({
2240
+ ...entry,
2241
+ fn: POLICY_IMPLEMENTATIONS[entry.name] as PolicyFunction,
2242
+ }));
2611
2243
 
2612
2244
  export function registerBuiltinPolicies(enabledNames: string[]): void {
2613
2245
  // Tolerate both flat ("sanitize-jwt") and qualified ("failproofai/sanitize-jwt")
2614
2246
  // forms in the user's enabledPolicies config — canonicalize both sides.
2615
2247
  const enabledSet = new Set(enabledNames.map(normalizePolicyName));
2616
2248
  for (const policy of BUILTIN_POLICIES) {
2617
- if (enabledSet.has(normalizePolicyName(policy.name))) {
2618
- registerPolicy(policy.name, policy.description, policy.fn, policy.match);
2249
+ // `alwaysOn` deliberately bypasses the enabled set, and the caller's three
2250
+ // ways of producing an empty one with it: a policy the user never enabled,
2251
+ // an active session pause (`handler.ts` passes `[]`), and a config file that
2252
+ // failed to parse (`hooks-config.ts` soft-fails to `{enabledPolicies: []}`).
2253
+ // A guard against the agent disabling failproofai that any of those can
2254
+ // switch off is not a guard.
2255
+ if (policy.alwaysOn || enabledSet.has(normalizePolicyName(policy.name))) {
2256
+ registerPolicy(policy.name, policy.description, policy.fn, policy.match, 0, policy.params);
2619
2257
  }
2620
2258
  }
2621
2259
  }