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,432 @@
1
+ """PostHog telemetry for the CLI — a thin, fail-safe wrapper.
2
+
3
+ Mirrors the dashboard's ``lib/analytics.ts``: import-safe, a no-op until
4
+ ``init_analytics`` runs, identifies operators by an opaque id only (never email),
5
+ and tags every event with ``product`` super-properties. Adapted for a short-lived
6
+ process: events are flushed on exit within a hard time bound, and **every** public
7
+ function swallows all exceptions so telemetry can never slow or break a command.
8
+
9
+ Privacy: the generic ``command_executed`` event records only static names (command,
10
+ subcommand, flag NAMES) plus coarse booleans/counts and one closed enum
11
+ (``auth_mode``). Argument *values* — dashboard URL, session token, API key, email,
12
+ session ids, score expressions, file paths — are never sent, in any form: not the
13
+ value, not its length, not a prefix.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import logging
19
+ import platform
20
+ import threading
21
+ import uuid
22
+ from typing import Any, Dict, FrozenSet, List, Optional, Tuple
23
+
24
+ from . import analytics_config as acfg
25
+ from . import config as cfgmod
26
+ from ._version import __version__
27
+
28
+ # Single client + per-invocation context (the dashboard keeps one posthog-js instance).
29
+ # The client is built LAZILY (see _ensure_client) on the first actual send, so a normal
30
+ # command never pays the posthog import + client construction on its startup path.
31
+ _client: Any = None
32
+ _distinct_id: Optional[str] = None
33
+ _command: Optional[str] = None
34
+ _json_output: bool = False
35
+ _auth_mode: str = "none"
36
+ _force_anonymous: bool = False
37
+ _pending_conf: Any = None
38
+ _init_done: bool = False
39
+
40
+ # Hard cap on how long shutdown may block the CLI waiting on the network.
41
+ _FLUSH_TIMEOUT_SECS = 1.5
42
+
43
+ # Recognised command / flag names. These are the STATIC FALLBACK used only if the
44
+ # derived registry (analytics_registry, introspected from the live Typer app) cannot
45
+ # be built. The generic event emits ONLY known static strings, so customer data (urls,
46
+ # tokens, ids, queries, paths) can never leak through it. The anti-drift test asserts
47
+ # the *derived* catalog stays exhaustive, which is the real guarantee of completeness.
48
+ _KNOWN_COMMANDS = frozenset(
49
+ {
50
+ "login", "logout", "whoami", "orgs", "events",
51
+ "sessions", "evals", "version", "help",
52
+ "list", "errors", "keys", "query",
53
+ "users", "settings", "alerts", "audits", "issues", "agent",
54
+ }
55
+ )
56
+ # group -> its leaf subcommand names (static fallback).
57
+ _STATIC_LEAVES: Dict[str, FrozenSet[str]] = {
58
+ "list": frozenset({"envs", "agents", "event_types", "score_filters", "models",
59
+ "hooks", "tools", "error_types"}),
60
+ "orgs": frozenset({"list", "switch", "current", "perms"}),
61
+ "keys": frozenset({"list", "show", "create", "update", "disable", "regenerate"}),
62
+ "query": frozenset({"list", "show", "create", "update", "delete", "run", "schema"}),
63
+ "users": frozenset({"list", "show", "create", "update", "disable", "enable"}),
64
+ "settings": frozenset({"list", "schema", "set"}),
65
+ "alerts": frozenset({"list", "show", "create", "update", "delete", "test"}),
66
+ "audits": frozenset({"list", "show", "create", "edit", "delete", "run", "runs", "findings",
67
+ "finding", "ack", "mute", "dismiss", "resolve", "reopen", "assign"}),
68
+ "issues": frozenset({"list", "count", "show", "ack", "assign", "resolve", "comment-list",
69
+ "comment-add", "comment-delete", "subscribers", "subscribe", "unsubscribe", "open"}),
70
+ "agent": frozenset({"health", "models", "chats", "show", "rename", "delete", "ask"}),
71
+ }
72
+ # Global options that consume a following token (static fallback for value-skipping).
73
+ _STATIC_VALUE_FLAGS = frozenset(
74
+ {"--base-url", "--org", "--token", "--api-key", "--timeout", "--email", "-e"}
75
+ )
76
+
77
+ # Any flag token (long or short) -> its canonical long name (static fallback).
78
+ _FLAG_ALIASES: Dict[str, str] = {
79
+ "--json": "--json",
80
+ "--base-url": "--base-url",
81
+ "--org": "--org",
82
+ "--token": "--token",
83
+ "--api-key": "--api-key",
84
+ "--timeout": "--timeout",
85
+ "--no-color": "--no-color",
86
+ "--quiet": "--quiet", "-q": "--quiet",
87
+ "--insecure": "--insecure", "--secure": "--secure",
88
+ "--version": "--version",
89
+ "--email": "--email", "-e": "--email",
90
+ "--environment": "--environment", "--env": "--environment",
91
+ "--agent-id": "--agent-id",
92
+ "--status": "--status",
93
+ "--score": "--score",
94
+ "--since": "--since", "--from": "--from", "--to": "--to",
95
+ "--limit": "--limit", "-n": "--limit",
96
+ "--cursor": "--cursor",
97
+ "--all": "--all",
98
+ "--page-size": "--page-size",
99
+ "--fields": "--fields",
100
+ "--arg": "--arg", "--param": "--param", "--force": "--force",
101
+ "--session-id": "--session-id",
102
+ "--event-type": "--event-type",
103
+ "--audit": "--audit", "--run-id": "--run-id", "--offset": "--offset",
104
+ "--reason": "--reason", "--to": "--to", "--show-id": "--show-id",
105
+ "--scope": "--scope", "--sensitivity": "--sensitivity", "--top-k": "--top-k",
106
+ "--window-mode": "--window-mode", "--channels": "--channels",
107
+ "--latest-per-session": "--latest-per-session",
108
+ "--events-limit": "--events-limit",
109
+ "--no-events": "--no-events", "--no-eval": "--no-eval",
110
+ "--output": "--output", "-o": "--output",
111
+ "--source": "--source",
112
+ "--help": "--help", "-h": "--help",
113
+ }
114
+
115
+
116
+ def _catalog() -> "tuple":
117
+ """``(known_commands, leaf_registry, flag_aliases, value_flags)``.
118
+
119
+ Prefers the live derived catalog; falls back to the static tables if introspection
120
+ fails (telemetry is best-effort and must never raise into a command).
121
+ """
122
+ try:
123
+ from . import analytics_registry as reg
124
+
125
+ known, leaves, flags, value_flags = reg.build()
126
+ if known and flags:
127
+ return known, leaves, flags, value_flags
128
+ except Exception:
129
+ pass
130
+ return _KNOWN_COMMANDS, _STATIC_LEAVES, _FLAG_ALIASES, _STATIC_VALUE_FLAGS
131
+
132
+ # The CLOSED set of auth modes we will emit. Mirrors `client.AuthMode`, but stated as
133
+ # a literal allowlist so an unexpected value degrades to "none" rather than being
134
+ # forwarded verbatim — this property must never become a channel for anything but
135
+ # these three words.
136
+ _AUTH_MODES: Dict[str, str] = {"session": "session", "api_key": "api_key", "none": "none"}
137
+
138
+ # Exit code -> coarse error class (derived from errors.py / Click conventions).
139
+ _EXIT_CATEGORY: Dict[int, Optional[str]] = {
140
+ 0: None, # success
141
+ 2: "usage",
142
+ 3: "network",
143
+ 4: "auth",
144
+ 5: "forbidden",
145
+ 6: "not_found",
146
+ }
147
+
148
+
149
+ def init_analytics(conf: cfgmod.CliConfig, *, force_anonymous: bool = False) -> None:
150
+ """Record config for a LAZILY-constructed PostHog client (resolve + build on first send).
151
+
152
+ Deferring the posthog import + client construction keeps them off every command's startup
153
+ path; an invocation that never emits an event (the common case, and every opted-out user)
154
+ pays nothing. :func:`_ensure_client` does the real work the first time a send is attempted.
155
+
156
+ ``force_anonymous`` is set in API-key mode. :func:`_resolve_distinct_id` reads the
157
+ SAVED config, so a machine where a human is logged in would attribute a CI key's
158
+ commands to that person — a wrong identity, silently, forever.
159
+ """
160
+ global _pending_conf, _init_done, _client, _distinct_id, _force_anonymous
161
+ _pending_conf = conf
162
+ _init_done = False
163
+ _client = None
164
+ _distinct_id = None
165
+ _force_anonymous = bool(force_anonymous)
166
+
167
+
168
+ def _ensure_client() -> None:
169
+ """Build the PostHog client on first use (idempotent). Any failure leaves telemetry off."""
170
+ global _client, _distinct_id, _init_done
171
+ if _init_done:
172
+ return
173
+ _init_done = True
174
+ conf = _pending_conf
175
+ if conf is None:
176
+ return
177
+ settings = acfg.resolve_config()
178
+ if not settings.enabled:
179
+ return
180
+ try:
181
+ from posthog import Posthog
182
+
183
+ _distinct_id = (
184
+ _ensure_anonymous_id(conf) if _force_anonymous else _resolve_distinct_id(conf)
185
+ )
186
+ _client = Posthog(
187
+ settings.api_key,
188
+ host=settings.host,
189
+ flush_at=1, # a CLI fires few events then exits — send promptly
190
+ max_retries=1, # don't retry-storm a blocked/slow network
191
+ timeout=3, # short per-request timeout
192
+ disable_geoip=True, # don't resolve the caller's IP to a location
193
+ super_properties=_super_properties(),
194
+ )
195
+ # The CLI owns stderr; keep posthog's own logger from printing onto it.
196
+ logging.getLogger("posthog").setLevel(logging.CRITICAL)
197
+ except Exception:
198
+ _client = None
199
+
200
+
201
+ def note_command(
202
+ command: Optional[str], json_output: bool, auth_mode: Any = None
203
+ ) -> None:
204
+ """Record (from the main callback) which command ran, whether ``--json`` is set, and
205
+ which credential it used.
206
+
207
+ Authoritative — taken from the parsed Typer context, not re-parsed from argv. Uses the
208
+ cheap STATIC command set (no Typer→Click tree build on the startup path). Safe to call
209
+ when telemetry is disabled (it only sets module state).
210
+
211
+ ``auth_mode`` is an ``AuthMode`` (a ``str`` enum we authored, so the property is a
212
+ closed set: ``session`` | ``api_key`` | ``none``). Never the key, its length, or a
213
+ prefix — the mode is the whole signal, and it is what makes "is anyone actually
214
+ running this in CI?" answerable.
215
+ """
216
+ global _command, _json_output, _auth_mode
217
+ _command = command if command in _KNOWN_COMMANDS else None
218
+ _json_output = bool(json_output)
219
+ _auth_mode = _AUTH_MODES.get(str(getattr(auth_mode, "value", auth_mode)), "none")
220
+
221
+
222
+ def capture(event: str, properties: Optional[Dict[str, Any]] = None) -> None:
223
+ """Send one event. No-op until initialised; never raises."""
224
+ _ensure_client()
225
+ if _client is None:
226
+ return
227
+ try:
228
+ # Keyword form. `posthog>=7` is `capture(self, event, **kwargs)` —
229
+ # everything after `event` is keyword-only — so the posthog-3 positional
230
+ # order `(distinct_id, event, …)` raised `TypeError: Client.capture()
231
+ # takes 2 positional arguments but 3 were given`, and the failure was
232
+ # invisible from three directions at once: posthog's own `@no_throw`
233
+ # swallowed it, `_ensure_client` sets the posthog logger to CRITICAL so
234
+ # the log it wrote was suppressed, and the `except Exception: pass` below
235
+ # would have swallowed it too. Nothing sent, nothing logged, nothing
236
+ # raised. (Dead today — `TELEMETRY_DISABLED` is True — which is precisely
237
+ # why it could sit here unnoticed until someone flipped that flag.)
238
+ _client.capture(event, distinct_id=_distinct_id, properties=properties or {})
239
+ except Exception:
240
+ pass
241
+
242
+
243
+ def capture_command(exit_code: int, duration_ms: int, argv: List[str]) -> None:
244
+ """Emit the generic ``command_executed`` event with an allowlisted payload.
245
+
246
+ ``command``/``subcommand`` come from resolving argv against the known command
247
+ tree, so every group's leaf (``keys create``, ``orgs switch``, …) is distinguished —
248
+ not just the top-level command. Both are static names from the catalog; values never leak.
249
+ """
250
+ _ensure_client()
251
+ if _client is None:
252
+ return
253
+ group, leaf = _resolve_command_path(argv)
254
+ command = _command if _command is not None else group
255
+ subcommand = leaf if (command is not None and command == group) else None
256
+ capture(
257
+ "command_executed",
258
+ {
259
+ "command": command,
260
+ "subcommand": subcommand,
261
+ "success": exit_code == 0,
262
+ "exit_code": exit_code,
263
+ "error_category": _EXIT_CATEGORY.get(exit_code, "error"),
264
+ "duration_ms": duration_ms,
265
+ "flags": _sanitize_flags(argv),
266
+ "json_output": _json_output,
267
+ "auth_mode": _auth_mode,
268
+ },
269
+ )
270
+
271
+
272
+ def identify(user_id: Optional[str]) -> None:
273
+ """Link this machine's prior anonymous activity to the operator id (called on login).
274
+
275
+ Mirrors the dashboard's ``posthog.identify(id)`` by the opaque operator id only.
276
+ No-op when telemetry is off or there is nothing to link.
277
+ """
278
+ _ensure_client()
279
+ if _client is None or not user_id:
280
+ return
281
+ try:
282
+ conf = cfgmod.load_config()
283
+ if conf.anonymous_id and conf.anonymous_id != user_id:
284
+ _client.alias(previous_id=conf.anonymous_id, distinct_id=user_id)
285
+ except Exception:
286
+ pass
287
+
288
+
289
+ def reset() -> None:
290
+ """Rotate the local anonymous id on logout so later anon events aren't tied to the user.
291
+
292
+ posthog-python has no client-side reset; this is local state only (the analog of
293
+ the dashboard's ``posthog.reset()``). Runs **regardless** of whether telemetry is
294
+ currently enabled: ``anonymous_id`` is persistent config state and the opt-out
295
+ flag can be toggled between runs, so the unlink-on-logout invariant must hold even
296
+ when this invocation has telemetry off (otherwise a later re-enabled run could
297
+ reuse an id still aliased to the operator who just logged out).
298
+ """
299
+ try:
300
+ conf = cfgmod.load_config()
301
+ conf.anonymous_id = uuid.uuid4().hex
302
+ cfgmod.save_config(conf)
303
+ except Exception:
304
+ pass
305
+
306
+
307
+ def shutdown() -> None:
308
+ """Flush pending events, bounded so telemetry never stalls the CLI on exit.
309
+
310
+ Idempotent. The flush runs on a daemon thread joined for at most
311
+ ``_FLUSH_TIMEOUT_SECS``; if the network is slow/blocked the thread is abandoned
312
+ (it dies with the process) and the event is dropped — telemetry is best-effort.
313
+
314
+ TODO(telemetry-nonblocking): this bounds only the *final* flush. The client build
315
+ and first ``capture()`` connect (in ``_ensure_client`` / ``capture_command``) are
316
+ NOT bounded, so a blocked PostHog host stalls the CLI ~5s/command before this runs.
317
+ Telemetry is currently disabled via ``analytics_config.TELEMETRY_DISABLED``; before
318
+ re-enabling, move the whole capture+flush onto this bounded daemon thread (or set an
319
+ aggressive connect timeout on the client) so no command can ever block on it.
320
+ """
321
+ global _client
322
+ client = _client
323
+ _client = None # a second call is a no-op
324
+ if client is None:
325
+ return
326
+
327
+ def _drain() -> None:
328
+ try:
329
+ client.flush()
330
+ except Exception:
331
+ pass
332
+ try:
333
+ client.shutdown()
334
+ except Exception:
335
+ pass
336
+
337
+ thread = threading.Thread(target=_drain, name="posthog-flush", daemon=True)
338
+ thread.start()
339
+ thread.join(_FLUSH_TIMEOUT_SECS)
340
+
341
+
342
+ # --- internals -------------------------------------------------------------------
343
+
344
+
345
+ def _super_properties() -> Dict[str, str]:
346
+ """Tags merged into every event (the analog of ``posthog.register``)."""
347
+ return {
348
+ "product": acfg.PRODUCT,
349
+ "cli_version": __version__,
350
+ "os": platform.system(), # coarse: "Linux" / "Darwin" / "Windows"
351
+ "python_version": platform.python_version(),
352
+ }
353
+
354
+
355
+ def _resolve_distinct_id(conf: cfgmod.CliConfig) -> str:
356
+ """Opaque operator id when logged in, else a stable per-machine anonymous id.
357
+
358
+ ``user_id`` is used only alongside a stored session token, so a logged-out machine
359
+ falls back to its anonymous id (which :func:`reset` rotates on logout).
360
+ """
361
+ if conf.user_id and conf.session_token:
362
+ return conf.user_id
363
+ return _ensure_anonymous_id(conf)
364
+
365
+
366
+ def _ensure_anonymous_id(conf: cfgmod.CliConfig) -> str:
367
+ """Return the persisted anonymous id, generating and saving one on first use."""
368
+ if conf.anonymous_id:
369
+ return conf.anonymous_id
370
+ anon = uuid.uuid4().hex
371
+ conf.anonymous_id = anon
372
+ try:
373
+ cfgmod.save_config(conf)
374
+ except Exception:
375
+ pass # fall back to an in-memory id for this run
376
+ return anon
377
+
378
+
379
+ def _resolve_command_path(argv: List[str]) -> Tuple[Optional[str], Optional[str]]:
380
+ """Resolve ``(group, leaf)`` from argv against the known command tree.
381
+
382
+ Walks tokens, skipping global/option flags (and the value of a value-taking option),
383
+ to find the first known top-level command (``group``) and then, if that group has
384
+ subcommands, the first matching leaf. Only ever returns static names from the
385
+ catalog, so argument values can never be emitted. Generalises the old
386
+ ``session``-only detection to every group.
387
+ """
388
+ known, leaves, _flags, value_flags = _catalog()
389
+ group: Optional[str] = None
390
+ leaf: Optional[str] = None
391
+ i = 0
392
+ while i < len(argv):
393
+ tok = argv[i]
394
+ if tok.startswith("-"):
395
+ name = tok.split("=", 1)[0]
396
+ if "=" not in tok and name in value_flags:
397
+ i += 2 # skip the option's value token
398
+ continue
399
+ i += 1
400
+ continue
401
+ if group is None:
402
+ if tok in known:
403
+ group = tok
404
+ i += 1
405
+ continue
406
+ if leaf is None and tok in leaves.get(group, frozenset()):
407
+ leaf = tok
408
+ break
409
+ i += 1
410
+ return group, leaf
411
+
412
+
413
+ def _detect_subcommand(argv: List[str]) -> Optional[str]:
414
+ """Back-compat shim: the leaf subcommand for the resolved command (or None)."""
415
+ return _resolve_command_path(argv)[1]
416
+
417
+
418
+ def _sanitize_flags(argv: List[str]) -> List[str]:
419
+ """Flag NAMES present in argv, intersected with the known set — never values.
420
+
421
+ ``--opt=value`` is split so the value is dropped, and any unknown token (including
422
+ a value that happens to start with ``-``) is discarded.
423
+ """
424
+ aliases = _catalog()[2]
425
+ seen: List[str] = []
426
+ for tok in argv:
427
+ if not tok.startswith("-"):
428
+ continue
429
+ canonical = aliases.get(tok.split("=", 1)[0])
430
+ if canonical and canonical not in seen:
431
+ seen.append(canonical)
432
+ return seen
@@ -0,0 +1,77 @@
1
+ """Resolve whether CLI telemetry runs, and with what PostHog credentials.
2
+
3
+ Mirrors the dashboard's ``lib/posthog-config.ts``: a public, write-only project key
4
+ shipped in the package, an opt-out env var, and a dev/prod gate — resolved at
5
+ invocation time. This module is intentionally pure (no ``posthog`` import) so it is
6
+ cheap and safe to import and easy to unit-test.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import os
12
+ from dataclasses import dataclass
13
+
14
+ # Public, write-only project key — the SAME PostHog project the dashboard uses
15
+ # (dashboard/lib/posthog-config.ts). Safe to ship in the package: it can only
16
+ # ingest events, not read them.
17
+ POSTHOG_KEY = "phc_Ac1Ww1GqKc0z1SyrRWbmatEeQdlOQIsDEEdP8l8JRgX"
18
+
19
+ # Direct ingest host. The dashboard posts to its own ``/ingest`` path and
20
+ # reverse-proxies to this; a CLI has no first-party origin to proxy through, so it
21
+ # talks to PostHog directly.
22
+ POSTHOG_HOST = "https://us.i.posthog.com"
23
+
24
+ # Tags every event so Cloud CLI data separates from the co-tenant "failproofai"
25
+ # (Enforcement) CLI in the shared Failproof AI project. REQUIRED — the analog of
26
+ # ``posthog.register({ product })``.
27
+ #
28
+ # This was ``"agenteye"`` before the rename. The value change splits the series in
29
+ # PostHog: saved insights filtered on ``product = 'agenteye'`` keep the historical
30
+ # rows and see nothing new. That is deliberate and the discontinuity is harmless
31
+ # here because ``TELEMETRY_DISABLED`` has been ``True`` since well before the
32
+ # rename, so no events were flowing across the boundary in either direction.
33
+ PRODUCT = "fp-cloud-cli"
34
+
35
+ # Master kill switch — telemetry is DISABLED for now (kept in the codebase, not removed).
36
+ # When the PostHog host is unreachable the send path blocks the CLI ~5s/command: the
37
+ # ``analytics.shutdown`` flush is bounded to 1.5s, but the client-build + first ``capture``
38
+ # connect attempt is not, so a blocked network stalls every command (even offline ones like
39
+ # ``version``). Until that path is made fully non-blocking (see the TODO in
40
+ # ``analytics.shutdown``), telemetry stays off. Flip this to ``False`` to re-enable; nothing
41
+ # else was removed, so re-enabling needs no other change.
42
+ TELEMETRY_DISABLED = True
43
+
44
+ _TRUTHY = {"1", "true", "yes"}
45
+
46
+
47
+ def _truthy_env(name: str) -> bool:
48
+ """Match the dashboard's ``isDisabled()`` parse: trim + lowercase, 1/true/yes."""
49
+ return (os.environ.get(name) or "").strip().lower() in _TRUTHY
50
+
51
+
52
+ @dataclass
53
+ class AnalyticsConfig:
54
+ enabled: bool
55
+ api_key: str
56
+ host: str
57
+
58
+
59
+ def is_disabled() -> bool:
60
+ """Opt-out via our own ``FP_ANALYTICS_DISABLED`` or the cross-tool ``DO_NOT_TRACK``."""
61
+ return _truthy_env("FP_ANALYTICS_DISABLED") or _truthy_env("DO_NOT_TRACK")
62
+
63
+
64
+ def is_dev_or_test() -> bool:
65
+ """The CLI analog of the dashboard's ``NODE_ENV === 'production'`` gate.
66
+
67
+ Keeps our own test runs and source checkouts out of the shared project. Customer
68
+ CI usage is intentionally **not** excluded here — that signal is wanted; CI users
69
+ who want out can set ``DO_NOT_TRACK``.
70
+ """
71
+ return "PYTEST_CURRENT_TEST" in os.environ or _truthy_env("FP_CLI_DEV")
72
+
73
+
74
+ def resolve_config() -> AnalyticsConfig:
75
+ """Resolve telemetry settings now (like the dashboard's request-time check)."""
76
+ enabled = not TELEMETRY_DISABLED and not is_disabled() and not is_dev_or_test()
77
+ return AnalyticsConfig(enabled=enabled, api_key=POSTHOG_KEY, host=POSTHOG_HOST)
@@ -0,0 +1,83 @@
1
+ """Derive the telemetry command/flag catalog from the assembled Typer app.
2
+
3
+ Hand-maintained allowlists drift: a new command or flag silently goes untracked
4
+ (lost signal) or, worse, leaks a value. Instead we walk the real Click command
5
+ tree once and build the catalog from it, so coverage is automatic. The anti-drift
6
+ test (`tests/test_telemetry_completeness.py`) asserts this stays exhaustive.
7
+
8
+ Built lazily and cached — the app module imports ``analytics``, so we cannot import
9
+ the app at module load without a cycle. Everything here is read-only introspection.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from functools import lru_cache
15
+ from typing import Dict, FrozenSet, List, Set, Tuple
16
+
17
+ from . import _click_compat as click # the Click Typer is running; see _click_compat
18
+
19
+
20
+ def _option_tokens(opt: click.Parameter) -> List[str]:
21
+ return list(opt.opts) + list(opt.secondary_opts)
22
+
23
+
24
+ def _canonical(tokens: List[str]) -> str:
25
+ longs = [t for t in tokens if t.startswith("--")]
26
+ return longs[0] if longs else tokens[0]
27
+
28
+
29
+ def _takes_value(opt: click.Parameter) -> bool:
30
+ """True for options that consume a following token (so we can skip the value)."""
31
+ return not getattr(opt, "is_flag", False) and not getattr(opt, "count", False)
32
+
33
+
34
+ def _walk(
35
+ cmd: click.Command,
36
+ prefix: Tuple[str, ...],
37
+ known: Set[str],
38
+ leaves: Dict[str, Set[str]],
39
+ flags: Dict[str, str],
40
+ value_flags: Set[str],
41
+ ) -> None:
42
+ for param in getattr(cmd, "params", []):
43
+ # `is_option`, not `isinstance(param, Option)`: Typer's vendored Click has no
44
+ # Option class, so an identity test silently matches nothing and this catalog
45
+ # comes back empty. See `_click_compat`.
46
+ if click.is_option(param):
47
+ tokens = _option_tokens(param)
48
+ if not tokens:
49
+ continue
50
+ canon = _canonical(tokens)
51
+ for tok in tokens:
52
+ flags[tok] = canon
53
+ if _takes_value(param):
54
+ value_flags.update(tokens)
55
+ subcommands = getattr(cmd, "commands", None)
56
+ if subcommands:
57
+ for name, sub in subcommands.items():
58
+ if not prefix:
59
+ known.add(name) # top-level command or group name
60
+ else:
61
+ leaves.setdefault(prefix[0], set()).add(name) # nested leaf
62
+ _walk(sub, prefix + (name,), known, leaves, flags, value_flags)
63
+
64
+
65
+ @lru_cache(maxsize=1)
66
+ def build() -> Tuple[FrozenSet[str], Dict[str, FrozenSet[str]], Dict[str, str], FrozenSet[str]]:
67
+ """Return ``(known_commands, leaf_registry, flag_aliases, value_flags)``."""
68
+ from typer.main import get_command
69
+
70
+ from .app import app # lazy: avoids the app <-> analytics import cycle
71
+
72
+ cli = get_command(app)
73
+ known: Set[str] = set()
74
+ leaves: Dict[str, Set[str]] = {}
75
+ flags: Dict[str, str] = {}
76
+ value_flags: Set[str] = set()
77
+ _walk(cli, (), known, leaves, flags, value_flags)
78
+ return (
79
+ frozenset(known),
80
+ {group: frozenset(subs) for group, subs in leaves.items()},
81
+ dict(flags),
82
+ frozenset(value_flags),
83
+ )