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,378 @@
1
+ """Saved SQL queries + ad-hoc runner: query list/show/create/update/delete/run/schema.
2
+
3
+ Runs against the server's read-only analytics pool. SQL can be inline or read from a
4
+ file with ``--sql @path.sql``; run parameters are positional ``$1..$N`` values.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Any, List, Optional
10
+
11
+ import typer
12
+
13
+ from .. import _click_compat as click # the Click Typer is running; see _click_compat
14
+ from .. import client as api
15
+ from .. import output
16
+ from .._context import GLOBALS_EPILOG, AppState, require_auth, resolve_fields, validate_limit
17
+ from ..errors import NotFoundError
18
+ from ..models import SavedQuery
19
+ from . import _write
20
+
21
+
22
+ def _humanize_list(items: List[str]) -> str:
23
+ """``["name","sql","description"]`` → ``name, sql, and description``; one item → itself."""
24
+ if not items:
25
+ return ""
26
+ if len(items) == 1:
27
+ return items[0]
28
+ if len(items) == 2:
29
+ return f"{items[0]} and {items[1]}"
30
+ return ", ".join(items[:-1]) + f", and {items[-1]}"
31
+
32
+
33
+ def _read_sql(value: str) -> str:
34
+ """Inline SQL, or the contents of a file when given as ``@path.sql``."""
35
+ if value.startswith("@"):
36
+ return _write.read_text_arg(value[1:], flag="--sql")
37
+ return value
38
+
39
+
40
+ def _coerce_value(raw: str) -> Any:
41
+ """Best-effort coercion of a run parameter value to int/float/bool/null/str."""
42
+ low = raw.lower()
43
+ if low in ("true", "false"):
44
+ return low == "true"
45
+ if low in ("null", "none"):
46
+ return None
47
+ try:
48
+ return int(raw)
49
+ except ValueError:
50
+ pass
51
+ try:
52
+ return float(raw)
53
+ except ValueError:
54
+ pass
55
+ return raw
56
+
57
+
58
+ def _resolve_query_or_exit(state: AppState, queries, handle: str) -> SavedQuery:
59
+ """Resolve a saved query by **name** (primary), falling back to an exact id match, raising a
60
+ typed error the central chokepoint renders: none → exit 6, several → exit 2."""
61
+ return _write.resolve_one(queries, handle, kind="query", plural="queries", list_cmd="query list")
62
+
63
+
64
+ def query_list(
65
+ ctx: typer.Context,
66
+ show_id: bool = typer.Option(False, "--show-id", help="Prepend a short query-id column (the full id is always in --json)."),
67
+ fields: Optional[str] = typer.Option(None, "--fields", help="Comma-separated subset of raw fields (falls back to a plain table)."),
68
+ ) -> None:
69
+ """List the org's saved queries in a boxed table, newest first.
70
+
71
+ Shows `name · description · created by · created` — the long description is truncated to one
72
+ line (full text in `query show` / `--json`), and `created` is when the query was made (not
73
+ `updated_at`). `name` is the handle `query run`/`query show` take; the raw id is hidden unless
74
+ `--show-id`. Needs `queries:read`. With `--json`: `{"queries": [{id, name, description,
75
+ sql_text, params, created_by, created_at, ...}]}`.
76
+
77
+ Example:
78
+
79
+ * `fp query list`
80
+ """
81
+ state: AppState = ctx.obj
82
+ cctx = require_auth(state)
83
+ queries = api.list_saved_queries(cctx)
84
+ cols = resolve_fields(fields, SavedQuery)
85
+ if state.json:
86
+ payload = output.project_dicts(queries, cols) if cols else queries
87
+ output.emit_json({"queries": payload})
88
+ return
89
+ if cols:
90
+ # `--fields` asks for specific raw columns → the generic table (no bespoke styling).
91
+ output.print_table(list(cols), output.project_rows(queries, cols), title=f"Saved queries ({len(queries)})")
92
+ return
93
+ output.render_queries(queries, show_id=show_id)
94
+
95
+
96
+ def query_show(
97
+ ctx: typer.Context,
98
+ name: str = typer.Argument(..., metavar="NAME", help="Saved query name (or id)."),
99
+ ) -> None:
100
+ """Show one saved query — a metadata card + its full, syntax-highlighted SQL.
101
+
102
+ Referenced by query **name** (a UUID-shaped id is also accepted). The SQL is shown in full with
103
+ line numbers. Not-found → red `✗ no query named "…"`, exit 6. Needs `queries:read`. With
104
+ `--json`: the full `SavedQuery` (raw `sql_text` for piping).
105
+
106
+ Example:
107
+
108
+ * `fp query show q_eval_score_avg`
109
+ """
110
+ state: AppState = ctx.obj
111
+ cctx = require_auth(state)
112
+ q = _resolve_query_or_exit(state, api.list_saved_queries(cctx), name)
113
+ if state.json:
114
+ output.emit_json(q)
115
+ return
116
+ output.render_query_show(q)
117
+
118
+
119
+ def query_create(
120
+ ctx: typer.Context,
121
+ name: str = typer.Argument(..., metavar="NAME", help="Saved query name (unique per org)."),
122
+ sql: str = typer.Option(..., "--sql", help="SQL text, or `@file.sql` to read from a file."),
123
+ description: str = typer.Option("", "--description", help="Optional one-line description."),
124
+ ) -> None:
125
+ """Create a saved query — give it a **name**, the SQL, and an optional description.
126
+
127
+ The query is saved to the org's analytics library; run it later with `fp query run
128
+ <name>`. The SQL can be inline or read from a file with `--sql @file.sql`. A name collision is
129
+ rejected up front. Needs `queries:write`. With `--json`: the created `SavedQuery`
130
+ (`{id, name, description, created_at, sql_text}`).
131
+
132
+ Examples:
133
+
134
+ * `fp query create top-agents --sql "SELECT agent_id, count() FROM analytics.events GROUP BY agent_id"`
135
+ * `fp query create errors-by-env --sql @errs.sql --description "errored events per environment"`
136
+ """
137
+ state: AppState = ctx.obj
138
+ cctx = require_auth(state)
139
+ if any(q.name == name for q in api.list_saved_queries(cctx)): # names are unique per org
140
+ raise click.UsageError(f'a query named "{name}" already exists')
141
+ result = api.create_saved_query(
142
+ cctx, name=name, sql_text=_read_sql(sql), description=description, params=[]
143
+ )
144
+ _write.record_action("saved_query_created", resource="query", success=True)
145
+ if state.json:
146
+ output.emit_json({"id": result.id, "name": result.name, "description": result.description,
147
+ "created_at": result.created_at, "sql_text": result.sql_text})
148
+ return
149
+ output.render_query_created(result)
150
+
151
+
152
+ def query_update(
153
+ ctx: typer.Context,
154
+ name: str = typer.Argument(..., metavar="NAME", help="Saved query name (or id) to update."),
155
+ new_name: Optional[str] = typer.Option(None, "--name", help="Rename the query (defaults to the current name)."),
156
+ sql: Optional[str] = typer.Option(None, "--sql", help="New SQL text, or `@file.sql` (defaults to current)."),
157
+ description: Optional[str] = typer.Option(None, "--description", help="New description (defaults to current)."),
158
+ 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."),
159
+ ) -> None:
160
+ """Update a saved query, referenced by **name** (or a UUID-shaped id).
161
+
162
+ Change any of `--name`, `--sql`, `--description` (pass at least one); fields you omit keep
163
+ their current value (the CLI reads the query first, then saves the merged result). It confirms
164
+ first (default no; `--yes` skips) and shows the updated query as a green card + numbered SQL
165
+ box. A no-op exits without saving. Needs `queries:write`. With `--json`: the updated
166
+ `SavedQuery`.
167
+
168
+ Examples:
169
+
170
+ * `fp query update top-agents --sql @top.sql` — replace the SQL
171
+ * `fp query update top-agents --name agent-totals --description "rows per agent"` — rename + redescribe
172
+ """
173
+ state: AppState = ctx.obj
174
+ if new_name is None and sql is None and description is None:
175
+ raise typer.BadParameter("nothing to update — pass --name, --sql, and/or --description.")
176
+ cctx = require_auth(state)
177
+ queries = api.list_saved_queries(cctx)
178
+ q = _resolve_query_or_exit(state, queries, name)
179
+
180
+ # A rename to an existing name collides (like create's 409).
181
+ if new_name is not None and new_name != q.name and any(o.name == new_name for o in queries):
182
+ raise click.UsageError(f'a query named "{new_name}" already exists')
183
+
184
+ # Read `--sql` exactly ONCE. `@-` is stdin, and stdin can only be drained once: a
185
+ # second `_read_sql(sql)` for the request body returns "", so change detection would
186
+ # compare the real text while the save wrote an empty query — silently, exit 0.
187
+ new_sql = _read_sql(sql) if sql is not None else None
188
+
189
+ # Which fields actually change → the confirm consequence (and no-op detection).
190
+ changed: List[str] = []
191
+ if new_name is not None and new_name != q.name:
192
+ changed.append("name")
193
+ if new_sql is not None and new_sql != q.sql_text:
194
+ changed.append("sql")
195
+ if description is not None and description != q.description:
196
+ changed.append("description")
197
+ if not changed:
198
+ if state.json:
199
+ output.emit_json({"id": q.id, "name": q.name, "description": q.description,
200
+ "created_at": q.created_at, "sql_text": q.sql_text})
201
+ else:
202
+ output.query_no_change()
203
+ return
204
+
205
+ if _write.should_prompt(state, yes):
206
+ if not output.confirm_query_update(q.name, _humanize_list(changed)):
207
+ if state.json:
208
+ output.emit_json({"cancelled": True})
209
+ else:
210
+ output.query_cancelled("nothing changed")
211
+ return
212
+
213
+ result = api.update_saved_query(
214
+ cctx, q.id,
215
+ name=new_name if new_name is not None else q.name,
216
+ sql_text=new_sql if new_sql is not None else q.sql_text,
217
+ description=description if description is not None else q.description,
218
+ params=q.params,
219
+ )
220
+ _write.record_action("saved_query_updated", resource="query", success=True)
221
+ if state.json:
222
+ output.emit_json({"id": result.id, "name": result.name, "description": result.description,
223
+ "created_at": result.created_at, "sql_text": result.sql_text})
224
+ return
225
+ output.render_query_updated(result, old_name=q.name)
226
+
227
+
228
+ def query_delete(
229
+ ctx: typer.Context,
230
+ name: str = typer.Argument(..., metavar="NAME", help="Saved query name (or id) to delete."),
231
+ 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."),
232
+ ) -> None:
233
+ """Delete a saved query, referenced by **name** (or a UUID-shaped id). This cannot be undone.
234
+
235
+ Needs `queries:delete`. With `--json`: `{"deleted": true, "id", "name"}`.
236
+
237
+ Example:
238
+
239
+ * `fp query delete errs --yes`
240
+ """
241
+ state: AppState = ctx.obj
242
+ cctx = require_auth(state)
243
+ q = _resolve_query_or_exit(state, api.list_saved_queries(cctx), name)
244
+ if _write.should_prompt(state, yes):
245
+ output.render_query_delete_preview(q) # amber preview of what's about to go
246
+ if not output.confirm_query_delete():
247
+ if state.json:
248
+ output.emit_json({"cancelled": True})
249
+ else:
250
+ output.query_cancelled("nothing deleted")
251
+ return
252
+ api.delete_saved_query(cctx, q.id)
253
+ _write.record_action("saved_query_deleted", resource="query", success=True, destructive=True)
254
+ if state.json:
255
+ output.emit_json({"deleted": True, "id": q.id, "name": q.name})
256
+ else:
257
+ output.query_deleted(q.name)
258
+
259
+
260
+ def query_run(
261
+ ctx: typer.Context,
262
+ name: Optional[str] = typer.Argument(None, metavar="[NAME]", help="Saved query name to run (or a UUID-shaped id)."),
263
+ sql: Optional[str] = typer.Option(None, "--sql", help="Run ad-hoc SQL instead of a saved query, or `@file.sql`."),
264
+ limit: Optional[int] = typer.Option(None, "--limit", help=f"Max rows to show in the table view (default {output.QUERY_RUN_ROW_CAP}; --json always returns all)."),
265
+ all_: bool = typer.Option(False, "--all", help="Show every returned row (override the table row cap)."),
266
+ param: Optional[List[str]] = typer.Option(None, "--arg", "--param", help="Positional argument value bound to $1..$N, in order (repeatable). Alias: --param."),
267
+ ) -> None:
268
+ """Run a saved query by **name**, or ad-hoc `--sql`, against the read-only analytics pool.
269
+
270
+ The result is rendered adaptively from its shape — a scalar stat card, a single record, or a
271
+ boxed table (capped to a preview; `--limit`/`--all` adjust it, `--json` returns everything).
272
+ Pass a saved query's positional parameters with `--arg` (one per `$1..$N`, in order). Needs
273
+ `queries:run`. Not-found → red `✗ no query named "…"`; a SQL/exec error → `✗ query failed — …`.
274
+ With `--json`: `{columns: [{name, type}], rows: [[...]], truncated, elapsed_ms}` (all rows).
275
+
276
+ Examples:
277
+
278
+ * `fp query run q_eval_total`
279
+ * `fp query run q_eval_score_avg --arg agent-codegen`
280
+ * `fp --json query run --sql "select count(*) from analytics.events"`
281
+ """
282
+ state: AppState = ctx.obj
283
+ if (name is None) == (sql is None):
284
+ raise typer.BadParameter("pass a saved query NAME or --sql (exactly one).")
285
+ validate_limit(limit)
286
+ cctx = require_auth(state)
287
+ query_id: Optional[str] = None
288
+ display_name = "query"
289
+ if name is not None:
290
+ q = _resolve_query_or_exit(state, api.list_saved_queries(cctx), name)
291
+ query_id, display_name = q.id, q.name
292
+ values = [_coerce_value(v) for v in (param or [])]
293
+ # A SQL/exec/permission failure propagates as a typed error to the central chokepoint
294
+ # (JSON envelope under --json, red box otherwise). The DB detail is surfaced because
295
+ # client._extract_error folds the server's `detail` into the message.
296
+ result = api.run_query(
297
+ cctx, sql=_read_sql(sql) if sql is not None else None, query_id=query_id, params=values
298
+ )
299
+ _write.record_action(
300
+ "query_run", success=True, via="saved" if query_id else "ad_hoc", row_count_bucket=_bucket(len(result.rows))
301
+ )
302
+ if state.json:
303
+ output.emit_json(result)
304
+ return
305
+ row_cap = limit if limit is not None else output.QUERY_RUN_ROW_CAP
306
+ output.render_query_result(display_name, result, row_cap=row_cap, show_all=all_)
307
+
308
+
309
+ def _bucket(n: int) -> str:
310
+ if n == 0:
311
+ return "0"
312
+ if n <= 10:
313
+ return "1-10"
314
+ if n <= 100:
315
+ return "11-100"
316
+ return "100+"
317
+
318
+
319
+ def query_schema(
320
+ ctx: typer.Context,
321
+ table: Optional[str] = typer.Argument(None, metavar="[TABLE]", help="Filter to one table's columns."),
322
+ ) -> None:
323
+ """Show the queryable analytics schema in a boxed, table-grouped view.
324
+
325
+ Each table's name prints once (then blanks down its columns); types are coloured by category
326
+ (numeric / string / uuid+timestamp / bool) with a dim `?` for nullable. Pass a `TABLE` to
327
+ filter to one. Needs `queries:read`. With `--json`: `{schema, columns: [{table, column, type,
328
+ nullable}]}` (the `?` split into a boolean).
329
+
330
+ Examples:
331
+
332
+ * `fp query schema`
333
+ * `fp query schema events`
334
+ """
335
+ state: AppState = ctx.obj
336
+ cctx = require_auth(state)
337
+ data = api.query_schema(cctx)
338
+ tables = list(data.get("tables", []) or [])
339
+ if table is not None:
340
+ match = [t for t in tables if t.get("name") == table]
341
+ if not match:
342
+ names = [str(t.get("name", "")) for t in tables]
343
+ raise NotFoundError(
344
+ f'no table named "{table}"', hint=f"available: {', '.join(names)}" if names else None
345
+ )
346
+ tables = match
347
+ data = {**data, "tables": tables}
348
+
349
+ if state.json:
350
+ flat = []
351
+ for t in tables:
352
+ for col in t.get("columns", []) or []:
353
+ ty = str(col.get("type", ""))
354
+ nullable = ty.endswith("?")
355
+ flat.append({"table": t.get("name", ""), "column": col.get("name", ""),
356
+ "type": ty[:-1] if nullable else ty, "nullable": nullable})
357
+ output.emit_json({"schema": data.get("schema", ""), "columns": flat})
358
+ return
359
+ output.render_query_schema(data)
360
+ total_cols = sum(len(t.get("columns", []) or []) for t in tables)
361
+ output.schema_footer(len(tables), total_cols)
362
+
363
+
364
+ def register(app: typer.Typer) -> None:
365
+ query_app = typer.Typer(
366
+ no_args_is_help=True,
367
+ rich_markup_mode="markdown",
368
+ context_settings={"help_option_names": ["-h", "--help"]},
369
+ help="Run and manage saved SQL queries (list / show / create / update / delete / run / schema).",
370
+ )
371
+ query_app.command("list", epilog=GLOBALS_EPILOG)(query_list)
372
+ query_app.command("show", epilog=GLOBALS_EPILOG)(query_show)
373
+ query_app.command("create", epilog=GLOBALS_EPILOG)(query_create)
374
+ query_app.command("update", epilog=GLOBALS_EPILOG)(query_update)
375
+ query_app.command("delete", epilog=GLOBALS_EPILOG)(query_delete)
376
+ query_app.command("run", epilog=GLOBALS_EPILOG)(query_run)
377
+ query_app.command("schema", epilog=GLOBALS_EPILOG)(query_schema)
378
+ app.add_typer(query_app, name="query")
@@ -0,0 +1,151 @@
1
+ """sessions — list agent sessions (newest first) with their run status."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import List, Optional
6
+
7
+ import typer
8
+
9
+ from .. import client as api
10
+ from .. import dates, output
11
+ from .._context import (
12
+ GLOBALS_EPILOG,
13
+ AppState,
14
+ collect_multi,
15
+ require_auth,
16
+ resolve_dates,
17
+ resolve_fields,
18
+ validate_choice,
19
+ validate_limit,
20
+ )
21
+ from ..models import Session
22
+
23
+
24
+ def sessions(
25
+ ctx: typer.Context,
26
+ limit: int = typer.Option(50, "--limit", "-n", help="Max rows in total. Use --all to auto-paginate beyond the server's single-request cap."),
27
+ since: Optional[str] = typer.Option(None, "--since", help=f"Relative window from now (dashboard presets): {', '.join(dates.SINCE_CHOICES)}."),
28
+ ts_from: Optional[str] = typer.Option(None, "--from", help="Custom-range start, ISO-8601 UTC (e.g. 2026-05-01T00:00:00Z). Overrides --since."),
29
+ ts_to: Optional[str] = typer.Option(None, "--to", help="Custom-range end, ISO-8601 UTC. Overrides --since."),
30
+ environment: Optional[List[str]] = typer.Option(None, "--env", help="Filter by environment. Accepts multiple — repeat the flag or comma-separate: `--env prod --env staging` or `--env prod,staging` (matches any)."),
31
+ status: Optional[List[str]] = typer.Option(None, "--status", help="Filter by run status (`done`/`error`/`timeout`), matched against each session's latest evaluation. Accepts multiple — repeat the flag or comma-separate: `--status error,timeout` (matches any)."),
32
+ agent_id: Optional[List[str]] = typer.Option(None, "--agent-id", help="Filter by agent id. Accepts multiple — repeat the flag or comma-separate: `--agent-id a,b` (matches any)."),
33
+ session_id: Optional[List[str]] = typer.Option(None, "--session-id", help="Filter by session id. Accepts multiple — repeat the flag or comma-separate: `--session-id a,b` (matches any)."),
34
+ fetch_all: bool = typer.Option(False, "--all", help="Auto-paginate through all pages, up to --limit."),
35
+ cursor: Optional[str] = typer.Option(None, "--cursor", help="Resume after this cursor (a prior next_cursor; opaque token)."),
36
+ page_size: Optional[int] = typer.Option(None, "--page-size", help="Rows per request when --all (max 200)."),
37
+ fields: Optional[str] = typer.Option(None, "--fields", help="Comma-separated subset of fields to output (applies to --json and the table). e.g. `session_id,status,last_event_at`."),
38
+ full_ids: bool = typer.Option(False, "--full-ids", help="Show full session ids in the table instead of truncating them (--json always has the full id)."),
39
+ agents_expand: bool = typer.Option(False, "--agents", help="Expand every multi-agent session into an indented roster of its agents (name + event count). Rendered view only — `--json` always carries the full `agents` list."),
40
+ ) -> None:
41
+ """List **sessions** — one row per agent run, newest first.
42
+
43
+ Shows what ran and how it ended: `time · env · agent · session · status`. `status` is the
44
+ session's latest evaluation outcome (`done`/`error`/`timeout`, blank if it was never
45
+ evaluated). For the per-evaluation **scores** behind a session — and rolled-up score stats —
46
+ use `fp evals`.
47
+
48
+ The filters `--env`, `--status`, `--agent-id`, and `--session-id` each accept **multiple
49
+ values** — repeat the flag or comma-separate (`--status error,timeout` is the same as
50
+ `--status error --status timeout`). Values within one filter match **any** of them; different
51
+ filters are combined (a session must satisfy all of them). Scope by time with `--since` (a
52
+ preset window) or `--from`/`--to` (a custom UTC range), and page with `--all` or `--cursor`.
53
+
54
+ A session can involve **more than one agent**. The `agent` column shows the root agent (the
55
+ first to start) plus a `+N` badge counting the others; `--agents` expands every multi-agent
56
+ session into an indented roster (each agent + its event count). `--agent-id` matches a session
57
+ if **any** of its agents is one you named (not just the root).
58
+
59
+ Needs `evaluations:read`. With `--json`: `{"sessions": [...], "next_cursor": <cursor or null>}`.
60
+ Each row has `session_id, agent_id, agents, environment, status, scores, event_count,
61
+ started_at, last_event_at, first_event_id, last_event_id, latest_evaluation` (also the valid
62
+ `--fields` names) — `agent_id` is the root agent and `agents` is the full roster (each
63
+ `{agent_id, event_count}`, sorted by event count); `status` and `scores` are flattened up from
64
+ the latest evaluation for convenience, and the full evaluation is kept under `latest_evaluation`.
65
+
66
+ Examples:
67
+
68
+ * `fp sessions --env prod,staging --status error,timeout` — recent prod/staging runs that errored or timed out
69
+ * `fp sessions --agent-id agent-orderbot --since 24h` — every session agent-orderbot took part in over the last 24h
70
+ * `fp sessions --agents` — expand each multi-agent session to its full agent roster
71
+ * `fp --json sessions --all --fields session_id,agents | jq '.sessions'` — every session's full agent roster as JSON
72
+ """
73
+ state: AppState = ctx.obj
74
+ cctx = require_auth(state)
75
+ validate_limit(limit)
76
+ frm, to = resolve_dates(since, ts_from, ts_to)
77
+ cols = resolve_fields(fields, Session)
78
+
79
+ # Multi-value filters: merge repeated flags + comma-separated values into one flat,
80
+ # de-duplicated list each (the server UNIONs within a filter via `IN`, ANDs across them).
81
+ environment = collect_multi(environment)
82
+ status = collect_multi(status)
83
+ agent_id = collect_multi(agent_id)
84
+ session_id = collect_multi(session_id)
85
+ # Validate each status value client-side (clean exit 2) rather than a server 400.
86
+ for s in status or []:
87
+ validate_choice(s, ("done", "error", "timeout"), flag="--status")
88
+
89
+ def fetch(cursor: Optional[str], limit: Optional[int]):
90
+ return api.list_sessions(
91
+ cctx,
92
+ session_id=session_id,
93
+ agent_id=agent_id,
94
+ environment=environment,
95
+ status=status,
96
+ ts_from=frm,
97
+ ts_to=to,
98
+ cursor=cursor,
99
+ limit=limit,
100
+ )
101
+
102
+ if fetch_all:
103
+ walk = api.Walk()
104
+ items = list(
105
+ api.paginate(fetch, limit=limit, page_size=page_size, start_cursor=cursor, walk=walk)
106
+ )
107
+ # NOT `None`. `--limit` defaults to 50, so `--all` without an explicit
108
+ # limit stops at 50 rows — and hard-coding the cursor to null told the
109
+ # caller the feed was exhausted, on the one output a script or an agent
110
+ # reads. `walk` carries the cursor the walk actually stopped on.
111
+ next_cursor = walk.next_cursor
112
+ else:
113
+ page = fetch(cursor, limit)
114
+ items = page.items
115
+ next_cursor = page.next_cursor
116
+
117
+ if state.json:
118
+ payload = output.project_dicts(items, cols) if cols else items
119
+ output.emit_json({"sessions": payload, "next_cursor": next_cursor})
120
+ return
121
+
122
+ # Which narrowing filters did the user set? Used to word the empty-box message and to
123
+ # nudge them to re-check those values when 0 rows come back (a value matching nothing
124
+ # returns empty, not an error — so a typo looks like "no sessions").
125
+ active_filters = [
126
+ flag for flag, val in (
127
+ ("--env", environment),
128
+ ("--status", status),
129
+ ("--agent-id", agent_id),
130
+ ("--session-id", session_id),
131
+ ("--since/--from/--to", since or ts_from or ts_to),
132
+ ) if val
133
+ ]
134
+
135
+ if cols:
136
+ # `--fields` asks for specific columns → the generic table (no bespoke styling).
137
+ output.print_table(list(cols), output.project_rows(items, cols), title=f"Sessions ({len(items)})")
138
+ else:
139
+ empty_message = "no sessions match these filters" if active_filters else "no sessions"
140
+ if agents_expand:
141
+ output.render_sessions_expanded(items, full_ids=full_ids, empty_message=empty_message)
142
+ else:
143
+ output.render_sessions(items, full_ids=full_ids, empty_message=empty_message)
144
+ multi_agent = sum(1 for e in items if output.is_multi_agent(e))
145
+ output.sessions_footer(len(items), more=next_cursor is not None, multi_agent=multi_agent)
146
+ if not items:
147
+ output.recheck_filters_hint(active_filters)
148
+
149
+
150
+ def register(app: typer.Typer) -> None:
151
+ app.command("sessions", epilog=GLOBALS_EPILOG)(sessions)
@@ -0,0 +1,150 @@
1
+ """Org settings: settings list / schema / set.
2
+
3
+ Settings are a FIXED registry — you can read them (``list``), inspect what each accepts
4
+ (``schema``), and change an existing key's value (``set``). You can't create new keys.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ from typing import Any, Optional
11
+
12
+ import typer
13
+
14
+ from .. import client as api
15
+ from .. import output
16
+ from .._context import GLOBALS_EPILOG, AppState, require_auth
17
+ from ..errors import NotFoundError
18
+ from . import _write
19
+
20
+
21
+ def settings_list(ctx: typer.Context) -> None:
22
+ """List the org's settings and their current values in a boxed table.
23
+
24
+ Shows `key · value · type · updated` — the value rendered type-aware (lists comma-joined,
25
+ numbers pink, secrets masked), truncated to one line (full values in `--json`). `key` is the
26
+ handle `settings set` takes. Needs `settings:read`. With `--json`: `{"settings": [{key, value,
27
+ updated_at, updated_by, scope, schema}]}`.
28
+
29
+ Example:
30
+
31
+ * `fp settings list`
32
+ """
33
+ state: AppState = ctx.obj
34
+ cctx = require_auth(state)
35
+ rows = api.list_settings(cctx)
36
+ if state.json:
37
+ output.emit_json({"settings": rows})
38
+ return
39
+ output.render_settings(rows, current_email=state.config.email)
40
+
41
+
42
+ def settings_schema(ctx: typer.Context) -> None:
43
+ """Show the settings registry — what each key is and what it accepts.
44
+
45
+ A boxed `key · type · accepts · description` table derived from each setting's `schema` blob
46
+ (there is no separate schema endpoint). `accepts` summarizes the constraints (int range + unit,
47
+ channel options, …). Needs `settings:read`. With `--json`: `{"settings": [<schema entries>]}`.
48
+
49
+ Example:
50
+
51
+ * `fp settings schema`
52
+ """
53
+ state: AppState = ctx.obj
54
+ cctx = require_auth(state)
55
+ schema = api.get_settings_schema(cctx)
56
+ if state.json:
57
+ output.emit_json({"settings": schema})
58
+ return
59
+ output.render_settings_schema(schema)
60
+
61
+
62
+ def settings_set(
63
+ ctx: typer.Context,
64
+ key: str = typer.Argument(..., help="Setting key to update (must be an existing key — see `settings list`)."),
65
+ value: Optional[str] = typer.Option(None, "--value", help="Scalar value (string; a digit-only value is sent as an integer)."),
66
+ json_value: Optional[str] = typer.Option(None, "--json-value", help="Raw JSON value, for arrays/objects (e.g. `[\"a@b.com\"]`)."),
67
+ file: Optional[str] = typer.Option(None, "--file", help="Read a JSON value from a file, or `-` for stdin."),
68
+ 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."),
69
+ ) -> None:
70
+ """Change one org setting's value, showing the before → after.
71
+
72
+ Provide the value exactly one way: `--value` (scalar), `--json-value` (raw JSON for
73
+ arrays/objects), or `--file`/stdin (JSON). The CLI checks the key exists, shows the change and
74
+ confirms (a no-op is skipped), then renders the updated value. Needs `settings:write`. Unknown
75
+ key → exit 6; an invalid value → the server's clean message, exit non-zero. With `--json`: the
76
+ updated `SettingRow` (or `{cancelled: true}`).
77
+
78
+ Examples:
79
+
80
+ * `fp settings set session_ttl_secs --value 86400`
81
+ * `fp settings set alerts.email_default_recipients --json-value '["a@b.com"]'`
82
+ """
83
+ state: AppState = ctx.obj
84
+ provided = [v is not None for v in (value, json_value, file)]
85
+ if sum(provided) != 1:
86
+ raise typer.BadParameter("Provide exactly one of --value, --json-value, or --file.")
87
+
88
+ if value is not None:
89
+ # `str.isdigit()` accepts characters int() rejects (superscripts, "--5"); just try the
90
+ # conversion and fall back to the string, so a non-int value is never an uncaught traceback.
91
+ try:
92
+ parsed: Any = int(value)
93
+ except ValueError:
94
+ parsed = value
95
+ elif json_value is not None:
96
+ try:
97
+ parsed = json.loads(json_value)
98
+ except json.JSONDecodeError as exc:
99
+ raise typer.BadParameter(f"--json-value is not valid JSON: {exc}", param_hint="--json-value")
100
+ else:
101
+ raw = _write.read_text_arg(file)
102
+ try:
103
+ parsed = json.loads(raw)
104
+ except json.JSONDecodeError as exc:
105
+ raise typer.BadParameter(f"--file is not valid JSON: {exc}", param_hint="--file")
106
+
107
+ cctx = require_auth(state)
108
+ current = next((s for s in api.list_settings(cctx) if s.key == key), None)
109
+ if current is None: # settings are a fixed registry — an unknown key can't be created
110
+ raise NotFoundError(
111
+ f'no setting named "{key}"', hint="run `fp settings list` to see them"
112
+ )
113
+ kind = (current.schema or {}).get("kind", "") if isinstance(current.schema, dict) else ""
114
+
115
+ if parsed == current.value: # no-op — don't call the server or prompt (secrets always blank)
116
+ if state.json:
117
+ output.emit_json(current)
118
+ else:
119
+ output.setting_no_change(key, current.value, kind)
120
+ return
121
+
122
+ if _write.should_prompt(state, yes):
123
+ if not output.confirm_setting_change(key, current.value, parsed, kind):
124
+ if state.json:
125
+ output.emit_json({"cancelled": True})
126
+ else:
127
+ output.print_cancelled("nothing changed")
128
+ return
129
+
130
+ # An invalid value (422) / unknown key (404) propagates as a typed error to the central
131
+ # chokepoint (JSON envelope under --json, red box otherwise).
132
+ row = api.put_setting(cctx, key, parsed)
133
+ _write.record_action("setting_updated", resource="setting", success=True)
134
+ if state.json:
135
+ output.emit_json(row)
136
+ return
137
+ output.render_setting_updated(row, kind)
138
+
139
+
140
+ def register(app: typer.Typer) -> None:
141
+ settings_app = typer.Typer(
142
+ no_args_is_help=True,
143
+ rich_markup_mode="markdown",
144
+ context_settings={"help_option_names": ["-h", "--help"]},
145
+ help="View and update org settings (list / schema / set).",
146
+ )
147
+ settings_app.command("list", epilog=GLOBALS_EPILOG)(settings_list)
148
+ settings_app.command("schema", epilog=GLOBALS_EPILOG)(settings_schema)
149
+ settings_app.command("set", epilog=GLOBALS_EPILOG)(settings_set)
150
+ app.add_typer(settings_app, name="settings")