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
@@ -43,6 +43,8 @@ import { getInstanceId } from "../../lib/telemetry-id";
43
43
  import { hookLogInfo, hookLogWarn } from "./hook-logger";
44
44
  import { readStdinPayload } from "./read-stdin";
45
45
  import { readActiveCloudManagedPolicies, type CloudManagedPolicyArtifact } from "./cloud-managed-policies";
46
+ import { hasInstalledPacks, readInstalledPacks, type PackError, type ResolvedPack } from "./pack-manifest";
47
+ import { missingGuards, packFailureReason } from "./pack-failclosed";
46
48
  import { readActivePause, type ActivePause } from "./session-pause";
47
49
  import { layoutWarningForHook } from "./fp-reset";
48
50
 
@@ -255,13 +257,23 @@ export async function evaluateHookEvent(
255
257
  /** Registered policy name → where it came from. See the set() below. */
256
258
  const policyAttribution = new Map<
257
259
  string,
258
- { source: "custom" | "convention" | "cloud"; cloudPolicyId?: string; cloudVersion?: number }
260
+ {
261
+ source: "custom" | "convention" | "cloud" | "pack";
262
+ cloudPolicyId?: string;
263
+ cloudVersion?: number;
264
+ packId?: string;
265
+ packVersion?: string;
266
+ }
259
267
  >();
260
268
  let cloudDeployment: number | undefined;
269
+ /** Policy names each pack actually got registered, for the fail-closed check. */
270
+ const registeredByPack = new Map<string, Set<string>>();
271
+ let packErrors: PackError[] = [];
261
272
  /** What observe-mode policies WOULD have done, had they been enforcing. */
262
273
  const observedResults: Array<{
263
274
  policyId: string;
264
- version: number;
275
+ /** A cloud deployment counts; a pack carries a version STRING. */
276
+ version: string | number;
265
277
  decision: "deny" | "instruct";
266
278
  reason: string | null;
267
279
  }> = [];
@@ -290,7 +302,34 @@ export async function evaluateHookEvent(
290
302
  // already exempts them: a locally-issued command that could switch off a
291
303
  // centrally assigned policy would make cloud enforcement decorative.
292
304
  activePause = readActivePause(session.sessionId);
293
- registerBuiltinPolicies(activePause ? [] : config.enabledPolicies);
305
+ // Enforcement comes from PACKS now. What still registers from this build is
306
+ // the always-on self-protection guard, and nothing else: a pack may not
307
+ // declare `alwaysOn` — a downloaded file that no local command can switch
308
+ // off is the thing that guard exists to prevent — so it cannot travel the
309
+ // pack lane and has to ship compiled in.
310
+ //
311
+ // The second argument is the migration shim, not a feature. A machine that
312
+ // upgraded into this build has `enabledPolicies` and no pack installed
313
+ // yet, and it must not lose enforcement in the gap before `failproofai
314
+ // update` runs. It disappears for that machine the moment a pack is
315
+ // installed, and never fires for a machine set up by this version.
316
+ const packsInstalledHere = hasInstalledPacks();
317
+ const legacyNames =
318
+ activePause || packsInstalledHere ? [] : config.enabledPolicies;
319
+ // `alwaysOn` policies bypass the enabled set inside `registerBuiltinPolicies`,
320
+ // so an empty list still registers the guard — which is exactly what this
321
+ // build should contribute once packs carry everything else.
322
+ registerBuiltinPolicies(activePause ? [] : legacyNames);
323
+ if (legacyNames.length > 0) {
324
+ hookLogWarn(
325
+ `enforcing ${legacyNames.length} policies from this build because no pack is installed — ` +
326
+ `run \`failproofai update\` to move them into the pack that ships with it`,
327
+ );
328
+ }
329
+ // What actually registered, for the pack-duplicate check below. A paused
330
+ // session registers none, and then a pack twin is not a duplicate of
331
+ // anything — but a pause already skips every local policy, pack included.
332
+ const enabledBuiltinNames = new Set(legacyNames);
294
333
 
295
334
  // Cloud-managed policies are daemon-reconciled artifacts, but they use
296
335
  // the same public JS policy API as local custom policies. Verify and add
@@ -334,13 +373,31 @@ export async function evaluateHookEvent(
334
373
  // separate question from "what decided", and only the former can tell a
335
374
  // rollout that changed nothing from one that never reached the machine.
336
375
  cloudDeployment = cloudManagedPolicies[0]?.deployment;
376
+ // Installed packs. `readInstalledPacks` never throws: a bad manifest or a
377
+ // tampered artifact yields zero packs and a recorded reason, which is
378
+ // sound ONLY because the builtins still ship compiled in and keep
379
+ // enforcing underneath. See the fail-open note in pack-manifest.ts — the
380
+ // day builtins become a fetched pack this posture has to change with them.
381
+ let installedPacks: ResolvedPack[] = [];
382
+ try {
383
+ const packResult = readInstalledPacks();
384
+ installedPacks = packResult.packs;
385
+ packErrors = packResult.errors;
386
+ for (const err of packResult.errors) {
387
+ hookLogWarn(`pack ${err.id ?? "(unnamed)"} not loaded: ${err.reason}`);
388
+ }
389
+ } catch (err) {
390
+ hookLogWarn(`pack manifest unreadable: ${err instanceof Error ? err.message : String(err)}`);
391
+ }
392
+
337
393
  const configuredCustomPaths = config.customPoliciesPaths ?? config.customPoliciesPath;
338
394
  const allExplicitPaths =
339
- cloudManagedPolicies.length === 0
395
+ cloudManagedPolicies.length === 0 && installedPacks.length === 0
340
396
  ? configuredCustomPaths
341
397
  : [
342
398
  ...(typeof configuredCustomPaths === "string" ? [configuredCustomPaths] : configuredCustomPaths ?? []),
343
399
  ...cloudManagedPolicies.map((policy) => policy.path),
400
+ ...installedPacks.map((pack) => pack.path),
344
401
  ];
345
402
 
346
403
  // Load and register custom hooks (layer 2, after builtins)
@@ -348,6 +405,7 @@ export async function evaluateHookEvent(
348
405
  sessionCwd: session.cwd,
349
406
  customPoliciesEnabled: config.customPoliciesEnabled,
350
407
  ...(cloudManagedPolicies.length > 0 ? { cloudManagedPolicies } : {}),
408
+ ...(installedPacks.length > 0 ? { packs: installedPacks } : {}),
351
409
  });
352
410
  customHooksList = loadResult.hooks;
353
411
  const disabledCustomPolicies = new Set(config.disabledCustomPolicies ?? []);
@@ -357,34 +415,78 @@ export async function evaluateHookEvent(
357
415
  const taggedHook = hook as CustomHook & {
358
416
  __policyId?: string;
359
417
  __cloudManaged?: CloudManagedPolicyArtifact;
418
+ __pack?: ResolvedPack;
360
419
  };
361
420
  const policyId = taggedHook.__policyId;
362
421
  const cloudManaged = taggedHook.__cloudManaged;
422
+ const pack = taggedHook.__pack;
363
423
  // Local config cannot disable a centrally assigned policy merely by
364
424
  // copying its generated ID into disabledCustomPolicies.
365
425
  if (!cloudManaged && policyId && disabledCustomPolicies.has(policyId)) continue;
366
426
  // Same rule for a session pause — it suspends local policy, never cloud.
367
427
  if (!cloudManaged && activePause) continue;
428
+ // A pack's artifact registers everything it contains; the user may have
429
+ // taken only some of it. `enabled: null` means the whole pack, which is
430
+ // what `pack add` writes when no selection was made.
431
+ if (pack?.enabled && !pack.enabled.includes(hook.name)) continue;
432
+ // A pack policy whose name is an ENABLED BUILTIN is the same guard
433
+ // twice. The two register under different keys — `failproofai/block-sudo`
434
+ // and `pack/<id>@<version>/block-sudo` — so nothing deduped them, and
435
+ // the bundled pack carries the builtins under exactly these names.
436
+ //
437
+ // A deny hides it (the first verdict short-circuits) but an INSTRUCT does
438
+ // not: instructions accumulate and are joined, so the agent received the
439
+ // identical paragraph twice. Every duplicate also ran its policy function
440
+ // a second time, inside its own 10s timeout race, against a 150ms daemon
441
+ // budget.
442
+ //
443
+ // The builtin wins, because a bare name means the builtin everywhere else
444
+ // — `policies --uninstall block-sudo` disables the compiled one, and a
445
+ // machine that wants the pack's copy instead turns the builtin off.
446
+ // A pack policy whose name matches one the MIGRATION SHIM registered.
447
+ // Only reachable on a machine that has not migrated yet and somehow has
448
+ // a pack too; once the shim stops, nothing else registers by name.
449
+ if (pack && enabledBuiltinNames.has(hook.name)) continue;
450
+ if (pack) {
451
+ const seen = registeredByPack.get(pack.id) ?? new Set<string>();
452
+ seen.add(hook.name);
453
+ registeredByPack.set(pack.id, seen);
454
+ }
368
455
  const hookName = hook.name;
369
456
  const conventionScope = (hook as CustomHook & { __conventionScope?: string }).__conventionScope;
370
457
  const isConvention = !!conventionScope;
458
+ // A pack's prefix carries its id and version, and it always contains a
459
+ // `/` — which is what keeps a pack policy structurally unable to
460
+ // normalize into the `failproofai/` namespace and REPLACE a builtin.
461
+ // pack-manifest.ts refuses a `/` in the declared name for the same
462
+ // reason; this is the second half of that guard.
371
463
  const prefix = cloudManaged
372
464
  ? `cloud/${cloudManaged.id}@${cloudManaged.version}`
373
- : isConvention
374
- ? `.failproofai-${conventionScope}`
375
- : "custom";
465
+ : pack
466
+ ? `pack/${pack.id}@${pack.version}`
467
+ : isConvention
468
+ ? `.failproofai-${conventionScope}`
469
+ : "custom";
376
470
  // Observe mode: run it for real, record what it decided, then hand back
377
471
  // an allow. Evaluating and discarding is the whole point — a rollout is
378
472
  // measured against real traffic before it can break anyone's work, and
379
473
  // a policy that did not actually run would measure nothing.
380
- const observeOnly = cloudManaged?.effect === "observe";
474
+ const observeOnly = cloudManaged?.effect === "observe" || pack?.effect === "observe";
381
475
  const fn: PolicyFunction = async (ctx): Promise<PolicyResult> => {
382
476
  if (observeOnly) {
383
477
  const shadow = await runObserved(hook, ctx, hookName, eventType, cli);
384
478
  if (shadow.decision !== "allow") {
479
+ // Sourced from whichever layer asked to observe. This read
480
+ // `cloudManaged!.id` — a non-null assertion that is simply false
481
+ // for a pack, so an observe-mode PACK threw on its first non-allow
482
+ // verdict. The throw escapes before the wrapper's own try below,
483
+ // so policy-evaluator swallowed it and `continue`d: nothing was
484
+ // recorded, the row read as a clean allow, and the rollout being
485
+ // trialled measured nothing while reporting healthy.
486
+ const observer = cloudManaged ?? pack;
385
487
  observedResults.push({
386
- policyId: cloudManaged!.id,
387
- version: cloudManaged!.version,
488
+ policyId: observer!.id,
489
+ version: observer!.version,
388
490
  decision: shadow.decision,
389
491
  reason: shadow.reason ?? null,
390
492
  });
@@ -419,8 +521,14 @@ export async function evaluateHookEvent(
419
521
  // question cloud attribution has to answer, "which rollout produced
420
522
  // this decision", could only be answered by re-parsing our own label.
421
523
  policyAttribution.set(registeredName, {
422
- source: cloudManaged ? "cloud" : isConvention ? "convention" : "custom",
524
+ // `pack` was in scope here and simply not consulted, so every pack
525
+ // decision was filed as "custom" — which is also what a user's own
526
+ // local .mjs gets, making the two indistinguishable without
527
+ // re-parsing the `pack/` prefix off the display name. That re-parsing
528
+ // is exactly the practice these fields exist to replace.
529
+ source: cloudManaged ? "cloud" : pack ? "pack" : isConvention ? "convention" : "custom",
423
530
  ...(cloudManaged ? { cloudPolicyId: cloudManaged.id, cloudVersion: cloudManaged.version } : {}),
531
+ ...(pack ? { packId: pack.id, packVersion: pack.version } : {}),
424
532
  });
425
533
  registerPolicy(
426
534
  registeredName,
@@ -428,9 +536,69 @@ export async function evaluateHookEvent(
428
536
  fn,
429
537
  hook.match ?? {},
430
538
  -1, // Custom hooks run after builtins (priority 0)
539
+ // A pack declares its policies' params in its manifest, so they work
540
+ // exactly like a builtin's — defaults merged under whatever the user
541
+ // configured. Matched by the pack's own name for the policy, which is
542
+ // the name before the `pack/<id>@<version>/` prefix is applied.
543
+ pack?.policies.find((p) => p.name === hook.name)?.params,
431
544
  );
432
545
  }
433
546
 
547
+ // Fail closed on enforcement this machine was told it had and does not.
548
+ //
549
+ // Additive, and deliberately NOT a clearPolicies() the way the
550
+ // daemon-unreachable branch is: `registerBuiltinPolicies` registers the
551
+ // alwaysOn self-protection guard unconditionally, and clearing here would
552
+ // let a corrupt third-party download switch off the one policy nothing may
553
+ // disable.
554
+ //
555
+ // Skipped entirely under a session pause. A pause suspends local policy for
556
+ // a bounded, deliberate window; a check derived from registrations would
557
+ // fire for every pack on every paused event and convert that into a
558
+ // machine-wide deny — the exact inversion of what a pause is for.
559
+ if (!activePause) {
560
+ const guards = missingGuards({
561
+ errors: packErrors,
562
+ packs: installedPacks,
563
+ registered: registeredByPack,
564
+ failed: loadResult.packFailures,
565
+ disabled: disabledCustomPolicies,
566
+ });
567
+ if (guards.length > 0) {
568
+ const reason = packFailureReason(guards);
569
+ const match = guards.length === 1
570
+ ? guards[0].match
571
+ : {
572
+ events: guards.every((g) => g.match.events)
573
+ ? [...new Set(guards.flatMap((g) => g.match.events ?? []))]
574
+ : undefined,
575
+ };
576
+ const name = "pack/failproofai-pack-unavailable";
577
+ policyAttribution.set(name, {
578
+ source: "pack",
579
+ packId: guards[0].packId,
580
+ ...(guards[0].packVersion ? { packVersion: guards[0].packVersion } : {}),
581
+ });
582
+ registerPolicy(
583
+ name,
584
+ "A policy pack this machine enforces could not be loaded",
585
+ async (): Promise<PolicyResult> =>
586
+ // UserPromptSubmit instructs rather than denies, whatever the
587
+ // missing policies declared: a deny there locks the user out of
588
+ // their own agent, which is the one thing that stops them fixing it.
589
+ canonicalEventType === "UserPromptSubmit"
590
+ ? { decision: "instruct", reason }
591
+ : { decision: "deny", reason },
592
+ match,
593
+ // Above builtins (0) and custom (-1), so the short-circuit attributes
594
+ // the deny to the missing pack rather than to whichever surviving
595
+ // policy happened to fire first.
596
+ 1,
597
+ );
598
+ hookLogWarn(reason);
599
+ }
600
+ }
601
+
434
602
  // Fire telemetry once per invocation for custom hook loads
435
603
  if (customHooksList.length > 0) {
436
604
  void trackHookEvent(getInstanceId(), "custom_hooks_loaded", {
@@ -501,6 +669,8 @@ export async function evaluateHookEvent(
501
669
  ...(attribution?.cloudVersion !== undefined
502
670
  ? { cloudVersion: attribution.cloudVersion }
503
671
  : {}),
672
+ ...(attribution?.packId ? { packId: attribution.packId } : {}),
673
+ ...(attribution?.packVersion ? { packVersion: attribution.packVersion } : {}),
504
674
  };
505
675
  })()
506
676
  : {}),
@@ -39,6 +39,16 @@ import { homedir } from "node:os";
39
39
  import { resolve } from "node:path";
40
40
  import { readConfig, updateConfig } from "./fp-config";
41
41
  import { configFile } from "./fp-home";
42
+ import {
43
+ emptyState,
44
+ note,
45
+ table,
46
+ optsFor,
47
+ rule,
48
+ stack,
49
+ title,
50
+ warning,
51
+ } from "./tui";
42
52
 
43
53
  /**
44
54
  * Harness keys `collector.sources.<key>` accepts.
@@ -314,45 +324,89 @@ export function listPaths(harness?: string): HarnessResult {
314
324
  (k) => !(HARNESS_KEYS as readonly string[]).includes(k),
315
325
  );
316
326
 
327
+ const opts = optsFor(process.stdout);
328
+ const head = (extra: number) =>
329
+ title(
330
+ "failproofai harness list",
331
+ `${HARNESS_KEYS.length} harnesses · ${extra} extra path${extra === 1 ? "" : "s"}`,
332
+ opts,
333
+ );
334
+
317
335
  if (names.length === 0 && unknown.length === 0) {
318
- return ok([
319
- "No extra capture paths configured.",
320
- "",
321
- "Every harness is watching only its default location. Add one with:",
322
- " failproofai harness add-path <harness> [<label>=]<path>",
323
- "",
324
- `Harnesses: ${HARNESS_KEYS.join(", ")}`,
325
- ]);
336
+ return ok(
337
+ stack(
338
+ head(0),
339
+ emptyState(
340
+ {
341
+ what: "No extra capture paths configured. Every harness is watching only its default location.",
342
+ hint: "Add one with:",
343
+ cmd: "failproofai harness add-path <harness> [<label>=]<path>",
344
+ },
345
+ opts,
346
+ ),
347
+ // Wrapped, not joined into one line: twelve names ran off the right edge
348
+ // of an 80-column terminal, and the twelfth is as real as the first.
349
+ note(`Harnesses: ${HARNESS_KEYS.join(", ")}`, opts),
350
+ ),
351
+ );
326
352
  }
327
353
 
328
- const lines: string[] = [];
354
+ const configured = names.reduce((n, name) => n + (sources[name]?.extraPaths?.length ?? 0), 0);
355
+ const groups: Array<string[] | null> = [head(configured)];
329
356
  for (const name of names) {
330
357
  const entries = sources[name]?.extraPaths ?? [];
331
358
  if (entries.length === 0) {
332
- if (harness) lines.push(`${name}: no extra paths configured (default location only)`);
359
+ if (harness) {
360
+ groups.push(rule(name, opts));
361
+ groups.push(note("no extra paths configured (default location only)", opts));
362
+ }
333
363
  continue;
334
364
  }
335
- lines.push(`${name}:`);
336
- for (const e of entries) {
337
- const label = labelOf(e);
338
- lines.push(
339
- label
340
- ? ` ${pathOf(e)} → agent ids ${label}-*`
341
- : ` ${pathOf(e)} → label derived from the folder name`,
342
- );
343
- }
365
+ groups.push(rule(name, opts));
366
+ // A table, not label/value rows: the PATH is the fact here, and a row's
367
+ // label column would have capped it at 24 columns — a truncated path cannot
368
+ // be copied, which makes the listing useless for the one thing it is for.
369
+ groups.push(
370
+ table(
371
+ {
372
+ head: ["Path", "Agent ids"],
373
+ rows: entries.map((e) => {
374
+ const label = labelOf(e);
375
+ return [
376
+ pathOf(e),
377
+ label ? `${label}-*` : "derived from the folder name",
378
+ ];
379
+ }),
380
+ flex: 1,
381
+ // The path is the value this listing exists to hand back; it is never
382
+ // the column that gives way.
383
+ protect: [0],
384
+ },
385
+ opts,
386
+ ),
387
+ );
344
388
  }
389
+ const lines: string[] = stack(...groups);
345
390
  // Unknown tables are surfaced here as well as by the daemon: a user who
346
391
  // hand-edited config.json runs `list` to check it, and that is the moment the
347
392
  // typo is cheapest to find.
348
393
  if (unknown.length > 0) {
349
- if (lines.length === 0) lines.push("No extra capture paths configured for any known harness.");
350
- lines.push(
394
+ const body =
395
+ configured === 0
396
+ ? [...head(0), "", ...note("No extra capture paths configured for any known harness.", opts)]
397
+ : lines;
398
+ return ok([
399
+ ...body,
351
400
  "",
352
- `⚠ config.json configures ${unknown.length} unknown harness(es): ${unknown.join(", ")}`,
353
- " Nothing is captured from them.",
354
- ` Known: ${HARNESS_KEYS.join(", ")}`,
355
- );
401
+ ...warning(
402
+ [
403
+ `config.json configures ${unknown.length} unknown harness(es): ${unknown.join(", ")}`,
404
+ "Nothing is captured from them.",
405
+ `Known: ${HARNESS_KEYS.join(", ")}`,
406
+ ],
407
+ opts,
408
+ ),
409
+ ]);
356
410
  }
357
411
  return ok(lines);
358
412
  }
@@ -96,11 +96,20 @@ export interface HookActivityEntry {
96
96
  * plain allow) and on rows written before this existed — so, like
97
97
  * `matchedPolicies`, `undefined` means "unknown", not "builtin".
98
98
  */
99
- policySource?: "builtin" | "custom" | "convention" | "cloud";
99
+ policySource?: "builtin" | "custom" | "convention" | "cloud" | "pack";
100
100
  /** Cloud policy id of the decider. Present only when `policySource` is "cloud". */
101
101
  cloudPolicyId?: string;
102
102
  /** Immutable version of that policy — the half of attribution that identifies WHICH version ran. */
103
103
  cloudVersion?: number;
104
+ /**
105
+ * Pack id and version of the decider. Present only when `policySource` is
106
+ * "pack", and here for the same reason the cloud pair is: the display name
107
+ * encodes both ("pack/acme/finance@1.2.0/…") but only as a string, so without
108
+ * these the question "which pack, which version decided this" could only be
109
+ * answered by re-parsing our own label.
110
+ */
111
+ packId?: string;
112
+ packVersion?: string;
104
113
  /**
105
114
  * The cloud deployment active when this event was evaluated, recorded on
106
115
  * every row of a managed machine regardless of what decided. "What was
@@ -117,7 +126,8 @@ export interface HookActivityEntry {
117
126
  */
118
127
  observed?: Array<{
119
128
  policyId: string;
120
- version: number;
129
+ /** A cloud deployment number, or a pack's version string. */
130
+ version: string | number;
121
131
  decision: "deny" | "instruct";
122
132
  reason: string | null;
123
133
  }>;
@@ -134,7 +144,7 @@ export interface HookActivityFilters {
134
144
  * organization's policies decided" is the question cloud rollout reporting
135
145
  * is built on, and it is unanswerable without this.
136
146
  */
137
- source?: "builtin" | "custom" | "convention" | "cloud";
147
+ source?: "builtin" | "custom" | "convention" | "cloud" | "pack";
138
148
  }
139
149
 
140
150
  export interface HookActivityStats {
@@ -358,7 +358,16 @@ export async function promptPolicySelection(
358
358
  // If stdin is not a TTY (piped/CI), return defaults
359
359
  if (!process.stdin.isTTY) {
360
360
  const available = BUILTIN_POLICIES.filter((p) => includeBeta || !p.beta);
361
- if (preSelected) return preSelected.filter((name) => available.some((p) => p.name === name));
361
+ // Returned UNCHANGED, deliberately. This used to intersect with the builtin
362
+ // catalog, and manager.ts writes the result straight back — so a piped
363
+ // `policies --install` silently deleted every enabled name the catalog did
364
+ // not contain: a `failproofai/`-qualified name (a form the enforcement path
365
+ // explicitly accepts, `registerBuiltinPolicies` canonicalizes both), a beta
366
+ // policy enabled with `--beta`, and now any pack policy. The line that
367
+ // reports what was enabled prints only the survivors, so the loss was
368
+ // invisible. Carrying an unknown name costs nothing — registration looks it
369
+ // up in a Set and finds nothing — while dropping one destroys configuration.
370
+ if (preSelected) return [...preSelected];
362
371
  return available.filter((p) => p.defaultEnabled).map((p) => p.name);
363
372
  }
364
373
 
@@ -374,6 +383,14 @@ export async function promptPolicySelection(
374
383
  beta: !!p.beta,
375
384
  }));
376
385
 
386
+ // Everything the user has enabled that this picker cannot show a row for, for
387
+ // the same reason as the non-TTY branch above: the picker's universe is the
388
+ // builtin catalog, and resolving from it alone deletes anything else. Kept in
389
+ // their original order and appended to whatever the user picks.
390
+ const carried = preSelected
391
+ ? preSelected.filter((name) => !items.some((i) => i.name === name))
392
+ : [];
393
+
377
394
  const total = items.length;
378
395
  const WINDOW_SIZE = 10;
379
396
 
@@ -570,10 +587,15 @@ export async function promptPolicySelection(
570
587
  cleanup();
571
588
  const selected = items.filter((i) => i.selected).map((i) => i.name);
572
589
  if (lastLineCount > 0) process.stdout.write(`\x1B[${lastLineCount}A\x1B[J`);
590
+ // Carried entries are NAMED, not counted. "3 kept" reads as fine right
591
+ // up until someone needs to know which three.
592
+ const summary = carried.length > 0
593
+ ? `${selected.length} selected, kept ${carried.join(", ")}`
594
+ : `${selected.length} selected`;
573
595
  process.stdout.write(
574
- `${dim(BAR)}\n${dim(DONE)} Policies\n${dim(BAR)} ${dim(`${selected.length} selected`)}\n`,
596
+ `${dim(BAR)}\n${dim(DONE)} Policies\n${dim(BAR)} ${dim(summary)}\n`,
575
597
  );
576
- resolve(selected);
598
+ resolve([...selected, ...carried]);
577
599
  } else if (key.name === "escape") {
578
600
  // Clear search filter
579
601
  search = "";