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,407 @@
1
+ """API key provisioning: keys list / show / create / update / disable / regenerate.
2
+
3
+ Keys are referenced by their **name** (unique within the org) across ``show`` / ``update`` /
4
+ ``disable`` / ``regenerate``. The group mirrors the ``users`` visual + permission language: a
5
+ boxed list, a ``show`` identity card + grouped permissions panel, and the SAME
6
+ ``--permission-set`` / ``--add`` / ``--remove`` flags as ``users create`` / ``users update``.
7
+
8
+ A KEY stores a **flat permission list** (no persisted role/set), so ``--permission-set`` is
9
+ expanded **client-side** to seed the grants (matching the dashboard's key SetPicker); the
10
+ human-only permissions (``keys:update`` / ``orgs:admin``) are stripped from a seed and rejected
11
+ from an explicit ``--add`` (the server's ``key_assignable`` would 422 them).
12
+
13
+ The CLI generates the secret for ``create`` (the server never echoes it back) and prints it
14
+ exactly once. ``regenerate`` rotates the secret and prints the new one once. Secrets go to
15
+ **stdout** (capturable); the "shown once" warning goes to stderr.
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import secrets
21
+ import sys
22
+ from typing import List, Optional
23
+
24
+ import typer
25
+
26
+ from .. import _click_compat as click # the Click Typer is running; see _click_compat
27
+ from .. import client as api
28
+ from .. import output, permissions
29
+ from .._context import (
30
+ GLOBALS_EPILOG,
31
+ AppState,
32
+ deny_in_key_mode,
33
+ require_auth,
34
+ resolve_fields,
35
+ )
36
+ from ..errors import ForbiddenError, NotFoundError
37
+ from ..models import ApiKey
38
+ from ..permissions import PermissionTokenError
39
+ from ..permissions import parse_permission_tokens as _parse_permissions
40
+ from . import _write
41
+
42
+ # ``PermissionTokenError`` / ``_parse_permissions`` live in ``permissions.py`` (shared with
43
+ # ``users``); re-exported here under their historical names so the keys flow + its tests keep
44
+ # importing them from this module.
45
+ __all__ = ["PermissionTokenError", "_parse_permissions", "register"]
46
+
47
+
48
+ def _resolve_key_or_exit(state: AppState, keys, name: str) -> ApiKey:
49
+ """Resolve a unique key NAME (or id) to its key, raising a typed error the central
50
+ chokepoint renders (JSON envelope under ``--json``, red box otherwise): none → exit 6,
51
+ several → exit 2."""
52
+ return _write.resolve_one(keys, name, kind="key", list_cmd="keys list")
53
+
54
+
55
+ def _parse_key_tokens_or_exit(state: AppState, tokens) -> List[str]:
56
+ """Expand the compact ``slug:act1.act2`` ``--add`` / ``--remove`` tokens for a KEY (empty when
57
+ none given). A malformed/unknown token — or a human-only permission (``keys:update`` /
58
+ ``orgs:admin``) — → a clean usage error (exit 2), before any create/update."""
59
+ if not tokens:
60
+ return []
61
+ try:
62
+ return permissions.parse_key_permission_tokens(tokens)
63
+ except PermissionTokenError as exc:
64
+ raise click.UsageError(str(exc))
65
+
66
+
67
+ def _expand_key_set_or_exit(state: AppState, cctx, set_name: str) -> List[str]:
68
+ """Expand a ``--permission-set`` NAME → its **key-assignable** permissions, to seed a key's
69
+ flat grants (keys have no persisted set). Resolves against the ORG's sets (fetched, so custom
70
+ sets work like the dashboard's SetPicker), falling back to the built-in presets if that read
71
+ is unavailable. Human-only perms are stripped. Unknown set → clean error + exit 2."""
72
+ try:
73
+ sets = api.list_permission_sets(cctx)
74
+ except (ForbiddenError, NotFoundError):
75
+ sets = {}
76
+ if set_name in sets:
77
+ return permissions.key_assignable_only(sets[set_name])
78
+ if set_name in permissions.PRESETS:
79
+ return permissions.key_assignable_only(permissions.PRESETS[set_name])
80
+ available = sorted(set(sets) | (set(permissions.PRESETS) - {"clear"}))
81
+ raise click.UsageError(
82
+ f'unknown permission set "{set_name}". available: {", ".join(available)}'
83
+ )
84
+
85
+
86
+ def keys_list(
87
+ ctx: typer.Context,
88
+ show_id: bool = typer.Option(False, "--show-id", help="Prepend a short key-id column (the full id is always in --json)."),
89
+ fields: Optional[str] = typer.Option(None, "--fields", help="Comma-separated subset of fields. e.g. `id,name,permissions`."),
90
+ ) -> None:
91
+ """List the org's API keys (metadata only — secrets are never returned), active keys first.
92
+
93
+ Shows `created · name · permissions · status` in a boxed table — **active keys sort to the
94
+ top** (then revoked), each group newest-first. The raw key id is hidden by default (use
95
+ `--show-id` for a short id, or `--json` for the full id). Needs `keys:read`. With `--json`:
96
+ `{"keys": [{id, name, permissions, created_at, revoked_at}]}`.
97
+
98
+ Example:
99
+
100
+ * `fp keys list`
101
+ * `fp --json keys list`
102
+ """
103
+ state: AppState = ctx.obj
104
+ cctx = require_auth(state)
105
+ keys = api.list_keys(cctx)
106
+ cols = resolve_fields(fields, ApiKey)
107
+ if state.json:
108
+ payload = output.project_dicts(keys, cols) if cols else keys
109
+ output.emit_json({"keys": payload})
110
+ return
111
+ if cols:
112
+ # `--fields` asks for specific raw columns → the generic table (no bespoke styling).
113
+ output.print_table(list(cols), output.project_rows(keys, cols), title=f"API keys ({len(keys)})")
114
+ return
115
+ output.render_keys(keys, show_id=show_id)
116
+ output.keys_footer(keys)
117
+
118
+
119
+ def keys_show(
120
+ ctx: typer.Context,
121
+ name: str = typer.Argument(..., help="Key name (unique within the org)."),
122
+ ) -> None:
123
+ """Show one key's identity and full permissions — like `users show`, for an API key.
124
+
125
+ Renders an identity card (name, created date, permission count, status) then the shared
126
+ grouped permissions panel with **all** the key's grants. Referenced by **name**. Needs
127
+ `keys:read`. With `--json`: the full key object `{id, name, permissions, created_at, revoked_at}`.
128
+
129
+ Example:
130
+
131
+ * `fp keys show ci-bot`
132
+ """
133
+ state: AppState = ctx.obj
134
+ cctx = require_auth(state)
135
+ key = _resolve_key_or_exit(state, api.list_keys(cctx), name)
136
+ if state.json:
137
+ output.emit_json(key)
138
+ return
139
+ output.render_key_show(key)
140
+
141
+
142
+ def keys_create(
143
+ ctx: typer.Context,
144
+ name: str = typer.Argument(..., help="Human-readable key name (unique within the org)."),
145
+ permission_set: Optional[str] = typer.Option(None, "--permission-set", help="Role to seed the key from — a permission set: `read-only`, `standard`, `admin`, or a custom set your org defines in the dashboard. The set is expanded into the key's grants (human-only perms are dropped). Omit for no base role."),
146
+ add: Optional[List[str]] = typer.Option(None, "--add", help="Grant extra permissions on top of the set, as `slug:action.action` tokens (dotted actions expand: `events:read.add` → `events:read`, `events:add`). Several via comma, repeated flag, or a quoted group: `--add events:read,keys:read` · `--add a --add b` · `--add \"a b\"`."),
147
+ remove: Optional[List[str]] = typer.Option(None, "--remove", help="Drop permissions from the set, same `slug:action.action` token format as --add (comma / repeated / quoted)."),
148
+ ) -> None:
149
+ """Create an API key and reveal its secret **once**.
150
+
151
+ Grant permissions exactly like `users create`: start from a role with `--permission-set`
152
+ (a built-in `read-only` / `standard` / `admin`, or a custom org set — expanded into the key's
153
+ grants), then fine-tune with `--add` / `--remove`. The effective grants are
154
+ `(set ∪ added) − removed`. `--add` / `--remove` take the compact `slug:action.action` token
155
+ format (dotted actions expand). Human-only permissions (`keys:update`) can't be granted to a
156
+ key.
157
+
158
+ The secret is generated locally; the server stores only a hash. Needs `keys:create`. With
159
+ `--json`: `{id, name, permissions, created_at, key}` — `key` is the only place the secret
160
+ appears, and `permissions` is the expanded flat list.
161
+
162
+ Examples:
163
+
164
+ * `fp keys create ci-bot --permission-set read-only` — a read-only key
165
+ * `fp keys create deployer --add events:read.add,keys:read` — just the listed grants
166
+ * `fp keys create ops --permission-set standard --add keys:create --remove agent:use` — a role, tuned
167
+ * `fp keys create ci-bot --permission-set read-only | pbcopy` — pipe captures just the secret
168
+ """
169
+ state: AppState = ctx.obj
170
+ if not name.strip():
171
+ raise typer.BadParameter("key name must not be empty.", param_hint="NAME")
172
+ parsed_add = _parse_key_tokens_or_exit(state, add)
173
+ parsed_remove = _parse_key_tokens_or_exit(state, remove)
174
+ both = sorted(set(parsed_add) & set(parsed_remove))
175
+ if both:
176
+ raise typer.BadParameter(f"{', '.join(both)} given to both --add and --remove.")
177
+ cctx = require_auth(state)
178
+ if any(k.name == name for k in api.list_keys(cctx)): # names are unique
179
+ raise click.UsageError(f'a key named "{name}" already exists')
180
+ base = _expand_key_set_or_exit(state, cctx, permission_set) if permission_set else []
181
+ flat = sorted((set(base) | set(parsed_add)) - set(parsed_remove))
182
+ secret = secrets.token_hex(32) # 64 hex chars, mirrors the dashboard's generateToken()
183
+ result = api.create_key(cctx, name=name, key=secret, permissions=flat)
184
+ _write.record_action("api_key_created", resource="key", success=True, permission_count=len(flat))
185
+ perms = result.permissions or flat
186
+ if state.json:
187
+ output.emit_json({"id": result.id, "name": result.name, "permissions": perms,
188
+ "created_at": result.created_at, "key": secret})
189
+ return
190
+ if not sys.stdout.isatty():
191
+ print(secret) # piped/redirected → just the secret (capturable)
192
+ return
193
+ output.render_key_created(result) # green identity card
194
+ output.render_created_secret_box(secret) # the secret, shown once
195
+ output.permissions_box(perms) # the grouped grants
196
+
197
+
198
+ def keys_update(
199
+ ctx: typer.Context,
200
+ name: str = typer.Argument(..., help="Key name to update (unique within the org)."),
201
+ permission_set: Optional[str] = typer.Option(None, "--permission-set", help="Reseed the key from a permission set: `read-only`, `standard`, `admin`, or a custom org set. REPLACES the key's grants with the set (then applies any --add/--remove). Human-only perms are dropped."),
202
+ add: Optional[List[str]] = typer.Option(None, "--add", help="Grant permissions, same `slug:action.action` token format as `keys create` (dotted actions expand; comma / repeated flag / quoted compose). Incremental — merged into the key's CURRENT grants, unless --permission-set is also given."),
203
+ remove: Optional[List[str]] = typer.Option(None, "--remove", help="Revoke permissions, same `slug:action.action` token format as --add. Incremental — applied to the key's CURRENT grants, unless --permission-set is also given."),
204
+ 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."),
205
+ ) -> None:
206
+ """Change an API key's permissions and show the diff — like `users update`, by key name.
207
+
208
+ Two ways to use it (combine if you like):
209
+
210
+ * **Reseed from a role** — `--permission-set <set>` replaces the key's grants with that set
211
+ (a built-in `read-only` / `standard` / `admin`, or a custom org set); add `--add`/`--remove`
212
+ to tune it.
213
+ * **Tweak incrementally** — `--add` / `--remove` **alone** adjust the key's *current* grants.
214
+ Both take the compact `slug:action.action` token format (dotted actions expand). Human-only
215
+ permissions (`keys:update`) can't be granted to a key.
216
+
217
+ The CLI reads the current grants, computes the result `(set ∪ added) − removed`, and shows a
218
+ git-style diff — added green, removed struck-through, unchanged dim. It confirms first (default
219
+ no; `--yes` skips); a no-op exits without calling the server. The key keeps working — only its
220
+ permissions change. Needs `keys:update`. With `--json`:
221
+ `{id, name, permissions, created_at, revoked_at, added, removed}`.
222
+
223
+ Examples:
224
+
225
+ * `fp keys update ci-bot --add keys:read` — grant on top of current grants
226
+ * `fp keys update ci-bot --remove events:add,agent:use` — revoke a couple of grants
227
+ * `fp keys update ci-bot --permission-set standard --yes` — reseed from the standard role
228
+ """
229
+ state: AppState = ctx.obj
230
+ # The only `keys` subcommand an API key can never run: it needs `keys:update`, and
231
+ # `Permission::key_assignable` forbids that grant on ANY key (a bearer key may
232
+ # create keys, never edit one). So this is unreachable by construction, not just
233
+ # unlikely — say so here instead of letting the server's 403 imply "ask for the
234
+ # permission", which nobody can grant.
235
+ deny_in_key_mode(
236
+ state,
237
+ "keys update",
238
+ "it needs the keys:update permission, which cannot be granted to any API key",
239
+ )
240
+ if permission_set is None and not add and not remove:
241
+ raise typer.BadParameter("nothing to update — pass --permission-set, --add, and/or --remove.")
242
+ parsed_add = _parse_key_tokens_or_exit(state, add)
243
+ parsed_remove = _parse_key_tokens_or_exit(state, remove)
244
+ both = sorted(set(parsed_add) & set(parsed_remove))
245
+ if both:
246
+ raise typer.BadParameter(f"{', '.join(both)} given to both --add and --remove.")
247
+ cctx = require_auth(state)
248
+ key = _resolve_key_or_exit(state, api.list_keys(cctx), name)
249
+ before = set(key.permissions)
250
+ add_set, remove_set = set(parsed_add), set(parsed_remove)
251
+
252
+ if permission_set is not None:
253
+ # Reseed: the set is the base; --add/--remove are fresh tweaks on top.
254
+ base = _expand_key_set_or_exit(state, cctx, permission_set)
255
+ after = sorted((set(base) | add_set) - remove_set)
256
+ else:
257
+ # Incremental: apply the deltas to the key's CURRENT flat grants.
258
+ after = sorted((before | add_set) - remove_set)
259
+ after_set = set(after)
260
+ added, removed = sorted(after_set - before), sorted(before - after_set)
261
+
262
+ if not added and not removed: # no-op: don't call the server, don't prompt
263
+ if state.json:
264
+ output.emit_json({"id": key.id, "name": key.name, "permissions": sorted(before),
265
+ "created_at": key.created_at, "revoked_at": key.revoked_at,
266
+ "added": [], "removed": []})
267
+ else:
268
+ output.key_no_change()
269
+ return
270
+
271
+ proceed = (not _write.should_prompt(state, yes)) or output.confirm_key_update(
272
+ key.name, len(added), len(removed))
273
+ if not proceed:
274
+ if state.json:
275
+ output.emit_json({"cancelled": True})
276
+ else:
277
+ output.print_cancelled("permissions unchanged")
278
+ return
279
+
280
+ result = api.update_key(cctx, key.id, permissions=after)
281
+ final = set(result.permissions)
282
+ added, removed = sorted(final - before), sorted(before - final)
283
+ _write.record_action("api_key_updated", resource="key", success=True, permission_count=len(final))
284
+ if state.json:
285
+ output.emit_json({"id": result.id, "name": result.name, "permissions": sorted(final),
286
+ "created_at": result.created_at, "revoked_at": result.revoked_at,
287
+ "added": added, "removed": removed})
288
+ return
289
+ output.render_key_updated(result, added=added, removed=removed, union=sorted(before | final))
290
+
291
+
292
+ def keys_disable(
293
+ ctx: typer.Context,
294
+ name: str = typer.Argument(..., help="Key name to disable (unique within the org)."),
295
+ 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."),
296
+ ) -> None:
297
+ """Disable (revoke) an API key by name. This cannot be undone.
298
+
299
+ Resolves the unique key name, confirms (amber, default no), then revokes it — anything
300
+ using the key stops working immediately. Needs `keys:disable`. With `--json`:
301
+ `{"name", "status": "disabled"}` (or `{"cancelled": true}` on a declined prompt).
302
+
303
+ Example:
304
+
305
+ * `fp keys disable "ci-bot" --yes`
306
+ """
307
+ state: AppState = ctx.obj
308
+ cctx = require_auth(state)
309
+ key = _resolve_key_or_exit(state, api.list_keys(cctx), name)
310
+ if key.revoked_at: # already disabled — a no-op, not an error
311
+ if state.json:
312
+ output.emit_json({"name": key.name, "status": "disabled"})
313
+ else:
314
+ output.key_already_disabled(key.name)
315
+ return
316
+ if not _write.confirm_destructive(
317
+ state, "disable the key", key.name,
318
+ consequence="this revokes the key immediately — anything using it will stop working",
319
+ assume_yes=yes,
320
+ ):
321
+ if state.json:
322
+ output.emit_json({"cancelled": True})
323
+ else:
324
+ output.print_cancelled()
325
+ return
326
+ api.disable_key(cctx, key.id)
327
+ _write.record_action("api_key_disabled", resource="key", success=True, destructive=True)
328
+ if state.json:
329
+ output.emit_json({"name": key.name, "status": "disabled"})
330
+ else:
331
+ output.key_disabled(key.name)
332
+
333
+
334
+ def keys_regenerate(
335
+ ctx: typer.Context,
336
+ name: str = typer.Argument(..., help="Key name to rotate the secret for (unique within the org)."),
337
+ 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."),
338
+ ) -> None:
339
+ """Rotate an API key's secret by name and reveal the new secret **once**.
340
+
341
+ Resolves the unique key name, confirms (amber, default no), then rotates — the old secret
342
+ stops working immediately. The new secret is shown once: piping captures just the raw
343
+ secret (`fp keys regenerate admin -y | pbcopy`); interactively it's shown in a box.
344
+ Needs `keys:regenerate`. With `--json`: `{"name", "key"}` — the new secret under `key`, the
345
+ same field `keys create` uses (or `{"cancelled": true}` on a declined prompt).
346
+
347
+ Example:
348
+
349
+ * `fp keys regenerate "ci-bot" -y`
350
+ """
351
+ state: AppState = ctx.obj
352
+ cctx = require_auth(state)
353
+ key = _resolve_key_or_exit(state, api.list_keys(cctx), name)
354
+ if not _write.confirm_destructive(
355
+ state, "regenerate the secret for key", key.name,
356
+ consequence="this revokes the current secret immediately and can't be undone",
357
+ assume_yes=yes,
358
+ ):
359
+ if state.json:
360
+ output.emit_json({"cancelled": True})
361
+ else:
362
+ output.print_cancelled()
363
+ return
364
+ secret = api.regenerate_key(cctx, key.id)
365
+ _write.record_action("api_key_regenerated", resource="key", success=True)
366
+ if state.json:
367
+ output.emit_json({"name": key.name, "key": secret})
368
+ return
369
+ if sys.stdout.isatty():
370
+ output.render_secret_box(key.name, secret) # pretty box (with secret) → stderr
371
+ else:
372
+ print(secret) # piped/redirected → bare secret to stdout, capturable
373
+
374
+
375
+ _KEYS_GROUP_HELP = """Provision and manage API keys — list, inspect, create, and adjust their permissions.
376
+
377
+ Keys are referenced by **name** (unique in the org). A key carries a flat set of permissions;
378
+ grant them from a role (`--permission-set`) plus `--add` / `--remove` overrides — the same
379
+ language as `users`. The secret is shown **once**, at create / regenerate.
380
+
381
+ **Subcommands:** `list` · `show` · `create` · `update` · `disable` · `regenerate`
382
+
383
+ **Examples:**
384
+
385
+ * `fp keys list` — all keys, active first
386
+ * `fp keys show ci-bot` — one key's identity + full grants
387
+ * `fp keys create ci-bot --permission-set read-only` — invite a key with a role
388
+ * `fp keys update ci-bot --add keys:read --remove agent:use` — tweak grants
389
+ * `fp keys regenerate ci-bot -y` — rotate the secret (shown once)
390
+ * `fp keys disable ci-bot` — revoke it
391
+ """
392
+
393
+
394
+ def register(app: typer.Typer) -> None:
395
+ keys_app = typer.Typer(
396
+ no_args_is_help=True,
397
+ rich_markup_mode="markdown",
398
+ context_settings={"help_option_names": ["-h", "--help"]},
399
+ help=_KEYS_GROUP_HELP,
400
+ )
401
+ keys_app.command("list", epilog=GLOBALS_EPILOG)(keys_list)
402
+ keys_app.command("show", epilog=GLOBALS_EPILOG)(keys_show)
403
+ keys_app.command("create", epilog=GLOBALS_EPILOG)(keys_create)
404
+ keys_app.command("update", epilog=GLOBALS_EPILOG)(keys_update)
405
+ keys_app.command("disable", epilog=GLOBALS_EPILOG)(keys_disable)
406
+ keys_app.command("regenerate", epilog=GLOBALS_EPILOG)(keys_regenerate)
407
+ app.add_typer(keys_app, name="keys")
@@ -0,0 +1,63 @@
1
+ """fp list — discover the distinct values behind the dashboard's filter dropdowns.
2
+
3
+ Each subcommand returns a flat list of strings for one facet (the same data that powers the
4
+ dashboard's dropdowns), handy for finding valid filter values to pass to `sessions` / `events`.
5
+ Every value comes from a per-org cached endpoint, so it stays cheap to call.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import typer
11
+
12
+ from .. import client as api
13
+ from .. import output
14
+ from .._context import GLOBALS_EPILOG, AppState, require_auth
15
+
16
+ # Friendly `list <name>` -> (facet key in client._FACET_PATHS, required permission, one-liner,
17
+ # title description). The order here is the order shown in `fp list --help`.
18
+ _LIST_KINDS = {
19
+ "envs": ("environments", "events:read or evaluations:read", "Environments seen across events.", "seen across events"),
20
+ "agents": ("agent_ids", "events:read or evaluations:read", "Agent ids seen across events.", "seen across events"),
21
+ "event_types": ("event_types", "events:read or evaluations:read", "Event types (agent_start, tool_use, error, …).", "seen across events"),
22
+ "score_filters": ("score_filters", "evaluations:read", "Evaluation score keys / metrics (for `--score KEY:MIN..MAX`).", "evaluation score keys"),
23
+ "models": ("models", "events:read", "Model names seen across events.", "seen across events"),
24
+ "hooks": ("hook_names", "events:read", "Hook names seen across events.", "seen across events"),
25
+ "tools": ("tool_names", "events:read", "Tool names seen across events.", "seen across events"),
26
+ "error_types": ("error_types", "events:read", "Error types seen across events.", "seen across events"),
27
+ }
28
+
29
+ def _make_list_cmd(name: str, facet_key: str, perm: str, summary: str, description: str):
30
+ """Build the handler for one `list <name>` subcommand (a thin wrapper over the shared
31
+ facet fetch, so all nine share one code path)."""
32
+
33
+ def _cmd(ctx: typer.Context) -> None:
34
+ state: AppState = ctx.obj
35
+ cctx = require_auth(state)
36
+ values = api.list_facet(cctx, facet_key)
37
+ if state.json:
38
+ output.emit_json({"kind": name, "values": values})
39
+ return
40
+ output.render_value_list(name, values, description=description)
41
+
42
+ _cmd.__name__ = f"list_{name}"
43
+ _cmd.__doc__ = (
44
+ f"{summary}\n\n"
45
+ f" Needs `{perm}`. With `--json`: `{{\"kind\": \"{name}\", \"values\": [...]}}`.\n\n"
46
+ f" Example:\n\n"
47
+ f" * `fp --json list {name} | jq '.values'`"
48
+ )
49
+ return _cmd
50
+
51
+
52
+ def register(app: typer.Typer) -> None:
53
+ list_app = typer.Typer(
54
+ no_args_is_help=True,
55
+ rich_markup_mode="markdown",
56
+ context_settings={"help_option_names": ["-h", "--help"]},
57
+ help="List the distinct values behind the dashboard's filter dropdowns. Subcommands: "
58
+ "**envs**, **agents**, **event_types**, **score_filters**, **models**, **hooks**, "
59
+ "**tools**, **error_types**.",
60
+ )
61
+ for name, (facet_key, perm, summary, description) in _LIST_KINDS.items():
62
+ list_app.command(name, epilog=GLOBALS_EPILOG)(_make_list_cmd(name, facet_key, perm, summary, description))
63
+ app.add_typer(list_app, name="list")