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
@@ -89,14 +89,14 @@ export const MIGRATIONS: readonly Migration[] = [
89
89
  from: 1,
90
90
  to: 3,
91
91
  describe:
92
- "layout 1 → 3: carry the decision log out of cache/, keep the policy config in place, drop the layout-1 credential files",
92
+ "layout 1 → 3: carry the decision log out of cache/, keep the policy config in place, drop the layout-1 credential files, and install the policy pack that now does the enforcing — carrying the policies you had enabled into its selection",
93
93
  run: () => resetHome(1, 3),
94
94
  },
95
95
  {
96
96
  from: 2,
97
97
  to: 3,
98
98
  describe:
99
- "layout 2 → 3: carry config.toml and credentials.toml into JSON, move custom-policies/ back up into policies/, nest the policy config at the root",
99
+ "layout 2 → 3: carry config.toml and credentials.toml into JSON, move custom-policies/ back up into policies/, nest the policy config at the root, and install the policy pack that now does the enforcing — carrying the policies you had enabled into its selection",
100
100
  run: () => resetHome(2, 3),
101
101
  },
102
102
  {
@@ -0,0 +1,505 @@
1
+ /**
2
+ * `failproofai pack add | remove | list`.
3
+ *
4
+ * Presentation only — every rule about what a pack may be lives in
5
+ * `pack-manifest.ts` (what may load) and `pack-store.ts` (what may install).
6
+ * This layer decides nothing; it formats.
7
+ */
8
+ import { createHash } from "node:crypto";
9
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
10
+ import { resolve } from "node:path";
11
+ import { parsePackIdentity, parsePackPolicy, readInstalledPacks } from "./pack-manifest";
12
+ import {
13
+ PACK_CHECKSUMS_ASSET,
14
+ PACK_ENTRY_ASSET,
15
+ PACK_MANIFEST_ASSET,
16
+ addPack,
17
+ checkPackArtifact,
18
+ CORE_ALIASES,
19
+ fetchPackPreview,
20
+ installBundledPack,
21
+ removePack,
22
+ slugifyCategory,
23
+ } from "./pack-store";
24
+ import type { PolicyEffect } from "./cloud-managed-policies";
25
+ import { loadCustomHooks } from "./custom-hooks-loader";
26
+ import {
27
+ chip,
28
+ emptyState,
29
+ note,
30
+ nextStep,
31
+ optsFor,
32
+ rows as kitRows,
33
+ rule,
34
+ stack,
35
+ table,
36
+ title,
37
+ warning,
38
+ } from "./tui";
39
+
40
+ export interface PackCliResult {
41
+ lines: string[];
42
+ exitCode: number;
43
+ }
44
+
45
+ const ok = (lines: string[]): PackCliResult => ({ lines, exitCode: 0 });
46
+ const fail = (lines: string[]): PackCliResult => ({ lines, exitCode: 1 });
47
+
48
+ function parseList(rest: string[], flag: string): string[] | undefined {
49
+ const idx = rest.findIndex((a) => a === flag || a.startsWith(`${flag}=`));
50
+ if (idx === -1) return undefined;
51
+ const raw = rest[idx].includes("=") ? rest[idx].split("=").slice(1).join("=") : rest[idx + 1];
52
+ if (!raw || raw.startsWith("--")) return [];
53
+ return raw.split(",").map((s) => s.trim()).filter(Boolean);
54
+ }
55
+
56
+ /** Flags that take a separate value, so it is never mistaken for the source. */
57
+ const VALUE_FLAGS = new Set(["--only", "--policy", "--category"]);
58
+
59
+ /** Find the positional source without mistaking a flag's separate value for it. */
60
+ export function packAddSource(rest: string[]): string | undefined {
61
+ const consumed = new Set<number>();
62
+ for (let i = 0; i < rest.length; i += 1) {
63
+ if (VALUE_FLAGS.has(rest[i])) consumed.add(i + 1);
64
+ }
65
+ return rest.find((arg, index) => !arg.startsWith("--") && !consumed.has(index));
66
+ }
67
+
68
+ /** Names taken by our own policies, so a selection can be checked before install. */
69
+ function selectionFrom(rest: string[]): { only?: string[]; categories?: string[]; all?: boolean } {
70
+ // `--policy` reads right for one ("give me this policy"), `--only` for a set.
71
+ // They are the same switch; taking both means neither is the wrong guess.
72
+ const only = parseList(rest, "--policy") ?? parseList(rest, "--only");
73
+ const categories = parseList(rest, "--category");
74
+ return {
75
+ ...(only ? { only } : {}),
76
+ ...(categories ? { categories } : {}),
77
+ ...(rest.includes("--all") ? { all: true } : {}),
78
+ };
79
+ }
80
+
81
+ /** Name a handful, then say how many more and where to see them. A 37-name wall
82
+ * is not information, and a count alone is not either. */
83
+ function summarise(names: string[], limit = 6): string {
84
+ if (names.length <= limit) return names.join(", ");
85
+ return `${names.slice(0, limit).join(", ")} +${names.length - limit} more`;
86
+ }
87
+
88
+
89
+ /**
90
+ * Turn a policy file into the three assets a GitHub release needs.
91
+ *
92
+ * The publishing side of the lane. Everything about what a pack IS was only
93
+ * discoverable by reading `pack-manifest.ts` and this repo's own build script —
94
+ * so a stranger who wanted to publish policies had to reverse-engineer a
95
+ * manifest, a checksum file and an asset naming convention, and would find out
96
+ * they got it wrong when somebody else's `pack add` refused it.
97
+ *
98
+ * It does NOT bundle. Only the ENTRY is content-addressed, so a pack whose entry
99
+ * imports local files could not honestly claim to be digest-pinned — the digest
100
+ * would cover one file out of several. A multi-file source must be bundled by
101
+ * its author first (esbuild, bun, rollup); this refuses it rather than shipping
102
+ * a promise it cannot keep. Not bundling here also keeps the command runnable on
103
+ * plain node, which is what the published CLI is.
104
+ *
105
+ * Every policy is validated with `parsePackPolicy` — the LOADER's own rules — so
106
+ * a pack that could never install fails here, where the author can fix it,
107
+ * rather than on a stranger's machine.
108
+ */
109
+ async function build(rest: string[]): Promise<PackCliResult> {
110
+ const flag = (name: string): string | undefined => {
111
+ const i = rest.findIndex((a) => a === `--${name}` || a.startsWith(`--${name}=`));
112
+ if (i === -1) return undefined;
113
+ return rest[i].includes("=") ? rest[i].split("=").slice(1).join("=") : rest[i + 1];
114
+ };
115
+ const entry = packAddSource(rest) ?? flag("entry");
116
+ const id = flag("id");
117
+ const version = flag("version");
118
+ const effect = flag("effect") ?? "enforce";
119
+ const outDir = resolve(flag("out") ?? "dist-pack");
120
+
121
+ if (!entry || !id || !version) {
122
+ return fail([
123
+ "Usage: failproofai pack build <entry.mjs> --id <publisher/name> --version <version>",
124
+ " [--out <dir>] [--effect enforce|observe]",
125
+ ]);
126
+ }
127
+ let identity: { id: string; version: string; effect: PolicyEffect };
128
+ try {
129
+ identity = parsePackIdentity({ id, version, effect });
130
+ } catch (err) {
131
+ return fail([err instanceof Error ? err.message : String(err)]);
132
+ }
133
+
134
+ const entryPath = resolve(entry);
135
+ if (!existsSync(entryPath)) return fail([`No such file: ${entryPath}`]);
136
+
137
+ // Refused rather than bundled: see the note above. A relative specifier is the
138
+ // only kind that would be rewritten by the loader and left outside the digest.
139
+ const source = readFileSync(entryPath, "utf8");
140
+ const localImport = /(?:^|\n)\s*(?:import|export)[^;\n]*from\s+["'](\.[^"']*)["']/.exec(source);
141
+ if (localImport) {
142
+ return fail([
143
+ `${entryPath} imports ${localImport[1]}, and only the entry file is digest-pinned.`,
144
+ "Bundle it to a single file first (esbuild, bun build, rollup), then build the pack from that.",
145
+ ]);
146
+ }
147
+
148
+ let hooks;
149
+ try {
150
+ hooks = await loadCustomHooks(entryPath, { strict: true });
151
+ } catch (err) {
152
+ return fail([`Could not load ${entryPath}: ${err instanceof Error ? err.message : String(err)}`]);
153
+ }
154
+ if (hooks.length === 0) {
155
+ return fail([
156
+ `${entryPath} registered no policies.`,
157
+ "A pack entry calls customPolicies.add({ name, description, match, fn }) for each one.",
158
+ ]);
159
+ }
160
+
161
+ const policies: unknown[] = [];
162
+ for (const [index, hook] of hooks.entries()) {
163
+ // `category` and `defaultEnabled` are pack-manifest fields a plain custom
164
+ // policy has no reason to carry, so they are read off the registration when
165
+ // the author set them and defaulted when not. `defaultEnabled` defaults to
166
+ // FALSE: a pack's declared defaults are what `pack add` switches on with no
167
+ // flags, and switching on a stranger's every policy unattended is the
168
+ // installer opinion this lane already refused once.
169
+ const extra = hook as unknown as { category?: unknown; defaultEnabled?: unknown };
170
+ const candidate = {
171
+ name: hook.name,
172
+ description: hook.description ?? "",
173
+ category: typeof extra.category === "string" && extra.category ? extra.category : "General",
174
+ defaultEnabled: extra.defaultEnabled === true,
175
+ match: hook.match ?? {},
176
+ };
177
+ try {
178
+ policies.push(parsePackPolicy(identity.id, candidate, index));
179
+ } catch (err) {
180
+ return fail([err instanceof Error ? err.message : String(err)]);
181
+ }
182
+ }
183
+
184
+ const manifest =
185
+ JSON.stringify(
186
+ { id: identity.id, version: identity.version, effect: identity.effect, policies },
187
+ null,
188
+ 2,
189
+ ) + "\n";
190
+ mkdirSync(outDir, { recursive: true });
191
+ const manifestPath = resolve(outDir, PACK_MANIFEST_ASSET);
192
+ const entryOut = resolve(outDir, PACK_ENTRY_ASSET);
193
+ writeFileSync(manifestPath, manifest, "utf8");
194
+ copyFileSync(entryPath, entryOut);
195
+ const sha = (bytes: Buffer | string) => createHash("sha256").update(bytes).digest("hex");
196
+ writeFileSync(
197
+ resolve(outDir, PACK_CHECKSUMS_ASSET),
198
+ `${sha(manifest)} ${PACK_MANIFEST_ASSET}\n${sha(readFileSync(entryOut))} ${PACK_ENTRY_ASSET}\n`,
199
+ "utf8",
200
+ );
201
+
202
+ const on = policies.filter((p) => (p as { defaultEnabled?: boolean }).defaultEnabled).length;
203
+ return ok([
204
+ `Built ${identity.id}@${identity.version} — ${policies.length} policies, ${on} on by default.`,
205
+ ` ${outDir}/${PACK_MANIFEST_ASSET}`,
206
+ ` ${outDir}/${PACK_ENTRY_ASSET}`,
207
+ ` ${outDir}/${PACK_CHECKSUMS_ASSET}`,
208
+ "",
209
+ `Publish: attach all three to a GitHub release tagged ${identity.version}, then anyone runs:`,
210
+ ` failproofai pack add <owner>/<repo>`,
211
+ ]);
212
+ }
213
+
214
+ async function add(rest: string[]): Promise<PackCliResult> {
215
+ const source = packAddSource(rest);
216
+ const selection = selectionFrom(rest);
217
+
218
+ // Our own pack, by the short name — and from the copy inside this package, so
219
+ // it is instant and works with no network at all.
220
+ if ((source && CORE_ALIASES.has(source.toLowerCase())) || rest.includes("--bundled")) {
221
+ const result = installBundledPack(selection);
222
+ if (!result.installed) {
223
+ return fail([`Could not install the Failproof AI policies: ${result.reason}`]);
224
+ }
225
+ const enabled = result.enabled ?? [];
226
+ const available = result.available ?? [];
227
+ const skipped = available.filter((n) => !enabled.includes(n));
228
+ const lines = [
229
+ `Installed ${result.id}@${result.version} from this package — no network needed.`,
230
+ ...(result.replaced?.length
231
+ ? [` replaced ${result.replaced.join(", ")} — same policies, renamed; your selection was kept`]
232
+ : []),
233
+ ` enabled (${enabled.length}/${available.length}): ${summarise(enabled)}`,
234
+ ];
235
+ if (skipped.length > 0) {
236
+ lines.push(` not enabled (${skipped.length}): ${summarise(skipped)}`);
237
+ lines.push("");
238
+ lines.push(" one policy: failproofai pack add core --policy block-rm-rf");
239
+ lines.push(" a category: failproofai pack add core --category dangerous-commands");
240
+ lines.push(" everything: failproofai pack add core --all");
241
+ lines.push(" see them all: failproofai pack list");
242
+ }
243
+ return ok(lines);
244
+ }
245
+
246
+ if (!source) {
247
+ return fail(["Usage: failproofai pack add <source> [--only a,b] [--category x,y] [--all]"]);
248
+ }
249
+ if (selection.only && selection.only.length === 0) {
250
+ return fail(["--policy needs at least one policy name, comma-separated"]);
251
+ }
252
+ if (selection.categories && selection.categories.length === 0) {
253
+ return fail(["--category needs at least one category, comma-separated"]);
254
+ }
255
+
256
+ try {
257
+ const result = await addPack(source, selection);
258
+ const lines = [
259
+ ...(result.replaced?.length
260
+ ? [`Replaced ${result.replaced.join(", ")} — same policies under a new name; your selection was kept.`]
261
+ : []),
262
+ result.resolvedFromLatest
263
+ ? `Installed ${result.id}@${result.version} from ${result.source} (newest release; pinned to ${result.tag})`
264
+ : `Installed ${result.id}@${result.version} from ${result.source}`,
265
+ ];
266
+ const skipped = result.available.filter((n) => !result.enabled.includes(n));
267
+
268
+ // Say WHY this set is on. Without it, "10 of 38 enabled" reads like
269
+ // something went wrong rather than like the pack's own recommendation.
270
+ const why = {
271
+ defaults: "the pack's defaults",
272
+ selected: "your selection",
273
+ carried: "your existing selection",
274
+ all: "everything in the pack",
275
+ }[result.selection];
276
+ lines.push(` enabled (${result.enabled.length}/${result.available.length}, ${why}): ${summarise(result.enabled)}`);
277
+
278
+ if (skipped.length > 0) {
279
+ lines.push(` not enabled (${skipped.length}): ${summarise(skipped)}`);
280
+ lines.push("");
281
+ lines.push(` see all: failproofai pack list`);
282
+ if (result.categories.length > 0) {
283
+ lines.push(` by category: failproofai pack add ${source} --category ${result.categories.slice(0, 3).join(",")}`);
284
+ }
285
+ lines.push(` everything: failproofai pack add ${source} --all`);
286
+ }
287
+ return ok(lines);
288
+ } catch (err) {
289
+ return fail([`Could not install pack: ${err instanceof Error ? err.message : String(err)}`]);
290
+ }
291
+ }
292
+
293
+ function remove(rest: string[]): PackCliResult {
294
+ const id = rest[0];
295
+ if (!id) return fail(["Usage: failproofai pack remove <publisher/name>"]);
296
+ if (!removePack(id)) return fail([`No installed pack with id ${id}`]);
297
+ return ok([
298
+ `Removed ${id}. Its artifact is kept on disk, so re-adding it works offline.`,
299
+ ]);
300
+ }
301
+
302
+ /**
303
+ * What a pack CONTAINS, for a pack this machine has not installed.
304
+ *
305
+ * `failproofai policies` already lists everything installed, packs included, so
306
+ * the only thing missing was the pack you are still deciding about. Reading the
307
+ * manifest answers that without installing it — and deliberately without
308
+ * downloading or importing the entry artifact, so looking at a stranger's pack
309
+ * cannot run a stranger's code.
310
+ */
311
+ async function listRemote(source: string): Promise<PackCliResult> {
312
+ const opts = optsFor(process.stdout);
313
+ let preview;
314
+ try {
315
+ preview = await fetchPackPreview(source);
316
+ } catch (err) {
317
+ return fail([`Could not read ${source}: ${err instanceof Error ? err.message : String(err)}`]);
318
+ }
319
+
320
+ const defaults = preview.policies.filter((p) => p.defaultEnabled);
321
+ const categories = [...new Set(preview.policies.map((p) => p.category))];
322
+ const rows: Array<string[] | { section: string }> = [];
323
+ for (const category of categories) {
324
+ const inCategory = preview.policies.filter((p) => p.category === category);
325
+ const on = inCategory.filter((p) => p.defaultEnabled).length;
326
+ rows.push({
327
+ section: `${category} — ${on}/${inCategory.length} on by default · ${slugifyCategory(category)}`,
328
+ });
329
+ for (const policy of inCategory) {
330
+ // The publisher's DEFAULTS, not a machine's state — this pack is not
331
+ // installed, so a row claiming ON would be describing nothing.
332
+ rows.push([
333
+ policy.defaultEnabled ? "default" : "opt-in",
334
+ policy.name,
335
+ policy.description,
336
+ ]);
337
+ }
338
+ }
339
+
340
+ return ok(
341
+ stack(
342
+ title(
343
+ `${preview.id}@${preview.version}`,
344
+ `${preview.policies.length} policies · ${categories.length} categories`,
345
+ opts,
346
+ ),
347
+ note(
348
+ `Not installed. ${defaults.length} of ${preview.policies.length} are on by default; the rest are opt-in.` +
349
+ (preview.effect === "observe" ? " This pack OBSERVES — it records and blocks nothing." : ""),
350
+ opts,
351
+ ),
352
+ preview.resolvedFromLatest ? note(`Newest release: ${preview.source}`, opts) : null,
353
+ table({ head: ["", "", ""], rows }, opts),
354
+ nextStep(`failproofai pack add ${source}`, "Install the defaults with:", opts),
355
+ note("Or take part of it: --policy <a,b>, --category <x,y>, --all", opts),
356
+ ),
357
+ );
358
+ }
359
+
360
+ async function list(): Promise<PackCliResult> {
361
+ const { packs, errors } = readInstalledPacks();
362
+ const opts = optsFor(process.stdout);
363
+ const policyCount = packs.reduce((n, pack) => n + pack.policies.length, 0);
364
+ const head = title(
365
+ "failproofai pack list",
366
+ packs.length === 0
367
+ ? undefined
368
+ : `${packs.length} pack${packs.length === 1 ? "" : "s"} · ${policyCount} policies`,
369
+ opts,
370
+ );
371
+
372
+ if (packs.length === 0 && errors.length === 0) {
373
+ return ok(
374
+ stack(
375
+ head,
376
+ emptyState(
377
+ {
378
+ what: "No packs installed.",
379
+ hint: "Install one with:",
380
+ cmd: "failproofai pack add github:owner/repo@tag",
381
+ },
382
+ opts,
383
+ ),
384
+ ),
385
+ );
386
+ }
387
+
388
+ const groups: Array<string[] | null> = [head];
389
+ const broken: string[] = [];
390
+ for (const pack of packs) {
391
+ const taken = pack.enabled ?? pack.policies.map((p) => p.name);
392
+ // Importing it is the only way to know it still loads. A listing that reads
393
+ // healthy while the machine is denying every tool call because of this pack
394
+ // is worse than no listing.
395
+ const failure = await checkPackArtifact(pack.path, pack.policies.map((p) => p.name));
396
+ if (failure) broken.push(`${pack.id}@${pack.version} ${failure}`);
397
+ groups.push(rule(`${pack.id}@${pack.version}`, opts));
398
+ groups.push(
399
+ kitRows(
400
+ [
401
+ ["source", pack.source],
402
+ ["digest", `${pack.sha256.slice(0, 16)}…`],
403
+ ["effect", pack.effect],
404
+ ["enabled", `${taken.length}/${pack.policies.length}`],
405
+ ...(failure ? ([["health", "WILL NOT LOAD"]] as Array<[string, string]>) : []),
406
+ ],
407
+ opts,
408
+ ),
409
+ );
410
+ // The category is a COLUMN rather than a set of sub-headings because it is
411
+ // what `--category` selects on: seeing the slug next to every policy is what
412
+ // tells someone the flag exists, and the suggestion below spells it out.
413
+ // Four columns leave a description about 24 characters wide on an
414
+ // 80-column terminal, which is not a description. Below 100 the category
415
+ // column goes and its slugs are named once underneath instead.
416
+ const wide = opts.cols >= 100;
417
+ groups.push(
418
+ table(
419
+ {
420
+ head: wide ? ["", "Policy", "Category", "Description"] : ["", "Policy", "Description"],
421
+ rows: pack.policies.map((policy) =>
422
+ wide
423
+ ? [
424
+ chip(taken.includes(policy.name) ? "on" : "off", opts),
425
+ policy.name,
426
+ policy.category,
427
+ policy.description,
428
+ ]
429
+ : [
430
+ chip(taken.includes(policy.name) ? "on" : "off", opts),
431
+ policy.name,
432
+ policy.description,
433
+ ],
434
+ ),
435
+ },
436
+ opts,
437
+ ),
438
+ );
439
+ const slugs = [...new Set(pack.policies.map((p) => slugifyCategory(p.category)))];
440
+ if (!wide && slugs.length > 0) {
441
+ groups.push(note(`Categories: ${slugs.join(", ")}`, opts));
442
+ }
443
+ // The RECORDED SOURCE, never the manifest id. `failproofai/builtins` is an
444
+ // id, not a repository, so suggesting `pack add failproofai/builtins` hands
445
+ // the user a command that resolves nothing. A `bundled:` pack came off the
446
+ // package rather than a release and has no `pack add` form at all.
447
+ const source = pack.source.startsWith("bundled:") ? null : pack.source;
448
+ if (source && taken.length < pack.policies.length && slugs.length > 0) {
449
+ groups.push(
450
+ nextStep(
451
+ `failproofai pack add ${source} --category ${slugs.slice(0, 3).join(",")}`,
452
+ "Take a whole category with:",
453
+ opts,
454
+ ),
455
+ );
456
+ }
457
+ }
458
+
459
+ // Never silent: a pack that was installed and now refuses to load is exactly
460
+ // the state someone needs told about, since the machine is enforcing less
461
+ // than its manifest says.
462
+ if (errors.length > 0) {
463
+ groups.push(
464
+ warning(
465
+ errors.map((err) => `NOT LOADED ${err.id ?? "(unnamed)"}: ${err.reason}`),
466
+ opts,
467
+ ),
468
+ );
469
+ }
470
+
471
+ if (broken.length > 0) {
472
+ groups.push(
473
+ warning(
474
+ [
475
+ ...broken,
476
+ "This machine denies the events those policies covered until it is fixed.",
477
+ ],
478
+ opts,
479
+ ),
480
+ );
481
+ }
482
+ const lines = stack(...groups);
483
+ return errors.length > 0 || broken.length > 0 ? fail(lines) : ok(lines);
484
+ }
485
+
486
+ export async function runPackCommand(argv: string[]): Promise<PackCliResult> {
487
+ const [sub, ...rest] = argv;
488
+ switch (sub) {
489
+ case "add":
490
+ return add(rest);
491
+ case "remove":
492
+ return remove(rest);
493
+ case "build":
494
+ return build(rest);
495
+ case "list":
496
+ case undefined: {
497
+ // `pack list` is what is installed here; `pack list <source>` is what a
498
+ // pack out there contains.
499
+ const source = packAddSource(rest);
500
+ return source ? listRemote(source) : list();
501
+ }
502
+ default:
503
+ return fail([`Unknown pack subcommand ${JSON.stringify(sub)}`, "Try: add, remove, list, build"]);
504
+ }
505
+ }