failproofai 1.0.1 → 1.0.2-beta.0

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 (389) 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]__0oa1lav._.js +1 -1
  97. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0p-5p8u._.js +4 -0
  98. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s740oi._.js +6 -0
  99. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__07tbbf3._.js → [root-of-the-server]__0zig5sv._.js} +2 -2
  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/{_0lvyuv4._.js → _00e9tnf._.js} +2 -2
  103. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  104. package/.next/standalone/.next/server/chunks/ssr/{_0u5zauv._.js → _12l4a_k._.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/{37fcpc36x9gpe.js → 0eqky-7n7dgdm.js} +1 -1
  121. package/.next/standalone/.next/static/chunks/{1ide1wl2f7zi1.js → 0sa9v5mhc8861.js} +13 -13
  122. package/.next/standalone/.next/static/chunks/1mfzsja6ftim5.css +2 -0
  123. package/.next/standalone/.next/static/chunks/{3k7mxbp9hiom0.js → 1nuqytbta44af.js} +1 -1
  124. package/.next/standalone/.next/static/chunks/1sl2xmn9inx3y.js +6 -0
  125. package/.next/standalone/.next/static/chunks/{2_2lhuojq2xop.js → 2aawsjld9ied_.js} +1 -1
  126. package/.next/standalone/.next/static/chunks/2gn7ut4svofm2.js +1 -0
  127. package/.next/standalone/.next/static/chunks/{31s1smp-g7gks.js → 2hs7ycvsav7v2.js} +1 -1
  128. package/.next/standalone/.next/static/chunks/{0k5050ezjvv49.js → 2i2yt3hzjredm.js} +1 -1
  129. package/.next/standalone/.next/static/chunks/{3c808qrfcq0im.js → 35xg6retpe6rp.js} +1 -1
  130. package/.next/standalone/.next/static/chunks/{2zpp1we2jv6tb.js → 3y54nw0i7dsjl.js} +1 -1
  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 +153 -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 -14
  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 +29 -22
  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 +145 -11
  319. package/dist/cli.mjs +4482 -2205
  320. package/dist/index.js +5 -5
  321. package/dist/worker.mjs +2399 -1978
  322. package/package.json +29 -22
  323. package/policy-pack/SHA256SUMS +2 -0
  324. package/policy-pack/failproofai-pack.json +732 -0
  325. package/policy-pack/failproofai-pack.mjs +2017 -0
  326. package/scripts/build-policy-pack.mjs +121 -0
  327. package/scripts/changelog-section.py +77 -0
  328. package/scripts/prune-standalone.mjs +3 -0
  329. package/scripts/python-version.py +232 -0
  330. package/scripts/translate-docs/cli.ts +21 -0
  331. package/scripts/translate-docs/mintlify-nav.ts +85 -13
  332. package/scripts/translate-docs/translator.ts +66 -11
  333. package/src/audit/cache.ts +40 -3
  334. package/src/audit/cli.ts +1 -1
  335. package/src/audit/index.ts +1 -1
  336. package/src/audit/replay.ts +89 -3
  337. package/src/audit/report.ts +5 -5
  338. package/src/audit/schedule-cli.ts +49 -53
  339. package/src/hooks/builtin-policies.ts +217 -579
  340. package/src/hooks/cloud-enrollment-cli.ts +66 -27
  341. package/src/hooks/cloud-managed-policies.ts +6 -1
  342. package/src/hooks/configure-wizard.ts +1 -1
  343. package/src/hooks/custom-hooks-loader.ts +89 -6
  344. package/src/hooks/fp-home.ts +92 -4
  345. package/src/hooks/fp-reset.ts +26 -2
  346. package/src/hooks/handler.ts +181 -11
  347. package/src/hooks/harness-cli.ts +79 -25
  348. package/src/hooks/hook-activity-store.ts +13 -3
  349. package/src/hooks/install-prompt.ts +25 -3
  350. package/src/hooks/manager.ts +418 -172
  351. package/src/hooks/migrations.ts +2 -2
  352. package/src/hooks/pack-cli.ts +505 -0
  353. package/src/hooks/pack-failclosed.ts +189 -0
  354. package/src/hooks/pack-manifest.ts +344 -0
  355. package/src/hooks/pack-store.ts +930 -0
  356. package/src/hooks/policy-catalog.ts +535 -0
  357. package/src/hooks/policy-evaluator.ts +24 -16
  358. package/src/hooks/policy-presets.ts +4 -2
  359. package/src/hooks/policy-registry.ts +8 -2
  360. package/src/hooks/policy-types.ts +26 -0
  361. package/src/hooks/session-pause-cli.ts +33 -9
  362. package/src/hooks/tui.ts +570 -0
  363. package/src/hooks/types.ts +15 -1
  364. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_usx0j._.js +0 -3
  365. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_zk340._.js +0 -3
  366. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0agdw2a._.js +0 -3
  367. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d1u_na._.js +0 -3
  368. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0oy4kxb._.js +0 -3
  369. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zf034w._.js +0 -3
  370. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tvn4wf._.js +0 -3
  371. package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +0 -3
  372. package/.next/standalone/.next/server/chunks/_1ger0a2._.js +0 -3
  373. package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +0 -3
  374. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_1iiwm5e._.js +0 -3
  375. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0kc8_v5._.js +0 -4
  376. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0kgy9da._.js +0 -4
  377. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0mhqk5a._.js +0 -4
  378. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0pltpn8._.js +0 -4
  379. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qkcyf-._.js +0 -4
  380. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0w0x_ok._.js +0 -4
  381. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1_dfocn._.js +0 -4
  382. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1bfex62._.js +0 -5
  383. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1kzapg5._.js +0 -6
  384. package/.next/standalone/.next/static/chunks/36fw6yk1s6x_f.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/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → nwbyWT06Ud0XdXOrVJyvS}/_buildManifest.js +0 -0
  388. /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → nwbyWT06Ud0XdXOrVJyvS}/_clientMiddlewareManifest.js +0 -0
  389. /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → nwbyWT06Ud0XdXOrVJyvS}/_ssgManifest.js +0 -0
@@ -0,0 +1,499 @@
1
+ """Cloud-managed policies: policies list / show / publish / enable / disable / delete.
2
+
3
+ Where a policy VERSION is written. Deploying one to a machine is `fp fleet`, and
4
+ seeing what it actually did is `fp guardrails` — three commands because they are
5
+ three jobs, done by different people at different times, exactly as the
6
+ dashboard splits them across three pages.
7
+
8
+ Publishing mints a new version and changes nothing on any machine. That is the
9
+ single most surprising thing here, so every success path says so.
10
+ """
11
+ from __future__ import annotations
12
+
13
+ from typing import Optional
14
+
15
+ import typer
16
+
17
+ from .. import client as api
18
+ from .. import output, theme
19
+ from .._context import GLOBALS_EPILOG, AppState, deny_in_key_mode, require_auth
20
+ from .. import _click_compat as click # the Click Typer is running; see _click_compat
21
+ from ..enforcement import RefError, RefUsageError, read_source
22
+ from ..policy_check import check_syntax, run_policy
23
+ from ..errors import ApiError, NotFoundError
24
+ from . import _write
25
+
26
+ #: Every command here is session-only. These endpoints are ROOT-ONLY on the
27
+ #: server — deliberately absent from `/v1`, because `/v1` is internet-facing and
28
+ #: publish/deploy/rollback are operator writes. Failing here beats translating a
29
+ #: path that would 404 with no explanation.
30
+ _KEY_MODE_REASON = (
31
+ "cloud-managed policies are an operator surface and are not exposed on the "
32
+ "versioned API that an API key authenticates against"
33
+ )
34
+
35
+
36
+ def policies_list(ctx: typer.Context) -> None:
37
+ """List every published policy version, newest of each policy first.
38
+
39
+ Shows `policy · version · state · description`, one row per VERSION —
40
+ versions are immutable and every one stays addressable, so a policy
41
+ published three times is three rows. The title counts distinct policies and
42
+ captions the version total, the way the dashboard's library does.
43
+
44
+ `state` is active, disabled (kept but not enforced) or archived (deleted;
45
+ machines already carrying it keep it until redeployed). Needs
46
+ `policies:read`. With `--json`: the server's policy list verbatim — also
47
+ every version, so deduplicate on `id` if you want one row per policy.
48
+
49
+ Example:
50
+
51
+ * `fp policies list`
52
+ """
53
+ state: AppState = ctx.obj
54
+ deny_in_key_mode(state, "policies", _KEY_MODE_REASON)
55
+ cctx = require_auth(state)
56
+ items = api.list_policies(cctx)
57
+ if output.is_json():
58
+ output.emit_json({"policies": [p.to_dict() for p in items]})
59
+ return
60
+ output.render_policies(items)
61
+
62
+
63
+ def policies_show(
64
+ ctx: typer.Context,
65
+ policy_id: str = typer.Argument(..., help="Policy id."),
66
+ ) -> None:
67
+ """Show one policy, including its full source.
68
+
69
+ Needs `policies:read`. With `--json`: the policy object with `source`.
70
+
71
+ Example:
72
+
73
+ * `fp policies show no-force-push`
74
+ """
75
+ state: AppState = ctx.obj
76
+ deny_in_key_mode(state, "policies show", _KEY_MODE_REASON)
77
+ cctx = require_auth(state)
78
+ # Explicitly the newest version, not the first one the server happened to
79
+ # list. `next(...)` returned whichever came back first, so the source shown
80
+ # was correct only for as long as the endpoint kept returning descending
81
+ # versions — and a stale source rendered identically to a current one.
82
+ versions = [p for p in api.list_policies(cctx) if p.id == policy_id]
83
+ if not versions:
84
+ raise NotFoundError(f"no policy named {policy_id}")
85
+ match = max(versions, key=lambda p: p.version)
86
+ if output.is_json():
87
+ output.emit_json(match.to_dict())
88
+ return
89
+ carriers = {
90
+ d.machine_id: ref.version
91
+ for d in api.list_deployments(cctx)
92
+ for ref in d.policies
93
+ if ref.id == policy_id
94
+ }
95
+ output.render_policy_published(match, carriers=carriers,
96
+ source_bytes=len((match.source or "").encode("utf-8")))
97
+ if match.source:
98
+ output.info(match.source)
99
+
100
+
101
+ def policies_publish(
102
+ ctx: typer.Context,
103
+ policy_id: str = typer.Argument(..., help="Policy id (letters, numbers, '.', '_', '-')."),
104
+ source: Optional[str] = typer.Argument(
105
+ None,
106
+ help="Path to the policy source, @path, or - for stdin. Omit to paste it.",
107
+ ),
108
+ description: str = typer.Option("", "--description", help="One-line description."),
109
+ no_verify: bool = typer.Option(
110
+ False, "--no-verify", help="Skip the JavaScript syntax check before publishing."
111
+ ),
112
+ ) -> None:
113
+ """Publish a policy — mints a NEW VERSION; it never edits one in place.
114
+
115
+ The source is parse-checked with node before it is sent. Nothing downstream
116
+ does this: the server validates the id and a size ceiling, and a broken
117
+ policy otherwise fails on the machine at enforcement time. `--no-verify`
118
+ skips it; a host without node publishes with a warning rather than a block.
119
+
120
+ Source can come from a path, `@path`, a pipe, `-`, or an interactive paste
121
+ when you give none and stdin is a terminal.
122
+
123
+ **Publishing deploys nothing.** A new version sits unused until
124
+ `fp fleet deploy` puts it on a machine. Needs `policies:write`.
125
+ With `--json`: the created version plus `carriers` — a map of machine id to
126
+ the version of this policy it currently runs, so a harness can tell what a
127
+ publish left behind without a second call.
128
+
129
+ Examples:
130
+
131
+ * `fp policies publish no-force-push ./rule.mjs`
132
+ * `cat rule.mjs | fp policies publish no-force-push`
133
+ * `fp policies publish no-force-push -` — read stdin explicitly
134
+ """
135
+ state: AppState = ctx.obj
136
+ deny_in_key_mode(state, "policies publish", _KEY_MODE_REASON)
137
+ cctx = require_auth(state)
138
+
139
+ def _paste_prompt() -> None:
140
+ output.hint("paste the policy source, then press Ctrl-D")
141
+
142
+ try:
143
+ text = read_source(source, prompt=_paste_prompt)
144
+ except RefUsageError as exc:
145
+ raise click.UsageError(str(exc))
146
+ except RefError as exc:
147
+ raise ApiError(str(exc))
148
+ if not text.strip():
149
+ raise ApiError("policy source is empty — nothing to publish")
150
+
151
+ # Nothing downstream parses this. The server checks the id and a size
152
+ # ceiling; the machines find out at enforcement time, which is the worst
153
+ # place for a syntax error to surface. `--no-verify` exists because a
154
+ # machine without node should still be able to publish, not because
155
+ # skipping is ever a good idea.
156
+ if not no_verify:
157
+ syn = check_syntax(text)
158
+ if not syn.ok:
159
+ raise ApiError(
160
+ f"{policy_id} is not parseable JavaScript — refusing to publish it:\n"
161
+ f"{syn.message}",
162
+ hint="fix the syntax, or pass --no-verify to publish it anyway",
163
+ )
164
+ if not syn.checked and not output.is_json():
165
+ output.warn(syn.message)
166
+
167
+ created = api.publish_policy(cctx, policy_id, text, description)
168
+
169
+ # Which machines already carry this policy, and at which version. Publishing
170
+ # deploys nothing, so this is the one thing the card must not guess at: it
171
+ # used to state "not deployed anywhere" unconditionally, which was wrong for
172
+ # every policy that already had a version in the field.
173
+ carriers = {
174
+ d.machine_id: ref.version
175
+ for d in api.list_deployments(cctx)
176
+ for ref in d.policies
177
+ if ref.id == policy_id
178
+ }
179
+ if output.is_json():
180
+ # `syntax` included, exactly as `policies test` does. `SyntaxResult.checked`
181
+ # exists so that "we did not look" can never render as "we looked and it
182
+ # passed" — and the only report of it was gated on `not output.is_json()`,
183
+ # so on the automated path an UNCHECKED publish was byte-identical to a
184
+ # verified one. A CI container without node published unparsed source,
185
+ # the harness read success, and the syntax error surfaced at enforcement
186
+ # time on the machines — the one place `policy_check`'s docstring exists
187
+ # to move it away from.
188
+ output.emit_json({**created.to_dict(), "carriers": carriers, "syntax": syn.to_dict()})
189
+ return
190
+ output.render_policy_published(created, carriers=carriers,
191
+ source_bytes=len(text.encode("utf-8")))
192
+
193
+
194
+ def policies_enable(
195
+ ctx: typer.Context,
196
+ policy_id: str = typer.Argument(..., help="Policy id."),
197
+ yes: bool = typer.Option(False, "--yes", "-y", help="Skip the confirmation prompt. The prompt only appears on an interactive terminal: under --json, or with stdin redirected, this command proceeds without asking."),
198
+ ) -> None:
199
+ """Re-enable a disabled policy, restoring it to the machines that lost it.
200
+
201
+ The exact inverse of `disable`: the server puts the policy back into every
202
+ deployment it was removed from, advancing each machine's generation again.
203
+ Nothing needs redeploying by hand.
204
+
205
+ Needs `policies:write`. With `--json`: `{id, disabled, archived,
206
+ machinesUpdated}` — `machinesUpdated` counts the deployments rewritten, and
207
+ matches the count the preceding `disable` reported.
208
+
209
+ Example:
210
+
211
+ * `fp policies enable no-force-push --yes`
212
+ """
213
+ state: AppState = ctx.obj
214
+ deny_in_key_mode(state, "policies enable", _KEY_MODE_REASON)
215
+ cctx = require_auth(state)
216
+ # Confirmed, like its exact inverse. `disable` took `--yes` and prompted;
217
+ # this fired the moment it was typed, with no prompt and no way to withhold
218
+ # one — on a fleet-wide mutation with the same blast radius in the opposite
219
+ # direction: re-arming a policy can start denying tool calls on every machine
220
+ # at its next poll. It was the only deployment-mutating command in the CLI
221
+ # with neither (`fleet deploy`, `fleet rollback`, `policies disable` and
222
+ # `policies delete` all confirm), and a mistyped id reached the server
223
+ # unchecked. Calm glyph rather than the destructive ⚠, matching `users
224
+ # enable`: this is restorative, not dangerous — but it is not a read.
225
+ if not _write.confirm_action(
226
+ state, "enable policy", policy_id,
227
+ consequence=("it is added back to every deployment it was removed from, "
228
+ "minting a new generation on each"),
229
+ assume_yes=yes, glyph="↑", color=theme.ACCENT,
230
+ ):
231
+ if output.is_json():
232
+ output.emit_json({"cancelled": True})
233
+ else:
234
+ output.print_cancelled()
235
+ return
236
+ res = api.set_policy_enabled(cctx, policy_id, True)
237
+ if output.is_json():
238
+ output.emit_json(res)
239
+ return
240
+ output.policy_lifecycle_changed(policy_id, "enabled")
241
+
242
+
243
+ def policies_disable(
244
+ ctx: typer.Context,
245
+ policy_id: str = typer.Argument(..., help="Policy id."),
246
+ yes: bool = typer.Option(False, "--yes", "-y", help="Skip the confirmation prompt. The prompt only appears on an interactive terminal: under --json, or with stdin redirected, this command proceeds without asking."),
247
+ ) -> None:
248
+ """Disable a policy. It is removed from every deployment carrying it.
249
+
250
+ Not just "machines stop enforcing it": the server reissues each affected
251
+ machine's deployment WITHOUT this policy, advancing that machine's
252
+ generation. `fp fleet history` shows the reissue as an ordinary entry.
253
+
254
+ `policies enable` is the exact inverse: it puts the policy back into every
255
+ deployment it was removed from, so nothing needs redeploying by hand.
256
+
257
+ Needs `policies:write`. With `--json`: `{id, disabled, archived,
258
+ machinesUpdated}` — `machinesUpdated` is how many deployments were rewritten
259
+ to drop it, and is the number to check if you expected this to be a no-op.
260
+
261
+ Example:
262
+
263
+ * `fp policies disable no-force-push --yes`
264
+ """
265
+ state: AppState = ctx.obj
266
+ deny_in_key_mode(state, "policies disable", _KEY_MODE_REASON)
267
+ cctx = require_auth(state)
268
+ if not _write.confirm_destructive(
269
+ state, "disable policy", policy_id,
270
+ consequence=("it is REMOVED from every deployment carrying it, minting a new "
271
+ "generation on each; `policies enable` puts it back the same way"),
272
+ assume_yes=yes,
273
+ ):
274
+ if output.is_json():
275
+ output.emit_json({"cancelled": True})
276
+ else:
277
+ output.print_cancelled()
278
+ return
279
+ res = api.set_policy_enabled(cctx, policy_id, False)
280
+ if output.is_json():
281
+ output.emit_json(res)
282
+ return
283
+ output.policy_lifecycle_changed(policy_id, "disabled")
284
+
285
+
286
+ def policies_delete(
287
+ ctx: typer.Context,
288
+ policy_id: str = typer.Argument(..., help="Policy id."),
289
+ yes: bool = typer.Option(False, "--yes", "-y", help="Skip the confirmation prompt. The prompt only appears on an interactive terminal: under --json, or with stdin redirected, this command proceeds without asking."),
290
+ ) -> None:
291
+ """Archive a policy. This cannot be undone from the CLI.
292
+
293
+ Archiving hides it from `policies list` and from future deployments. A
294
+ machine already carrying it keeps enforcing it until something redeploys —
295
+ deleting is not a way to stop enforcement everywhere, and `disable` is.
296
+
297
+ Needs `policies:write`. With `--json`: `{id, disabled, archived,
298
+ machinesUpdated}`, or `{"cancelled": true}` if you decline.
299
+
300
+ Example:
301
+
302
+ * `fp policies delete old-rule --yes`
303
+ """
304
+ state: AppState = ctx.obj
305
+ deny_in_key_mode(state, "policies delete", _KEY_MODE_REASON)
306
+ cctx = require_auth(state)
307
+ if not _write.confirm_destructive(
308
+ state, "archive policy", policy_id,
309
+ consequence=("machines already carrying it keep enforcing until redeployed — "
310
+ "`policies disable` is what stops enforcement"),
311
+ assume_yes=yes,
312
+ ):
313
+ if output.is_json():
314
+ output.emit_json({"cancelled": True})
315
+ else:
316
+ output.print_cancelled()
317
+ return
318
+ res = api.delete_policy(cctx, policy_id)
319
+ if output.is_json():
320
+ output.emit_json(res)
321
+ return
322
+ output.policy_lifecycle_changed(policy_id, "archived")
323
+
324
+
325
+ def policies_test(
326
+ ctx: typer.Context,
327
+ source: Optional[str] = typer.Argument(
328
+ None, help="Policy file, @path, or - for stdin. Omit to paste it."
329
+ ),
330
+ tool: str = typer.Option("Bash", "--tool", help="Tool name the hook fired for."),
331
+ command: Optional[str] = typer.Option(None, "--command", help="Bash command to test against."),
332
+ file_path: Optional[str] = typer.Option(None, "--file", help="File path to test against."),
333
+ event: str = typer.Option("PreToolUse", "--event", help="Hook event type."),
334
+ expect: Optional[str] = typer.Option(
335
+ None, "--expect",
336
+ help="Assert the decision is allow/deny/instruct; exit 1 if it is not.",
337
+ ),
338
+ ) -> None:
339
+ """Run a policy locally and print what it would decide. No server, no fleet.
340
+
341
+ Executes the real file — bare `import { deny } from "failproofai"` and all —
342
+ against a context you describe, and prints allow / deny / instruct per
343
+ registered policy. Nothing is published and nothing is installed.
344
+
345
+ Needs `node` on PATH. This is a dry run, not the enforcement path: it proves
346
+ the policy parses, registers and decides for the input given. It cannot
347
+ prove the daemon feeds it the same context.
348
+
349
+ With `--json`: `{ok, decision, policies:[{name, decision, reason}]}` — the
350
+ overall `decision` is the strictest any policy returned.
351
+
352
+ Examples:
353
+
354
+ * `fp policies test ./rule.mjs --command "git push --force"`
355
+ * `fp policies test ./rule.mjs --tool Write --file .env`
356
+ """
357
+ # No `require_auth` and no `deny_in_key_mode`: this command talks to node,
358
+ # not to the dashboard, so it works logged out and under an API key alike.
359
+
360
+ def _paste_prompt() -> None:
361
+ output.hint("paste the policy source, then press Ctrl-D")
362
+
363
+ try:
364
+ text = read_source(source, prompt=_paste_prompt)
365
+ except RefUsageError as exc:
366
+ raise click.UsageError(str(exc))
367
+ except RefError as exc:
368
+ raise ApiError(str(exc))
369
+ if not text.strip():
370
+ raise ApiError("policy source is empty — nothing to test")
371
+
372
+ # Checked before the syntax check runs, so a bad --expect reports itself
373
+ # rather than being masked by whatever node says about the file. A usage
374
+ # error should never depend on the content of an argument.
375
+ if expect is not None and expect not in ("allow", "deny", "instruct"):
376
+ raise typer.BadParameter(
377
+ f"invalid --expect value {expect!r}; choose one of allow, deny, instruct"
378
+ )
379
+
380
+ syn = check_syntax(text)
381
+ if not syn.ok:
382
+ if output.is_json():
383
+ output.emit_json({"ok": False, "syntax": syn.to_dict(), "policies": []})
384
+ raise typer.Exit(1)
385
+ raise ApiError(f"the policy is not parseable JavaScript:\n{syn.message}")
386
+
387
+ run = run_policy(text, tool=tool, command=command, file_path=file_path, event=event)
388
+
389
+ # A policy that correctly denies is a SUCCESSFUL test, so the decision does
390
+ # not set the exit code on its own — otherwise `policies test` would fail
391
+ # whenever the policy worked. `--expect` is how CI asserts instead: it turns
392
+ # "what did it decide" into "did it decide what I meant".
393
+ met = expect is None or run.decision == expect
394
+ if output.is_json():
395
+ output.emit_json({**run.to_dict(), "syntax": syn.to_dict(),
396
+ "expected": expect, "met": met})
397
+ raise typer.Exit(0 if (run.ok and met) else 1)
398
+ if not run.ok:
399
+ raise ApiError(run.error)
400
+ output.render_policy_test(run, tool=tool, command=command, file_path=file_path,
401
+ expected=expect)
402
+ if not met:
403
+ raise typer.Exit(1)
404
+
405
+
406
+ def policies_compose(
407
+ ctx: typer.Context,
408
+ prompt: str = typer.Argument(..., help="What the policy should do, in plain English."),
409
+ out: Optional[str] = typer.Option(None, "--out", help="Write the draft to this file."),
410
+ publish_as: Optional[str] = typer.Option(
411
+ None, "--publish", help="Publish the draft immediately under this policy id."
412
+ ),
413
+ ) -> None:
414
+ """Draft a policy from a description, using the Cloud assistant.
415
+
416
+ The assistant writes the source; **you** decide whether it ships. By default
417
+ the draft is printed and nothing else happens — a generated policy that
418
+ deploys itself is a generated policy nobody read.
419
+
420
+ `--out` saves it; `--publish <id>` publishes it, still syntax-checked first.
421
+ Needs `policies:write` — for the draft as well as the publish. The route is
422
+ `POST /api/agent/compose-policy`, which the dashboard exports as
423
+ `withAuth("policies:write", …)`; `agent:use` gates the assistant's other
424
+ routes (chat, answer, conversations) and is NOT checked on this one. So a
425
+ role holding only `agent:use` is refused here, and one holding
426
+ `policies:write` without it works. Session-only.
427
+
428
+ With `--json`: `{prompt, source, syntax, published}`.
429
+
430
+ Examples:
431
+
432
+ * `fp policies compose "block force pushes to main"`
433
+ * `fp policies compose "deny reading .env" --out env.mjs`
434
+ """
435
+ state: AppState = ctx.obj
436
+ deny_in_key_mode(state, "policies compose", _KEY_MODE_REASON)
437
+ cctx = require_auth(state)
438
+
439
+ with output.thinking("drafting…", enabled=not output.is_json()):
440
+ res = api.compose_policy(cctx, prompt)
441
+ source = (res or {}).get("source") or (res or {}).get("policy") or ""
442
+ if not source.strip():
443
+ raise ApiError(
444
+ "the assistant returned no policy source",
445
+ hint="check `fp agent health` — the assistant may not be configured here",
446
+ )
447
+
448
+ syn = check_syntax(source)
449
+
450
+ # Saved BEFORE anything that can fail. `--out` used to run after the
451
+ # publish, so a publish that was refused — bad syntax, no `policies:write`,
452
+ # a network blip — threw away the draft the user had just paid an assistant
453
+ # to write, with no way to get that same text back.
454
+ if out:
455
+ try:
456
+ with open(out, "w", encoding="utf-8") as fh:
457
+ fh.write(source)
458
+ except OSError as exc:
459
+ raise ApiError(f"cannot write {out}: {exc.strerror or exc}")
460
+
461
+ published = None
462
+ if publish_as:
463
+ if not syn.ok:
464
+ raise ApiError(
465
+ f"the drafted policy is not parseable JavaScript — refusing to publish:\n"
466
+ f"{syn.message}",
467
+ hint=("fix it and publish it with `fp policies publish`"
468
+ if out else "save it with --out, fix it, then publish"),
469
+ )
470
+ published = api.publish_policy(cctx, publish_as, source, f"drafted: {prompt}"[:500])
471
+
472
+ if output.is_json():
473
+ output.emit_json({
474
+ "prompt": prompt, "source": source, "syntax": syn.to_dict(),
475
+ "published": published.to_dict() if published else None,
476
+ "savedTo": out,
477
+ })
478
+ return
479
+ output.render_composed_policy(prompt, source, syn, saved_to=out)
480
+ if published:
481
+ output.policy_published_brief(published)
482
+
483
+
484
+ def register(app: typer.Typer) -> None:
485
+ policies_app = typer.Typer(
486
+ no_args_is_help=True,
487
+ rich_markup_mode="markdown",
488
+ context_settings={"help_option_names": ["-h", "--help"]},
489
+ help="Write and manage cloud-managed policies (list / show / publish / enable / disable / delete).",
490
+ )
491
+ policies_app.command("list", epilog=GLOBALS_EPILOG)(policies_list)
492
+ policies_app.command("show", epilog=GLOBALS_EPILOG)(policies_show)
493
+ policies_app.command("publish", epilog=GLOBALS_EPILOG)(policies_publish)
494
+ policies_app.command("enable", epilog=GLOBALS_EPILOG)(policies_enable)
495
+ policies_app.command("disable", epilog=GLOBALS_EPILOG)(policies_disable)
496
+ policies_app.command("delete", epilog=GLOBALS_EPILOG)(policies_delete)
497
+ policies_app.command("test", epilog=GLOBALS_EPILOG)(policies_test)
498
+ policies_app.command("compose", epilog=GLOBALS_EPILOG)(policies_compose)
499
+ app.add_typer(policies_app, name="policies")