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,259 @@
1
+ # FailproofAI Cloud CLI (`fp`)
2
+
3
+ A command-line client for the **FailproofAI Cloud** API. It lets a developer —
4
+ or the coding agent working alongside them — authenticate and query agent
5
+ sessions, event logs, and evaluations from the terminal, with a `--json` flag on
6
+ every command for scripting.
7
+
8
+ > **The package is `fp-cloud-cli`; the command is `fp`.** They differ because `fp` was
9
+ > already taken on PyPI. This is also distinct from `failproofai` on npm, which is
10
+ > the Enforcement CLI — that one runs inside the agent loop and decides what an
11
+ > agent may do; this one reads back what it did.
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ pipx install fp-cloud-cli # recommended (isolated)
17
+ # or: uv tool install fp-cloud-cli / pip install fp-cloud-cli
18
+ ```
19
+
20
+ Then the command is `fp`:
21
+
22
+ ```bash
23
+ fp --version
24
+ fp help
25
+ ```
26
+
27
+ For development in this repo:
28
+
29
+ ```bash
30
+ cd fp-cloud-cli
31
+ uv sync --extra dev
32
+ uv run fp --help
33
+ ```
34
+
35
+ ## Authentication
36
+
37
+ The CLI talks to your dashboard (set `--base-url` or `FP_DASHBOARD_URL`) and logs in with
38
+ an emailed one-time code:
39
+
40
+ ```bash
41
+ fp login --email you@example.com
42
+ # enter the 6-digit code; the session is stored in
43
+ # ~/.failproofai/fpcli/cli-auth.json (mode 0600)
44
+ fp whoami
45
+ fp logout
46
+ ```
47
+
48
+ Sessions expire (24h by default); re-run `fp login` when prompted.
49
+
50
+ ## Working across orgs (multi-tenant)
51
+
52
+ Your account can belong to more than one org. The active org is chosen **at login** and saved:
53
+
54
+ ```bash
55
+ fp login --org acme # pick the tenant at login (saved for later commands)
56
+ fp orgs list # your orgs + your role in each (active one marked)
57
+ fp orgs switch globex # switch the active org (pass a slug…)
58
+ fp orgs switch # …or omit it to pick from a list (in a terminal)
59
+ fp orgs current # which org you're acting as right now (identity card)
60
+ fp orgs perms # your permissions in the active org (grouped by resource)
61
+ fp --org globex sessions # override for a single command
62
+ ```
63
+
64
+ If you belong to exactly one org it's selected automatically. If you belong to several, you
65
+ pick at login (or with `orgs switch`); pass `--org` to choose non-interactively. A slug you
66
+ can't access (non-existent, or not yours) is rejected rather than saved. The active org is
67
+ sent as the `X-AgentEye-Org` header on every request, and your permissions are resolved per
68
+ org. (All tenant commands live under one group: `orgs list` / `orgs switch` / `orgs current` /
69
+ `orgs perms`.)
70
+
71
+ ## Commands
72
+
73
+ **Query & observability**
74
+
75
+ ```text
76
+ fp sessions [--since 24h] [--status error] [--agent-id <id>] [--all] # runs: time/env/agent/session/status
77
+ fp evals [--score helpfulness:..0.5] [--all] # eval results + scores
78
+ fp evals --aggregate [--since 7d] # rolled-up eval health (status mix + per-metric score stats)
79
+ fp events --session-id <id> [--event-type tool_use,tool_result] [--env prod] [--all]
80
+ fp errors [--since 24h] [--error-type TimeoutError] [--all] # list errored events
81
+ fp errors --aggregate [--since 7d] # error summary (count + sessions/agents/last seen)
82
+ fp list <thing> # discover dropdown values to filter on:
83
+ # envs · agents · event_types · score_filters · models · hooks · tools · error_types
84
+ ```
85
+
86
+ **Manage your org** (each gated by the matching permission)
87
+
88
+ ```text
89
+ fp keys list|show|create|update|disable|regenerate # API keys (secret shown once)
90
+ fp users list|show|create|update|disable|enable
91
+ fp settings list|schema|set
92
+ fp alerts list|show|create|update|delete|test
93
+ fp issues list|count|show|ack|assign|resolve|comment-add|comment-list|comment-delete|subscribe|subscribers|unsubscribe|open
94
+ fp audits list|show|create|edit|delete|run|runs|findings|finding # scheduled audits
95
+ fp audits ack|assign|resolve|dismiss|mute|reopen # triage a finding
96
+ fp audits context-show|context-set|context-refresh # reference context
97
+ fp usage # org usage for the metering window
98
+ ```
99
+
100
+ **Analytics & assistant**
101
+
102
+ ```text
103
+ fp query list|show|create|update|delete|run|schema # saved SQL + ad-hoc runner
104
+ fp agent health|models|chats|show|rename|delete|ask
105
+ # agent models → models available for --model (with the default marked)
106
+ # agent ask "…" → starts a NEW chat, answers + persists, prints the chat id
107
+ # agent ask --chat <id> "…" → continue that chat (shows in the dashboard; 1st Q auto-titles)
108
+ # agent chats|show <id>|rename <id> --title …|delete <id> → manage saved chats
109
+ fp version | help
110
+ ```
111
+
112
+ **Mutations are non-interactive-safe.** Create/update/delete prompt for confirmation in a
113
+ terminal, but auto-skip the prompt under `--json` or when stdin isn't a TTY (so scripts/agents
114
+ never hang). Pass `--yes`/`-y` to skip it explicitly. Request bodies can be supplied with
115
+ `--file payload.json` (or `--file -` for stdin) on `alerts` and `settings` — mutually
116
+ exclusive with the discrete flags. `users create`/`update` take only the discrete
117
+ flags (`--permission-set`, `--add`, `--remove`). (Saved-query SQL uses `--sql @file.sql`.)
118
+
119
+ Every command and subcommand has `--help` / `-h`; `fp -h` documents auth, exit codes, and
120
+ the global options. **Global options go before the command** (`fp --json events`, not
121
+ `fp events --json`).
122
+
123
+ Add `--json` for machine-readable output, and `--fields` to project just the keys you need:
124
+
125
+ ```bash
126
+ fp --json events --session-id run-001 --all | jq '.events[].payload'
127
+ fp --json sessions --since 7d --fields session_id,status,scores
128
+ ```
129
+
130
+ ### Cloud-managed policies
131
+
132
+ Three commands for the three jobs the dashboard splits across three pages —
133
+ `fp policies` writes a policy version, `fp fleet` decides which machines run it,
134
+ `fp guardrails summary` reports what it actually blocked.
135
+
136
+ ```bash
137
+ fp policies publish no-force-push ./rule.mjs # path, @path, a pipe, - or a paste
138
+ fp fleet deploy ci-runner-01 --add no-force-push
139
+ fp guardrails summary --since 24h
140
+ ```
141
+
142
+ **A deploy REPLACES a machine's whole policy set.** The server takes the full
143
+ list and does not merge, so `fleet deploy` reads what the machine currently runs,
144
+ applies your `--add`/`--remove`, prints the complete resulting set, and writes
145
+ that. Use `--set` only when you mean "exactly these, drop the rest".
146
+
147
+ ```bash
148
+ fp fleet deploy ci-runner-01 \
149
+ --add no-force-push \ # keeps its pinned version if already deployed
150
+ --add prod-guard@1:observe \ # id@version:effect
151
+ --remove old-rule
152
+ ```
153
+
154
+ Three things worth knowing before you script it:
155
+
156
+ * A bare `--add` of a policy the machine already runs keeps its **pinned
157
+ version**. Pass `id@version` to move it — a pin is usually deliberate.
158
+ * The endpoint has no lock. The CLI records the deployment generation it read and
159
+ **refuses** if the write does not land at exactly one higher, because that means
160
+ somebody deployed in between and a replace does not merge.
161
+ * The exit code separates your mistake from the server's answer. A malformed ref,
162
+ `--set` alongside `--add`/`--remove`, or no flags at all is **2**; a ref that
163
+ parses but names a policy that does not exist is **1**; an unknown machine is
164
+ **6**. Branch on those rather than on the message.
165
+
166
+ `fp fleet diff` shows intent versus delivery: a machine can be deployed-to and
167
+ still enforcing an older set until it next polls. It refuses a machine id nobody
168
+ has reported under rather than rendering it as an empty fleet.
169
+
170
+ These commands are **session-only** (`fp login`). They are absent from the
171
+ versioned API an API key authenticates against, so `--api-key` exits 2 with the
172
+ reason rather than failing at the request.
173
+
174
+ ## Configuration
175
+
176
+ | Setting | Flag | Env var | Default |
177
+ |---|---|---|---|
178
+ | Dashboard URL | `--base-url` | `FP_DASHBOARD_URL` | `https://app.befailproof.ai` |
179
+ | Active org/tenant | `--org` | `FP_ORG` | chosen at login; saved in `~/.failproofai/fpcli/cli-auth.json` |
180
+ | Session token | `--token` | `FP_TOKEN` | from `~/.failproofai/fpcli/cli-auth.json` |
181
+ | API key (CI) | `--api-key` | `FP_API_KEY` | none; never written to disk |
182
+ | JSON output | `--json` | `FP_JSON` | off |
183
+ | Skip TLS verification | `--insecure` / `--secure` | `FP_INSECURE` | off (saved at login) |
184
+ | Disable usage telemetry | _(none)_ | `FP_ANALYTICS_DISABLED` (or `DO_NOT_TRACK`) | off — [this build sends nothing](#telemetry) |
185
+
186
+ Precedence is **flag > environment variable > config file > built-in default**. A fresh
187
+ install points at the hosted product with no configuration; set `--base-url` or
188
+ `FP_DASHBOARD_URL` for a self-hosted or dev instance and it is saved after `login`.
189
+
190
+ The session lives at `~/.failproofai/fpcli/cli-auth.json` (mode `0600`). The directory
191
+ is resolved as `FP_HOME` > `$FAILPROOFAI_HOME/fpcli` > `~/.failproofai/fpcli` — `FP_HOME`
192
+ names the CLI's own directory and is used as-is, so an existing export keeps addressing
193
+ the same place; `FAILPROOFAI_HOME` names the shared home root, so `fpcli/` is appended.
194
+
195
+ The CLI only ever creates. It will bring `~/.failproofai` into existence on a machine
196
+ that has never run the Enforcement CLI, and leaves a populated one exactly as it found
197
+ it — nothing here removes or rewrites a path it does not own. The file is registered in
198
+ that home's layout (`src/hooks/fp-home.ts`) and classified `user-typed`, which is what
199
+ keeps a layout migration from dropping it.
200
+
201
+ The Python SDK writes its spool under `$FAILPROOFAI_HOME/custom-agents/events`,
202
+ otherwise `~/.failproofai/custom-agents/events` — it moved onto the shared umbrella in
203
+ the same release that renamed this CLI. `FAILPROOFAI_HOME` relocates it the same way it
204
+ relocates this CLI's own directory; what no longer works is `AGENTEYE_HOME`, and nothing
205
+ moves the spool *off* the umbrella except `configure(base_dir=...)` in the application.
206
+ `failproofaid` still drains `~/.agenteye/events` as well, for SDKs old enough to write
207
+ there.
208
+
209
+ > **Upgrading from a version that used `~/.fp/cli.json`?** Nothing to do — the old
210
+ > session is adopted on your next command, so you are not signed out. It is copied, not
211
+ > moved, so rolling back to an older `fp` still works; remove `~/.fp/` yourself once you
212
+ > are happy.
213
+
214
+ For a dashboard with a self-signed or internal TLS certificate, add `--insecure` to skip
215
+ certificate verification (saved at login, so you set it once). This disables protection
216
+ against man-in-the-middle attacks — prefer a valid certificate outside internal/testing use.
217
+
218
+ ## Telemetry
219
+
220
+ **Telemetry is currently disabled and this build sends nothing.**
221
+ `TELEMETRY_DISABLED` is `True` in `fp_cli/analytics_config.py`: when the analytics
222
+ host is unreachable the send path stalls every command for ~5s — the shutdown flush
223
+ is bounded, but the client build and first connect attempt are not — so it stays off
224
+ until that path is fully non-blocking. Nothing was removed; re-enabling is one
225
+ constant.
226
+
227
+ The rest of this section describes what it collects **if** it is re-enabled, so you
228
+ can review it in advance rather than discover it in a release note:
229
+
230
+ - which command ran (including its subcommand, e.g. `keys create`), success/exit
231
+ status and duration, the **names** of flags used, and a per-action event for
232
+ mutations (e.g. `api_key_created`, `query_run`) carrying only static names/enums
233
+ and coarse counts;
234
+ - **no data, URLs, tokens, emails, ids, SQL, key secrets, or query values are ever
235
+ sent**, and operators are identified only by an opaque id.
236
+
237
+ `FP_ANALYTICS_DISABLED=1` (or the cross-tool `DO_NOT_TRACK=1`) opts out, and keeps
238
+ working as an opt-out if it is ever switched back on. See
239
+ <https://docs.befailproof.ai/reference/cloud-cli> for the full privacy details.
240
+
241
+ ## Exit codes
242
+
243
+ | Code | Meaning |
244
+ |---|---|
245
+ | 0 | Success |
246
+ | 1 | Unexpected error (e.g. an unhandled server status) |
247
+ | 2 | Usage error (bad arguments) |
248
+ | 3 | Cannot reach the dashboard |
249
+ | 4 | Not logged in / session expired |
250
+ | 5 | Authenticated but missing permission |
251
+ | 6 | Resource not found |
252
+
253
+ ## Tests
254
+
255
+ ```bash
256
+ cd fp-cloud-cli
257
+ uv run --extra dev pytest
258
+ ```
259
+
@@ -0,0 +1,10 @@
1
+ """FailproofAI Cloud CLI — a command-line client for the FailproofAI Cloud API.
2
+
3
+ The query layer lives in :mod:`fp_cli.client` as pure functions that take a
4
+ ``ClientContext`` and return plain dataclasses. They never print and never import
5
+ Typer/Rich, so a future MCP server can wrap them with zero duplication.
6
+ """
7
+
8
+ from ._version import __version__
9
+
10
+ __all__ = ["__version__"]
@@ -0,0 +1,4 @@
1
+ from .app import main_entry
2
+
3
+ if __name__ == "__main__":
4
+ main_entry()
@@ -0,0 +1,64 @@
1
+ """The Click that Typer is actually running. Import Click through here, never directly.
2
+
3
+ Typer 0.26 vendored Click into ``typer._click`` and dropped its dependency on the pip
4
+ ``click`` distribution. The vendored classes are *different class objects* from pip
5
+ Click's, so every place we hand Click an object, or ask Click about one, breaks when
6
+ the two disagree — and each break is silent, because the code still imports, still
7
+ compiles, and every happy path still passes:
8
+
9
+ * ``ClickException`` — Typer's command runner catches only *its* Click's exception
10
+ class. Errors subclassing pip Click's escape **uncaught**: a typed failure that
11
+ should print ``✗ …`` and exit 5 exits **1 with an empty stderr**, and the
12
+ ``rich_format_error`` hook in ``app.py`` (reached only *after* that catch) never
13
+ runs. Same for the ``UsageError``/``BadParameter`` we raise by hand.
14
+ * ``Abort`` — ``typer.prompt`` raises its own Click's ``Abort`` on closed stdin, so a
15
+ pip-Click ``except click.Abort`` stops matching and the clean "no TTY, pass a slug"
16
+ usage error becomes a bare abort.
17
+ * Options — Typer 0.26+ has no ``Option`` class in its vendored Click *at all*: every
18
+ option in a Typer-built tree is a ``typer.core.TyperOption``, subclassing
19
+ ``Parameter`` directly. ``isinstance(param, click.Option)`` is then quietly always
20
+ False, which emptied the telemetry flag catalog (``analytics_registry``) while its
21
+ own anti-drift test stayed green — the test asked the same broken question.
22
+
23
+ So: resolve the Click that Typer imported, and speak that one.
24
+ ``tests/test_click_compat.py`` asserts the package never imports ``click`` directly
25
+ again, and that our errors are still the class Typer catches.
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ try:
31
+ # typer >= 0.26. pip `click` may well still be installed — it is simply not the
32
+ # Click in play, so binding to it here would reintroduce the whole class of bug.
33
+ from typer._click import ClickException, Command, Parameter
34
+ from typer._click.exceptions import Abort, BadParameter, UsageError
35
+ except ImportError: # typer < 0.26 drives the pip `click` distribution directly
36
+ from click import ( # type: ignore[assignment]
37
+ Abort,
38
+ BadParameter,
39
+ ClickException,
40
+ Command,
41
+ Parameter,
42
+ UsageError,
43
+ )
44
+
45
+ __all__ = [
46
+ "Abort",
47
+ "BadParameter",
48
+ "ClickException",
49
+ "Command",
50
+ "Parameter",
51
+ "UsageError",
52
+ "is_option",
53
+ ]
54
+
55
+
56
+ def is_option(param: Parameter) -> bool:
57
+ """True if ``param`` is an option (``--flag``), not a positional argument.
58
+
59
+ Class identity cannot answer this across both Clicks — the vendored one has no
60
+ ``Option`` class to test against — so read the ``param_type_name`` that Click sets
61
+ on every parameter (``"option"`` / ``"argument"``). That holds for pip Click's
62
+ ``Option`` and for ``TyperOption`` alike.
63
+ """
64
+ return getattr(param, "param_type_name", None) == "option"
@@ -0,0 +1,332 @@
1
+ """Shared command-layer state and helpers.
2
+
3
+ Kept separate from ``app.py`` so command modules can import these without a
4
+ circular dependency (``app.py`` imports the command modules).
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import dataclasses
10
+ import math
11
+ import re
12
+ from dataclasses import dataclass
13
+ from typing import List, Optional, Sequence, Tuple
14
+
15
+ from . import _click_compat as click # the Click Typer is running; see _click_compat
16
+ from . import config as cfgmod
17
+ from . import dates as _dates
18
+
19
+ # `AuthMode` is DEFINED in `client.py`, not here, even though it is this layer that
20
+ # resolves it: the import runs `_context` -> `client` (below), and `client` needs the
21
+ # enum at runtime for its bearer-vs-cookie branch — defining it here would make that
22
+ # a cycle. Re-exported so `from ._context import AuthMode` reads naturally beside
23
+ # AppState, which is where most callers want it.
24
+ from .client import AuthMode, ClientContext
25
+ from .errors import AuthError, KeyModeUnsupportedError
26
+
27
+
28
+ @dataclass
29
+ class AppState:
30
+ json: bool
31
+ base_url: Optional[str]
32
+ token: Optional[str]
33
+ timeout: float
34
+ config: cfgmod.CliConfig
35
+ insecure: bool = False
36
+ org: Optional[str] = None # active tenant slug (flag > env > config)
37
+ # The EXPLICITLY-supplied tenant (global `--org` or `FP_ORG`), before
38
+ # the saved-config fallback. `login` uses this so a *saved* tenant never
39
+ # silently bypasses the interactive org picker — only an explicit choice does.
40
+ # Key mode reuses it as the ONLY org it will ever send (see `build_context`).
41
+ org_explicit: Optional[str] = None
42
+ # The bearer credential in key mode. NEVER written to `cli.json` — see
43
+ # `resolve_auth`.
44
+ api_key: Optional[str] = None
45
+ # Which credential this invocation carries. Defaults to NONE so an AppState
46
+ # built by another path (tests, embedders) is never silently treated as key
47
+ # mode; the transport reads it directly, and everything that is not API_KEY
48
+ # takes the cookie path.
49
+ auth_mode: AuthMode = AuthMode.NONE
50
+
51
+
52
+ def resolve_auth(
53
+ *,
54
+ api_key: Optional[str],
55
+ api_key_on_cli: bool,
56
+ token: Optional[str],
57
+ token_on_cli: bool,
58
+ saved_token: Optional[str],
59
+ ) -> Tuple[AuthMode, Optional[str], Optional[str]]:
60
+ """Resolve the one credential this invocation uses → ``(mode, api_key, token)``.
61
+
62
+ Precedence, highest first::
63
+
64
+ --api-key AND --token -> usage error, exit 2 (never guess)
65
+ --api-key -> key mode
66
+ --token -> session mode
67
+ FP_API_KEY -> key mode (a key env var beats a token env var)
68
+ FP_TOKEN -> session mode
69
+ cli.json session_token -> session mode
70
+ nothing -> AuthMode.NONE (require_auth then exits 4)
71
+
72
+ ``*_on_cli`` distinguishes a flag from its env var, which the *values* cannot:
73
+ an explicit ``--token`` has to beat ``FP_API_KEY`` while
74
+ ``FP_API_KEY`` beats ``FP_TOKEN``. Click's
75
+ ``ctx.get_parameter_source`` is the only thing that knows the difference.
76
+
77
+ ``--api-key ""`` (an unset CI variable spelled out) means "no override": the mode
78
+ stays KEY with an empty credential, so `require_auth` raises instead of quietly
79
+ acting as whichever human is logged in on this machine. That mirrors the
80
+ established ``--token ""`` rule exactly.
81
+
82
+ The key is returned for this process only and is never persisted: a session token
83
+ expires in ~24h, which bounds the blast radius of a leaked `cli.json`; an API key
84
+ is valid until someone revokes it. There is also no honest revocation path from
85
+ here — `keys disable` needs `keys:disable`, which a scoped CI key will not hold —
86
+ so a "clear the saved key" command could not actually revoke anything.
87
+ """
88
+ if api_key_on_cli and token_on_cli:
89
+ raise click.UsageError(
90
+ "--api-key and --token are mutually exclusive: --api-key authenticates as an "
91
+ "API key against /v1, --token as a signed-in user session. Pass exactly one."
92
+ )
93
+ if api_key_on_cli:
94
+ return AuthMode.API_KEY, api_key, None
95
+ if token_on_cli:
96
+ return AuthMode.SESSION, None, token
97
+ # Neither flag was given: whatever Click resolved came from the environment.
98
+ # (Click treats an empty env var as unset, so `FP_API_KEY=""` falls
99
+ # through to the next rung rather than becoming an empty-credential key mode.)
100
+ if api_key is not None:
101
+ return AuthMode.API_KEY, api_key, None
102
+ if token is not None:
103
+ return AuthMode.SESSION, None, token
104
+ if saved_token:
105
+ return AuthMode.SESSION, None, saved_token
106
+ return AuthMode.NONE, None, None
107
+
108
+
109
+ def deny_in_key_mode(state: "AppState", command: str, reason: str) -> None:
110
+ """Fail ``command`` with exit 2 when this invocation carries an API key.
111
+
112
+ Called as the FIRST statement of every command an API key cannot perform, so the
113
+ CLI never opens a connection it already knows will fail — a 401/403 from the
114
+ server would be a much worse explanation than the real one.
115
+ """
116
+ if state.auth_mode is AuthMode.API_KEY:
117
+ raise KeyModeUnsupportedError(
118
+ f"`fp {command}` does not work with an API key — {reason}.",
119
+ hint="drop --api-key / FP_API_KEY and sign in with fp login",
120
+ )
121
+
122
+
123
+ def resolved_base_url(state: AppState) -> str:
124
+ """The effective dashboard URL.
125
+
126
+ The app callback already resolves flag/env > saved config > the public
127
+ default (`config.DEFAULT_BASE_URL`), so `state.base_url` is normally set.
128
+ This falls back to the same default for any AppState built by another path
129
+ (tests, embedders), so the CLI always has a URL to talk to.
130
+ """
131
+ return state.base_url or cfgmod.DEFAULT_BASE_URL
132
+
133
+
134
+ def _org_header(state: AppState) -> Optional[str]:
135
+ """The tenant slug to send as ``X-AgentEye-Org``.
136
+
137
+ In KEY mode only an EXPLICIT ``--org`` / ``FP_ORG`` is ever sent. The saved
138
+ `cli.json` org belongs to whichever human logged in on this machine and has no
139
+ bearing on which org a CI key was minted for; sending it would silently ask for
140
+ another tenant's data and get a 403 that reads like a missing permission.
141
+
142
+ (The reverse trap is real too and `whoami` is the pre-flight for it: an
143
+ instance-scoped key with no `--org` resolves server-side to the DEFAULT org and
144
+ answers with that org's data, no error anywhere.)
145
+ """
146
+ if state.auth_mode is AuthMode.API_KEY:
147
+ return state.org_explicit
148
+ return state.org
149
+
150
+
151
+ def build_context(state: AppState) -> ClientContext:
152
+ return ClientContext(
153
+ base_url=resolved_base_url(state),
154
+ token=state.token,
155
+ timeout=state.timeout,
156
+ verify=not state.insecure,
157
+ org=_org_header(state),
158
+ api_key=state.api_key,
159
+ auth_mode=state.auth_mode,
160
+ )
161
+
162
+
163
+ def require_auth(state: AppState) -> ClientContext:
164
+ """Return a client context, or raise if no URL is set / not authenticated."""
165
+ base = resolved_base_url(state) # the URL is the prerequisite — check it first
166
+ if state.auth_mode is AuthMode.API_KEY:
167
+ # `--api-key ""` lands here: key mode, no credential. It must NOT fall back
168
+ # to a saved cookie session (see `resolve_auth`), so this is an auth failure.
169
+ if not state.api_key:
170
+ raise AuthError(
171
+ "No API key supplied. Pass --api-key <key> or set FP_API_KEY."
172
+ )
173
+ # No local expiry check: an API key carries no expiry the CLI can see, and the
174
+ # server is the only authority on whether it is still live.
175
+ return ClientContext(
176
+ base_url=base,
177
+ api_key=state.api_key,
178
+ auth_mode=AuthMode.API_KEY,
179
+ timeout=state.timeout,
180
+ verify=not state.insecure,
181
+ org=_org_header(state),
182
+ )
183
+ if not state.token:
184
+ # A pre-move file with no usable session in it (expired, or only ever
185
+ # held a base_url) reaches here after adoption declined to carry
186
+ # anything. Name it, so the upgrade is not blamed for the logout.
187
+ if cfgmod.legacy_install_detected():
188
+ raise AuthError(
189
+ "Not logged in. Run fp login.\n"
190
+ f"The config moved to {cfgmod.config_path()}; "
191
+ f"{cfgmod.legacy_config_path()} held no usable session to carry "
192
+ "over. It is left in place — remove it when convenient."
193
+ )
194
+ raise AuthError("Not logged in. Run fp login.")
195
+ # Only enforce local expiry when the token came from the stored config; an
196
+ # explicit --token / env override has no known expiry, so trust it.
197
+ if state.token == state.config.session_token and cfgmod.is_expired(state.config):
198
+ raise AuthError("Session expired. Run fp login.")
199
+ return ClientContext(
200
+ base_url=base,
201
+ token=state.token,
202
+ timeout=state.timeout,
203
+ verify=not state.insecure,
204
+ org=_org_header(state),
205
+ )
206
+
207
+
208
+ def resolve_dates(
209
+ since: Optional[str], ts_from: Optional[str], ts_to: Optional[str]
210
+ ) -> Tuple[Optional[str], Optional[str]]:
211
+ try:
212
+ return _dates.resolve_range(since, ts_from, ts_to)
213
+ except ValueError as exc:
214
+ raise click.BadParameter(str(exc))
215
+
216
+
217
+ def resolve_fields(raw: Optional[str], model_cls: type) -> Optional[List[str]]:
218
+ """Parse a ``--fields`` CSV into a validated list of model field names (or None).
219
+
220
+ Field names must match the dataclass (and thus the ``--json``) keys of the
221
+ model; unknown names raise a usage error listing the valid set.
222
+ """
223
+ if not raw:
224
+ return None
225
+ valid = [f.name for f in dataclasses.fields(model_cls)]
226
+ chosen = [f.strip() for f in raw.split(",") if f.strip()]
227
+ unknown = [f for f in chosen if f not in valid]
228
+ if unknown:
229
+ raise click.BadParameter(
230
+ f"unknown field(s): {', '.join(unknown)}. Valid fields: {', '.join(valid)}"
231
+ )
232
+ return chosen
233
+
234
+
235
+ def collect_multi(values: Optional[Sequence[str]]) -> Optional[List[str]]:
236
+ """Normalize a repeatable + comma-separated CLI option into one flat, de-duplicated list.
237
+
238
+ The single reusable helper behind every multi-value filter. Typer hands us a list with
239
+ one entry per repeated flag (``--env prod --env staging`` → ``["prod", "staging"]``), and
240
+ each entry may itself be a comma-separated group (``--env prod,staging`` → ``["prod,staging"]``).
241
+ This splits every entry on commas, trims surrounding whitespace (so ``--env "prod, staging"``
242
+ works), drops empties (so a trailing comma ``--env prod,`` adds nothing), and de-duplicates
243
+ while preserving first-seen order. Returns ``None`` when nothing usable remains, so an unset
244
+ or blank option stays ``None`` and the client drops the param (unchanged single-value path).
245
+
246
+ A single value still yields the obvious one-item list (``--env prod`` → ``["prod"]``), which
247
+ the client serializes back to a bare ``environment=prod`` — fully backward compatible.
248
+ """
249
+ if not values:
250
+ return None
251
+ out: List[str] = []
252
+ seen: set = set()
253
+ for raw in values:
254
+ for part in str(raw).split(","):
255
+ v = part.strip()
256
+ if v and v not in seen:
257
+ seen.add(v)
258
+ out.append(v)
259
+ return out or None
260
+
261
+
262
+ def validate_choice(
263
+ value: Optional[str], allowed: Sequence[str], *, flag: str
264
+ ) -> Optional[str]:
265
+ """Return ``value`` if it's None or one of ``allowed``; else a usage error (exit 2).
266
+
267
+ Keeps enum-style flags (``--status``) failing fast client-side with a clear
268
+ message, consistent with ``--order``/``--source``/``--kind`` — rather than the
269
+ server's opaque HTTP 400 (exit 1).
270
+ """
271
+ if value is None or value in allowed:
272
+ return value
273
+ raise click.BadParameter(
274
+ f"'{value}' is not valid for {flag}. Choose one of: {', '.join(allowed)}.",
275
+ param_hint=flag,
276
+ )
277
+
278
+
279
+ def validate_limit(limit: Optional[int], *, flag: str = "--limit") -> None:
280
+ """Reject a non-positive row limit up front with a clean usage error (exit 2), rather
281
+ than passing ``0``/negative through to the server, which silently defaults/clamps it to
282
+ a confusing result. Mirrors ``validate_choice`` / ``validate_score_filters``."""
283
+ if limit is not None and limit <= 0:
284
+ raise click.BadParameter("must be a positive integer (at least 1).", param_hint=flag)
285
+
286
+
287
+ def validate_score_filters(values: Optional[Sequence[str]]) -> None:
288
+ """Validate ``--score`` values are ``KEY:MIN..MAX`` (either bound optional).
289
+
290
+ Without this a malformed value (no ``:`` or no ``..``) is silently sent and
291
+ dropped server-side, returning the UNFILTERED set — a silent footgun. Raises a
292
+ usage error (exit 2) on a bad value. Accepts e.g. ``helpfulness:0.5..0.8``,
293
+ ``x:..0.5``, ``y:0.9..``.
294
+ """
295
+ for v in values or []:
296
+ key, sep, rng = v.partition(":")
297
+ ok = bool(sep) and bool(key.strip()) and ".." in rng
298
+ if ok:
299
+ lo, _, hi = rng.partition("..")
300
+ # Both bounds empty (`helpfulness:..`) is meaningless: the server silently
301
+ # drops it and returns the UNFILTERED set, so reject it client-side too.
302
+ if lo == "" and hi == "":
303
+ ok = False
304
+ for bound in (lo, hi):
305
+ if bound != "":
306
+ try:
307
+ # `float("nan")`/`float("inf")` succeed but the server silently
308
+ # drops the filter — reject non-finite bounds too.
309
+ if not math.isfinite(float(bound)):
310
+ ok = False
311
+ break
312
+ except ValueError:
313
+ ok = False
314
+ break
315
+ if not ok:
316
+ raise click.BadParameter(
317
+ f"'{v}' is not a valid score filter. Use KEY:MIN..MAX (either bound "
318
+ "optional), e.g. helpfulness:0.5..0.8, tool_efficiency:..0.3, factuality:0.9..",
319
+ param_hint="--score",
320
+ )
321
+
322
+
323
+ # Appended to every subcommand's --help so an agent that jumps straight to
324
+ # `fp <command> -h` still learns the argument order + where the global options go.
325
+ GLOBALS_EPILOG = (
326
+ "Argument order: `fp [GLOBAL OPTIONS] <command> [<subcommand>] [ARGS] [OPTIONS]`. "
327
+ "**Global** options come *before* the command — `--json`, `--base-url`, `--token`, "
328
+ "`--api-key`, `--insecure`/`--secure`, `--timeout`, `--quiet`, `--no-color`. A command's (or "
329
+ "subcommand's) own options come *after* it. "
330
+ "e.g. `fp --json keys create ci-bot --permission-set read-only` — `--json` is global, "
331
+ "`keys` the command, `create` the subcommand, `--permission-set` its option."
332
+ )
@@ -0,0 +1 @@
1
+ __version__ = "0.0.1b1"