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
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Install/remove/list failproofai hooks for one or more agent CLIs.
2
+ * Install/remove/list failproofai hooks for one or more agent harnesses.
3
3
  *
4
4
  * Per-CLI path resolution and settings I/O live in `./integrations` (one
5
5
  * `Integration` impl per CLI). This module orchestrates: validation, policy
@@ -26,6 +26,23 @@ import { CliError } from "../cli-error";
26
26
  import { hookLogWarn } from "./hook-logger";
27
27
  import { customPoliciesDir, globalPolicyConfigFile } from "./fp-home";
28
28
  import { readActiveCloudManagedPolicies } from "./cloud-managed-policies";
29
+ import { installBundledPack, setPackPolicyEnabled } from "./pack-store";
30
+ import type { ResolvedPack } from "./pack-manifest";
31
+ import { hasInstalledPacks, readInstalledPacks } from "./pack-manifest";
32
+ import {
33
+ chip,
34
+ note,
35
+ nextStep,
36
+ optsFor,
37
+ printBlock,
38
+ rule,
39
+ stack,
40
+ table,
41
+ title,
42
+ warning,
43
+ type ChipState,
44
+ type TableRow,
45
+ } from "./tui";
29
46
 
30
47
  const VALID_POLICY_NAMES = new Set(BUILTIN_POLICIES.map((p) => p.name));
31
48
 
@@ -63,13 +80,167 @@ function resolveFailproofaiBinary(): string {
63
80
  }
64
81
  }
65
82
 
66
- function validatePolicyNames(names: string[]): void {
67
- const invalid = names.filter((n) => !VALID_POLICY_NAMES.has(n));
68
- if (invalid.length > 0) {
69
- const validList = [...VALID_POLICY_NAMES].join(", ");
83
+ /** One policy of one installed pack, resolved from a name the user typed. */
84
+ interface PackPolicyRef {
85
+ packId: string;
86
+ packVersion: string;
87
+ name: string;
88
+ /** The `disabledCustomPolicies` entry the dashboard writes for it. */
89
+ disabledKey: string;
90
+ }
91
+
92
+ /**
93
+ * Split names the user typed into builtins and installed-pack policies.
94
+ *
95
+ * Without this, every name went through `validatePolicyNames`, whose set is the
96
+ * compiled builtins — so `policies --disable block-big-refund` on a pack the
97
+ * user had just installed answered "Unknown policy name" and listed 39 names
98
+ * that were not the one they meant. A pack could be installed and then not
99
+ * managed at all.
100
+ *
101
+ * A builtin wins a bare name, because that is the name people have typed for a
102
+ * year and a third-party pack must not be able to capture it. Two packs
103
+ * declaring the same name is the one case that cannot be guessed, so it is
104
+ * refused with the qualified `<pack-id>:<name>` form spelled out.
105
+ */
106
+ function resolvePolicyNames(names: string[]): { builtins: string[]; packs: PackPolicyRef[] } {
107
+ const builtins: string[] = [];
108
+ const packs: PackPolicyRef[] = [];
109
+ const unknown: string[] = [];
110
+
111
+ let installed: ResolvedPack[] = [];
112
+ try {
113
+ installed = readInstalledPacks().packs;
114
+ } catch {
115
+ // No packs, or an unreadable manifest: names simply resolve as builtins and
116
+ // an unknown one gets the ordinary error. A listing-adjacent command must
117
+ // not fail because a pack manifest is corrupt.
118
+ }
119
+
120
+ const refsFor = (packId: string | null, policyName: string): PackPolicyRef[] =>
121
+ installed
122
+ .filter((pack) => (packId === null || pack.id === packId))
123
+ .filter((pack) => pack.policies.some((p) => p.name === policyName))
124
+ .map((pack) => ({
125
+ packId: pack.id,
126
+ packVersion: pack.version,
127
+ name: policyName,
128
+ disabledKey: `pack:${pack.id}@${pack.version}:${policyName}`,
129
+ }));
130
+
131
+ for (const raw of names) {
132
+ // A PACK first, then the compiled set. This order is the whole fix for
133
+ // `policy remove block-sudo` printing "Disabled 0" while `block-sudo` kept
134
+ // denying: the name resolved to a builtin, the command edited
135
+ // `enabledPolicies`, and `enabledPolicies` stopped deciding anything when
136
+ // this build stopped registering builtins. The pack is where the switch is.
137
+ const direct = refsFor(null, raw);
138
+ if (direct.length === 1) {
139
+ packs.push(direct[0]);
140
+ continue;
141
+ }
142
+ if (direct.length > 1) {
143
+ throw new CliError(
144
+ `"${raw}" is declared by ${direct.length} installed packs.\n` +
145
+ `Name the one you mean:\n` +
146
+ direct.map((m) => ` ${m.packId}:${m.name}`).join("\n"),
147
+ );
148
+ }
149
+ // No pack carries it. Falls back to the compiled name set, which is what a
150
+ // machine still running on the migration shim has.
151
+ if (VALID_POLICY_NAMES.has(raw)) {
152
+ builtins.push(raw);
153
+ continue;
154
+ }
155
+ // `acme/finance:block-big-refund` — a pack id holds a slash, never a colon,
156
+ // so the last colon separates them unambiguously.
157
+ const colon = raw.lastIndexOf(":");
158
+ const qualified = colon > 0
159
+ ? { packId: raw.slice(0, colon), name: raw.slice(colon + 1) }
160
+ : null;
161
+ const matches = qualified
162
+ ? refsFor(qualified.packId, qualified.name)
163
+ : refsFor(null, raw);
164
+
165
+ if (matches.length === 1) {
166
+ packs.push(matches[0]);
167
+ continue;
168
+ }
169
+ if (matches.length > 1) {
170
+ throw new CliError(
171
+ `"${raw}" is declared by ${matches.length} installed packs.\n` +
172
+ `Name the one you mean:\n` +
173
+ matches.map((m) => ` ${m.packId}:${m.name}`).join("\n"),
174
+ );
175
+ }
176
+ unknown.push(raw);
177
+ }
178
+
179
+ if (unknown.length > 0) {
180
+ const packNames = installed.flatMap((pack) =>
181
+ pack.policies.map((p) => `${pack.id}:${p.name}`),
182
+ );
183
+ throw new CliError(
184
+ `Unknown policy name(s): ${unknown.join(", ")}\n` +
185
+ `Valid policies: ${[...VALID_POLICY_NAMES].join(", ")}` +
186
+ (packNames.length > 0 ? `\nFrom installed packs: ${packNames.join(", ")}` : ""),
187
+ );
188
+ }
189
+ return { builtins, packs };
190
+ }
191
+
192
+ /** Turn pack policies on or off, and say what happened. */
193
+ function applyPackPolicies(
194
+ refs: PackPolicyRef[],
195
+ on: boolean,
196
+ scope: HookScope,
197
+ cwd?: string,
198
+ ): void {
199
+ if (refs.length === 0) return;
200
+ for (const ref of refs) {
201
+ const result = setPackPolicyEnabled(ref.packId, ref.name, on);
202
+ if (!result.ok) {
203
+ throw new CliError(`Could not ${on ? "enable" : "disable"} ${ref.name}: ${result.reason}`);
204
+ }
205
+ }
206
+ if (on) {
207
+ // Clearing the dashboard's key too. The selection and the disabled key are
208
+ // two different switches for one policy, and leaving the second one set
209
+ // would report the policy enabled while it stayed off.
210
+ const config = readScopedHooksConfig(scope, cwd);
211
+ const keys = new Set(refs.map((r) => r.disabledKey));
212
+ const remaining = (config.disabledCustomPolicies ?? []).filter((k) => !keys.has(k));
213
+ if (remaining.length !== (config.disabledCustomPolicies ?? []).length) {
214
+ const next: HooksConfig = { ...config, disabledCustomPolicies: remaining };
215
+ if (remaining.length === 0) delete next.disabledCustomPolicies;
216
+ writeScopedHooksConfig(next, scope, cwd);
217
+ }
218
+ }
219
+ for (const ref of refs) {
220
+ console.log(
221
+ `${on ? "Enabled" : "Disabled"} ${ref.name} from pack ${ref.packId}@${ref.packVersion}.`,
222
+ );
223
+ }
224
+ }
225
+
226
+ /**
227
+ * Refuse to "disable" a policy that will register anyway.
228
+ *
229
+ * Removing an `alwaysOn` name from `enabledPolicies` succeeds at the file level
230
+ * and changes nothing at the enforcement level, so without this the CLI reports
231
+ * a policy disabled while it keeps denying — the operator's mental model and the
232
+ * machine's behaviour diverge silently, which is the failure this policy exists
233
+ * to prevent in the first place.
234
+ */
235
+ function rejectAlwaysOnPolicies(names: string[]): void {
236
+ const alwaysOn = new Set(BUILTIN_POLICIES.filter((p) => p.alwaysOn).map((p) => p.name));
237
+ const refused = names.filter((n) => alwaysOn.has(n));
238
+ if (refused.length > 0) {
70
239
  throw new CliError(
71
- `Unknown policy name(s): ${invalid.join(", ")}\n` +
72
- `Valid policies: ${validList}`
240
+ `Cannot disable: ${refused.join(", ")}\n` +
241
+ `This policy stops an agent from switching off failproofai itself, so it ` +
242
+ `is always on and ships with the package. A guard the agent can disable ` +
243
+ `by the means it is meant to prevent is not a guard.`
73
244
  );
74
245
  }
75
246
  }
@@ -151,8 +322,21 @@ async function installHooksImpl(
151
322
  // Validate user input first before any system checks
152
323
  if (policyNames !== undefined && policyNames.length > 0) {
153
324
  const nonAllNames = policyNames.filter((n) => n !== "all");
154
- // Check unknown names first (most actionable error for the user)
155
- if (nonAllNames.length > 0) validatePolicyNames(nonAllNames);
325
+ // Check unknown names first (most actionable error for the user). Pack
326
+ // policies are applied here and taken out of the list: the rest of this
327
+ // function writes `enabledPolicies`, which is a builtin-only set.
328
+ if (nonAllNames.length > 0) {
329
+ const resolved = resolvePolicyNames(nonAllNames);
330
+ applyPackPolicies(resolved.packs, true, scope, cwd);
331
+ if (resolved.packs.length > 0) {
332
+ policyNames = policyNames.filter((n) => n === "all" || resolved.builtins.includes(n));
333
+ // Named ONLY pack policies: the work is done. Carrying on would resolve
334
+ // the failproofai binary and rewrite every CLI's settings to enable a
335
+ // set of builtins nobody asked about — and would fail outright on a
336
+ // machine where the binary is not on PATH, AFTER the pack change landed.
337
+ if (policyNames.length === 0) return;
338
+ }
339
+ }
156
340
  // Then check if "all" is mixed with valid specific names
157
341
  if (policyNames.includes("all") && nonAllNames.length > 0) {
158
342
  throw new CliError(
@@ -290,6 +474,49 @@ async function installHooksImpl(
290
474
  }
291
475
  }
292
476
  writeScopedHooksConfig(configToWrite, scope, cwd);
477
+
478
+ // Choosing policies IS selecting from the pack now. Nothing registers these
479
+ // names from this build any more, so writing `enabledPolicies` and stopping
480
+ // would leave a freshly set-up machine enforcing nothing at all — which is
481
+ // the failure mode this whole product exists to prevent.
482
+ //
483
+ // Installed from the copy vendored in the package: no network, so setup
484
+ // cannot fail behind a proxy, and the machine is guarded the moment it is
485
+ // configured rather than the moment it next reaches github.com.
486
+ // The always-on guard is excluded: a pack may not declare `alwaysOn`, so the
487
+ // pack does not carry it and asking for it by name is a selection the pack
488
+ // cannot satisfy. It ships compiled in and registers regardless.
489
+ const alwaysOnNames = new Set(BUILTIN_POLICIES.filter((p) => p.alwaysOn).map((p) => p.name));
490
+ const fromPack = selectedPolicies.filter((name) => !alwaysOnNames.has(name));
491
+ if (fromPack.length > 0) {
492
+ // ONLY when there is no pack yet. Installing the bundled pack with
493
+ // `only: <selection>` REPLACES whatever the machine had chosen, and
494
+ // `selectedPolicies` is derived from `enabledPolicies` — which is empty on a
495
+ // machine whose pack came from `pack add core`. `policy add block-rm-rf`
496
+ // therefore took a machine from ten guards to one, silently, and nine
497
+ // policies went from denying to allowing.
498
+ //
499
+ // With a pack already installed the names are switched on individually
500
+ // instead, which is additive and touches nothing else.
501
+ if (!hasInstalledPacks()) {
502
+ const bundled = installBundledPack({ only: fromPack });
503
+ if (!bundled.installed) {
504
+ console.log(
505
+ `\nWarning: could not install the policy pack (${bundled.reason}).\n` +
506
+ `Nothing is enforcing yet — run \`failproofai pack add core\` once that is fixed.`,
507
+ );
508
+ }
509
+ } else {
510
+ for (const name of fromPack) {
511
+ for (const pack of readInstalledPacks().packs) {
512
+ if (pack.policies.some((p) => p.name === name)) {
513
+ setPackPolicyEnabled(pack.id, name, true);
514
+ break;
515
+ }
516
+ }
517
+ }
518
+ }
519
+ }
293
520
  console.log(`\nEnabled ${selectedPolicies.length} policy(ies): ${selectedPolicies.join(", ")}\n`);
294
521
  if (removeCustomHooks) {
295
522
  console.log("Custom hooks path cleared.");
@@ -434,7 +661,18 @@ export async function removeHooks(policyNames?: string[], scope: HookScope | "al
434
661
 
435
662
  // Remove specific policies from config (keep hooks installed)
436
663
  if (policyNames && policyNames.length > 0 && !(policyNames.length === 1 && policyNames[0] === "all")) {
437
- validatePolicyNames(policyNames);
664
+ const resolved = resolvePolicyNames(policyNames);
665
+ applyPackPolicies(resolved.packs, false, configScope, cwd);
666
+ policyNames = resolved.builtins;
667
+ rejectAlwaysOnPolicies(policyNames);
668
+ // Named ONLY pack policies: they are off now and there is nothing else to
669
+ // do. Falling through would reach the hook-removal path below with an empty
670
+ // name list, which is the "remove failproofai from every CLI" branch — so
671
+ // `--uninstall <a-pack-policy>` would have torn out every hook on the
672
+ // machine.
673
+ if (resolved.packs.length > 0 && policyNames.length === 0) return;
674
+ }
675
+ if (policyNames && policyNames.length > 0 && !(policyNames.length === 1 && policyNames[0] === "all")) {
438
676
  const config = readScopedHooksConfig(configScope, cwd);
439
677
  const removeSet = new Set(policyNames);
440
678
  const remaining = config.enabledPolicies.filter((p) => !removeSet.has(p));
@@ -593,135 +831,88 @@ export async function removeHooks(policyNames?: string[], scope: HookScope | "al
593
831
  */
594
832
  export async function listHooks(cwd?: string): Promise<void> {
595
833
  const config = readMergedHooksConfig(cwd);
596
- const enabledSet = new Set(config.enabledPolicies);
597
834
  const disabledCustomSet = new Set(config.disabledCustomPolicies ?? []);
835
+ const opts = optsFor(process.stdout);
598
836
 
599
837
  // Determine which scopes have hooks installed (deduplicate when paths overlap, e.g. cwd === home)
600
838
  const uniqueScopes = deduplicateScopes(HOOK_SCOPES, cwd);
601
839
  const installedScopes = uniqueScopes.filter((s) => hooksInstalledInSettings(s, cwd));
602
840
 
603
- // Separate beta from regular policies
604
- const regularPolicies = BUILTIN_POLICIES.filter((p) => !p.beta);
605
- const betaPolicies = BUILTIN_POLICIES.filter((p) => p.beta);
606
-
607
- // Dynamic name column width based on longest policy name
608
- const nameColWidth = Math.max(...BUILTIN_POLICIES.map((p) => p.name.length)) + 2;
609
-
610
- // All known builtin policy names (for unknown policyParams key detection)
611
- const builtinPolicyNames = new Set(BUILTIN_POLICIES.map((p) => p.name));
612
-
613
- // Helper: print params summary lines beneath a policy row
614
- const printParamsSummary = (policyName: string, indent: string) => {
615
- const params = config.policyParams?.[policyName];
616
- if (!params) return;
617
- for (const [key, val] of Object.entries(params)) {
618
- console.log(`${indent} ${key}: ${JSON.stringify(val)}`);
841
+ // Names a `policyParams` key may legitimately use: every policy an installed
842
+ // pack carries. Previously the compiled catalog, which no longer describes
843
+ // what runs.
844
+ const knownPolicyNames = new Set<string>();
845
+ try {
846
+ for (const pack of readInstalledPacks().packs) {
847
+ for (const policy of pack.policies) knownPolicyNames.add(policy.name);
619
848
  }
620
- };
849
+ } catch {
850
+ // Unreadable manifest: skip the typo warning rather than invent one.
851
+ }
621
852
 
622
- const statusCol = 8;
623
- const printSimpleRow = (policy: { name: string; description: string }) => {
624
- const mark = enabledSet.has(policy.name) ? `\x1B[32m\u2713\x1B[0m` : " ";
625
- console.log(` ${mark}${" ".repeat(statusCol - 1)}${policy.name.padEnd(nameColWidth)}${policy.description}`);
626
- printParamsSummary(policy.name, ` ${" ".repeat(statusCol)}`);
627
- };
628
- const printBetaSection = (printRow: (p: { name: string; description: string }) => void) => {
629
- if (betaPolicies.length > 0) {
630
- console.log(`\n \x1B[2m\u2500\u2500 Beta \u2500\u2500\x1B[0m`);
631
- for (const policy of betaPolicies) printRow(policy);
853
+ const groups: Array<string[] | null> = [];
854
+ const packCount = (() => {
855
+ try {
856
+ return readInstalledPacks().packs.reduce(
857
+ (n, pack) => n + (pack.enabled ?? pack.policies.map((p) => p.name)).length,
858
+ 0,
859
+ );
860
+ } catch {
861
+ return 0;
632
862
  }
633
- };
863
+ })();
864
+ groups.push(
865
+ title(
866
+ "failproofai policies",
867
+ installedScopes.length === 0
868
+ ? "not installed"
869
+ : `${installedScopes.join(" + ")} · ${packCount} on`,
870
+ opts,
871
+ ),
872
+ );
634
873
 
635
874
  if (installedScopes.length === 0) {
636
- // State A: No hooks installed — show table with configured state + descriptions
637
- console.log("\nFailproof AI Policies \u2014 not installed\n");
638
-
639
- console.log(` ${"Status".padEnd(statusCol)}${"Name".padEnd(nameColWidth)}Description`);
640
- console.log(` ${"\u2500".repeat(6)} ${"\u2500".repeat(nameColWidth - 2)} ${"\u2500".repeat(38)}`);
641
-
642
- for (const policy of regularPolicies) printSimpleRow(policy);
643
- printBetaSection(printSimpleRow);
644
-
645
- if (config.enabledPolicies.length > 0) {
646
- console.log("\n Policies not installed. Run `failproofai policies --install` to activate.");
647
- } else {
648
- console.log("\n Run `failproofai policies --install` to get started.");
649
- }
650
- console.log(` Config: ${globalPolicyConfigFile()}\n`);
651
- } else if (installedScopes.length === 1) {
652
- // State B: Single scope — table with header row
653
- const scope = installedScopes[0];
654
- console.log(`\nFailproof AI Hook Policies (${scope})\n`);
655
-
656
- console.log(` ${"Status".padEnd(statusCol)}${"Name".padEnd(nameColWidth)}Description`);
657
- console.log(` ${"\u2500".repeat(6)} ${"\u2500".repeat(nameColWidth - 2)} ${"\u2500".repeat(38)}`);
658
-
659
- for (const policy of regularPolicies) printSimpleRow(policy);
660
- printBetaSection(printSimpleRow);
661
-
662
- console.log(`\n Config: ${globalPolicyConfigFile()}\n`);
663
- } else {
664
- // State C: Multiple scopes — column table
665
- const COL = 9;
666
- const scopeLabelMap: Record<HookScope, string> = {
667
- user: "User",
668
- project: "Project",
669
- local: "Local",
670
- };
671
-
672
- console.log("\nFailproof AI Hook Policies\n");
673
-
674
- // Header with only installed scope columns + separator
675
- const buildScopePrefix = () => {
676
- let s = " ";
677
- for (const sc of installedScopes) s += scopeLabelMap[sc].padEnd(COL);
678
- return s;
679
- };
680
- const scopeHeaderWidth = installedScopes.length * COL;
681
- console.log(`${buildScopePrefix()}${"Name".padEnd(nameColWidth)}Description`);
682
- console.log(` ${"\u2500".repeat(scopeHeaderWidth)}${"\u2500".repeat(nameColWidth)}${"\u2500".repeat(38)}`);
683
-
684
- const printMultiScopeRow = (policy: { name: string; description: string }) => {
685
- const enabled = enabledSet.has(policy.name);
686
- let row = " ";
687
- for (const _scope of installedScopes) {
688
- if (enabled) {
689
- row += `\x1B[32m\u2713 ON\x1B[0m` + " ".repeat(COL - 4);
690
- } else {
691
- row += " OFF" + " ".repeat(COL - 5);
692
- }
693
- }
694
- row += policy.name.padEnd(nameColWidth) + policy.description;
695
- console.log(row);
696
- printParamsSummary(policy.name, ` ${" ".repeat(scopeHeaderWidth)}`);
697
- };
698
-
699
- for (const policy of regularPolicies) printMultiScopeRow(policy);
700
-
701
- if (betaPolicies.length > 0) {
702
- console.log(`\n \x1B[2m\u2500\u2500 Beta \u2500\u2500\x1B[0m`);
703
- for (const policy of betaPolicies) printMultiScopeRow(policy);
704
- }
705
-
706
- console.log(`\n Config: ${globalPolicyConfigFile()}`);
707
-
708
- // Multi-scope warning
709
- const scopeNames = installedScopes.join(", ");
710
- console.log();
711
- console.log(`\x1B[33m\u26A0 Hooks in multiple scopes (${scopeNames}).\x1B[0m`);
712
- console.log(" Consider keeping one. Remove with: failproofai policies --uninstall --scope <scope>\n");
875
+ groups.push(
876
+ nextStep(
877
+ "failproofai policies --install",
878
+ config.enabledPolicies.length > 0
879
+ ? "These are configured but NOT installed — no hook is running them:"
880
+ : "Nothing is installed yet. Get started with:",
881
+ opts,
882
+ ),
883
+ );
884
+ }
885
+ // Held back to the end rather than printed here. Everything below this point
886
+ // is another section of the same listing, and a footer in the middle of it
887
+ // reads as the end of the output — while a warning at the very end is the one
888
+ // a reader scrolling back from their prompt actually sees.
889
+ const footer: Array<string[] | null> = [note(`Config: ${globalPolicyConfigFile()}`, opts)];
890
+
891
+ if (installedScopes.length > 1) {
892
+ footer.push(
893
+ warning(
894
+ [
895
+ `Hooks in multiple scopes (${installedScopes.join(", ")}).`,
896
+ "Consider keeping one. Remove with: failproofai policies --uninstall --scope <scope>",
897
+ ],
898
+ opts,
899
+ ),
900
+ );
713
901
  }
714
902
 
715
903
  // Warn about unknown policyParams keys
716
904
  if (config.policyParams) {
717
905
  const unknownKeys: string[] = [];
718
906
  for (const key of Object.keys(config.policyParams)) {
719
- if (!builtinPolicyNames.has(key)) {
720
- console.log(` \x1B[33mWarning: unknown policyParams key "${key}" — possible typo\x1B[0m`);
721
- unknownKeys.push(key);
722
- }
907
+ if (knownPolicyNames.size > 0 && !knownPolicyNames.has(key)) unknownKeys.push(key);
723
908
  }
724
909
  if (unknownKeys.length > 0) {
910
+ footer.push(
911
+ warning(
912
+ unknownKeys.map((key) => `unknown policyParams key "${key}" — possible typo`),
913
+ opts,
914
+ ),
915
+ );
725
916
  try {
726
917
  await trackHookEvent(getInstanceId(), "policy_params_validation_warning", {
727
918
  unknown_keys_count: unknownKeys.length,
@@ -734,30 +925,38 @@ export async function listHooks(cwd?: string): Promise<void> {
734
925
  // Explicit Custom Policies section
735
926
  const explicitPaths = configuredCustomPolicyPaths(config);
736
927
  if (explicitPaths.length > 0) {
737
- console.log(`\n \u2500\u2500 Custom Policies \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`);
928
+ groups.push(rule("Custom Policies", opts));
738
929
  for (const path of explicitPaths) {
739
930
  // Enforcement resolves configured paths from the project config root.
740
931
  // Use the same canonical path here so the ID checked by the CLI exactly
741
932
  // matches the ID written by the dashboard.
742
933
  const absPath = resolve(findProjectConfigDir(cwd ?? process.cwd()), path);
743
- console.log(` ${absPath}`);
934
+ groups.push(note(absPath, opts));
744
935
  if (!existsSync(absPath)) {
745
- console.log(` \x1B[31m\u2717 File not found: ${absPath}\x1B[0m`);
936
+ groups.push(warning([`file not found: ${absPath}`], opts));
746
937
  continue;
747
938
  }
748
939
  const hooks = await loadCustomHooks(absPath);
749
940
  if (hooks.length === 0) {
750
- console.log(` \x1B[31m\u2717 ERR failed to load (check ~/.failproofai/logs/hooks.log)\x1B[0m`);
941
+ groups.push(
942
+ warning(["failed to load (check ~/.failproofai/logs/hooks.log)"], opts),
943
+ );
751
944
  } else {
752
- const descColWidth = nameColWidth;
753
- for (const hook of hooks) {
754
- const disabled = disabledCustomSet.has(`custom:${absPath}:${hook.name}`);
755
- const status = disabled ? "\x1B[2m OFF\x1B[0m" : "\x1B[32m\u2713 ON\x1B[0m";
756
- console.log(` ${status} ${hook.name.padEnd(descColWidth)}${hook.description ?? ""}`);
757
- }
945
+ groups.push(
946
+ table(
947
+ {
948
+ head: ["", "Name", "Description"],
949
+ rows: hooks.map((hook) => [
950
+ chip(disabledCustomSet.has(`custom:${absPath}:${hook.name}`) ? "off" : "on", opts),
951
+ hook.name,
952
+ hook.description ?? "",
953
+ ]),
954
+ },
955
+ opts,
956
+ ),
957
+ );
758
958
  }
759
959
  }
760
- console.log();
761
960
  }
762
961
 
763
962
  // Convention Policies section (.failproofai/policies/*policies.{js,mjs,ts})
@@ -801,43 +1000,82 @@ export async function listHooks(cwd?: string): Promise<void> {
801
1000
  for (const t of targets) discovered[t].push({ file, hooks });
802
1001
  };
803
1002
 
804
- console.log(`\n \u2500\u2500 Convention Policies \u2014 ${label} (${dir}) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`);
805
- // `nameColWidth` is sized to the longest BUILTIN name, but a convention
806
- // filename can be longer \u2014 `padEnd` is then a no-op and the hook count runs
807
- // straight into the filename with no space
808
- // (`enforce-bengaluru-event-links-policies.mjs1 hook(s)`). Widen to fit the
809
- // files actually being printed, keeping a two-space gutter.
810
- const colWidth = Math.max(nameColWidth, ...files.map((f) => basename(f).length + 2));
1003
+ groups.push(rule(`Convention Policies ${label}`, opts));
1004
+ groups.push(note(dir, opts));
1005
+ const rows: TableRow[] = [];
811
1006
  for (const file of files) {
1007
+ const filename = basename(file);
812
1008
  try {
813
1009
  const hooks = await loadCustomHooks(file);
814
- const filename = basename(file);
815
1010
  record(filename, hooks.map((h) => h.name));
816
1011
  if (hooks.length === 0) {
817
- console.log(` \x1B[31m\u2717\x1B[0m ${filename.padEnd(colWidth)}\x1B[31mfailed to load\x1B[0m`);
818
- } else {
819
- const hookStates = hooks.map((hook) => ({
820
- hook,
821
- disabled: disabledCustomSet.has(`convention:${policyScope}:${filename}:${hook.name}`),
822
- }));
823
- const disabledCount = hookStates.filter((entry) => entry.disabled).length;
824
- const status = disabledCount === 0
825
- ? "\x1B[32m\u2713 ON\x1B[0m"
826
- : disabledCount === hooks.length
827
- ? "\x1B[2m OFF\x1B[0m"
828
- : "\x1B[33m\u25D0 MIXED\x1B[0m";
829
- const hookSummary = hookStates
830
- .map(({ hook, disabled }) => `${hook.name}${disabled ? " (OFF)" : ""}`)
831
- .join(", ");
832
- console.log(` ${status} ${filename.padEnd(colWidth)}${hooks.length} hook(s): ${hookSummary}`);
1012
+ rows.push({ cells: [chip("failed", opts), filename, "failed to load"] });
1013
+ continue;
833
1014
  }
1015
+ const hookStates = hooks.map((hook) => ({
1016
+ hook,
1017
+ disabled: disabledCustomSet.has(`convention:${policyScope}:${filename}:${hook.name}`),
1018
+ }));
1019
+ const disabledCount = hookStates.filter((entry) => entry.disabled).length;
1020
+ const state: ChipState =
1021
+ disabledCount === 0 ? "on" : disabledCount === hooks.length ? "off" : "mixed";
1022
+ const hookSummary = hookStates
1023
+ .map(({ hook, disabled }) => `${hook.name}${disabled ? " (OFF)" : ""}`)
1024
+ .join(", ");
1025
+ rows.push({
1026
+ cells: [chip(state, opts), filename, `${hooks.length} hook(s): ${hookSummary}`],
1027
+ });
834
1028
  } catch {
835
- const filename = basename(file);
836
1029
  record(filename, []);
837
- console.log(` \x1B[31m\u2717\x1B[0m ${filename.padEnd(colWidth)}\x1B[31merror\x1B[0m`);
1030
+ rows.push({ cells: [chip("failed", opts), filename, "error"] });
838
1031
  }
839
1032
  }
840
- console.log();
1033
+ groups.push(table({ head: ["", "File", "Hooks"], rows }, opts));
1034
+ }
1035
+
1036
+ // Installed packs. They enforce on this machine exactly like every section
1037
+ // above, and until now the only way to see one was `failproofai pack list` —
1038
+ // so the command that answers "what is enforcing here?" answered it with a
1039
+ // subset, for the one source a person had to go out of their way to install.
1040
+ try {
1041
+ const { packs, errors } = readInstalledPacks();
1042
+ for (const pack of packs) {
1043
+ const taken = pack.enabled ?? pack.policies.map((p) => p.name);
1044
+ groups.push(rule(`Pack — ${pack.id}@${pack.version}`, opts));
1045
+ groups.push(
1046
+ table(
1047
+ {
1048
+ head: ["", "Name", "Description"],
1049
+ rows: pack.policies.map((policy) => {
1050
+ const disabled = disabledCustomSet.has(
1051
+ `pack:${pack.id}@${pack.version}:${policy.name}`,
1052
+ );
1053
+ // `observe` evaluates and discards its verdict, so a row reading
1054
+ // ON would claim enforcement the pack deliberately is not doing.
1055
+ const state: ChipState =
1056
+ pack.effect === "observe"
1057
+ ? "observe"
1058
+ : !taken.includes(policy.name) || disabled
1059
+ ? "off"
1060
+ : "pack";
1061
+ return [chip(state, opts), policy.name, policy.description];
1062
+ }),
1063
+ },
1064
+ opts,
1065
+ ),
1066
+ );
1067
+ }
1068
+ if (errors.length > 0) {
1069
+ groups.push(
1070
+ warning(
1071
+ errors.map((err) => `pack ${err.id ?? "(unnamed)"} will not load: ${err.reason}`),
1072
+ opts,
1073
+ ),
1074
+ );
1075
+ }
1076
+ } catch {
1077
+ // Same rule as the cloud section below: a listing must not be the thing
1078
+ // that turns an unreadable manifest into a broken command.
841
1079
  }
842
1080
 
843
1081
  // Cloud-managed policies. These enforce on this machine exactly like the two
@@ -852,21 +1090,27 @@ export async function listHooks(cwd?: string): Promise<void> {
852
1090
  try {
853
1091
  const cloud = readActiveCloudManagedPolicies();
854
1092
  if (cloud.length > 0) {
855
- const gen = cloud[0].deployment;
856
- console.log(
857
- `\n \u2500\u2500 Cloud-managed \u2014 deployment ${gen} \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`,
1093
+ groups.push(rule(`Cloud-managed deployment ${cloud[0].deployment}`, opts));
1094
+ groups.push(
1095
+ table(
1096
+ {
1097
+ head: ["", "Policy", "Version"],
1098
+ rows: cloud.map((artifact) => [
1099
+ // `observe` is evaluated and then has its verdict discarded, so a
1100
+ // row that read "ON" would claim enforcement this policy
1101
+ // deliberately is not doing.
1102
+ chip(artifact.effect === "observe" ? "observe" : "cloud", opts),
1103
+ artifact.id,
1104
+ `v${artifact.version}`,
1105
+ ]),
1106
+ flex: 1,
1107
+ },
1108
+ opts,
1109
+ ),
1110
+ );
1111
+ groups.push(
1112
+ note("Managed from the dashboard — not switchable with `failproofai policies`.", opts),
858
1113
  );
859
- const colWidth = Math.max(nameColWidth, ...cloud.map((c) => c.id.length + 2));
860
- for (const artifact of cloud) {
861
- // `observe` is evaluated and then has its verdict discarded, so a row
862
- // that read "ON" would claim enforcement this policy deliberately is
863
- // not doing.
864
- const status =
865
- artifact.effect === "observe" ? "\x1B[33m\u25D0 OBS\x1B[0m" : "\x1B[32m\u2713 ON\x1B[0m";
866
- console.log(` ${status} ${artifact.id.padEnd(colWidth)}v${artifact.version}`);
867
- }
868
- console.log("\n Managed from the dashboard \u2014 not switchable with `failproofai policies`.");
869
- console.log();
870
1114
  }
871
1115
  } catch {
872
1116
  // A machine with no deployment, or an unreadable manifest, simply has no
@@ -874,6 +1118,8 @@ export async function listHooks(cwd?: string): Promise<void> {
874
1118
  // the thing that turns a bad manifest into a broken command.
875
1119
  }
876
1120
 
1121
+ printBlock(process.stdout, stack(...groups, ...footer));
1122
+
877
1123
  // Mirror what was just listed into the USER config. Safe here because
878
1124
  // `failproofai policies` is a one-shot command — never do this on the hook
879
1125
  // path (see the HooksConfig.conventionPolicies doc comment).