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
@@ -20,6 +20,7 @@ import {
20
20
  daemonVersionSkew,
21
21
  } from "./daemon-service";
22
22
  import { clearActiveCloudManagedPolicies } from "./cloud-managed-policies";
23
+ import { optsFor, rows as kitRows, stack, warning } from "./tui";
23
24
  import { deliveryHealth, deliveryHealthLine } from "./delivery-health";
24
25
  import { readVersionFile, readCredentials } from "./fp-config";
25
26
  import { version as cliVersion } from "../../package.json";
@@ -380,18 +381,36 @@ export function versionStatusLines(): string[] {
380
381
  ];
381
382
  }
382
383
 
383
- export function connectionStatusLines(
384
+ export interface ConnectionStatusReport {
385
+ /** Label/value pairs, unrendered, so a caller printing several blocks in one
386
+ * window can align them all to ONE column instead of each block to its own. */
387
+ rows: Array<[string, string]>;
388
+ /** Lines for the one warning shape, already stripped of their own gutter. */
389
+ warnings: string[];
390
+ }
391
+
392
+ /**
393
+ * The connection half of `--status`, as data.
394
+ *
395
+ * Separate from the rendering because `config --status` prints this block and
396
+ * the pause block together: rendered independently they computed two different
397
+ * label columns and the window read as two commands' output stacked up.
398
+ */
399
+ export function connectionStatusReport(
384
400
  daemonStatus = daemonServiceStatus,
385
- /** Print the full machine id rather than a short prefix. */
386
401
  verbose = false,
387
- ): string[] {
402
+ ): ConnectionStatusReport {
388
403
  const envUrl = process.env.FAILPROOFAI_CLOUD_URL;
389
404
  if (envUrl) {
390
405
  // Env wins over the file in the daemon, so reporting the file here would
391
406
  // describe a configuration that is not in effect.
392
- return [
393
- `Cloud: configured by environment (${envUrl}), which takes precedence over ${cloudCredentialPath()}.`,
394
- ];
407
+ return {
408
+ rows: [
409
+ ["cloud", `configured by environment (${envUrl})`],
410
+ ["", `takes precedence over ${cloudCredentialPath()}`],
411
+ ],
412
+ warnings: [],
413
+ };
395
414
  }
396
415
  const creds = readCloudCredentials();
397
416
  const ingest = readIngestCredential();
@@ -400,13 +419,13 @@ export function connectionStatusLines(
400
419
  // activity but pulling no policy, or the reverse, is a state worth seeing at
401
420
  // a glance — it is exactly the half-configured case this command exists to
402
421
  // catch, and two unrelated lines made it easy to miss.
403
- if (!creds && !ingest) return ["Cloud: not connected."];
422
+ if (!creds && !ingest) return { rows: [["cloud", "not connected"]], warnings: [] };
404
423
 
405
424
  // Recorded at connect time from the server's own answer, never guessed from
406
425
  // the URL: one deployment hosts many orgs, so the host says nothing about
407
426
  // which one this machine's data lands in. Absent against a server with no
408
427
  // introspect endpoint, and on credentials written before this was recorded —
409
- // in both cases the line is simply omitted rather than guessed at.
428
+ // in both cases the row is simply omitted rather than guessed at.
410
429
  const org = readCredentials().org;
411
430
  const orgLine = org
412
431
  ? org.name && org.slug
@@ -414,22 +433,25 @@ export function connectionStatusLines(
414
433
  : (org.name ?? org.slug ?? org.id)
415
434
  : undefined;
416
435
 
417
- const lines: string[] = [];
436
+ // Rows, not a prose lead. The URL, the machine label and the masked token used
437
+ // to be crammed into one sentence — three separate facts, none of them
438
+ // scannable, and the two that follow were already a hand-padded column that
439
+ // agreed with nothing else the CLI prints.
440
+ const detail: Array<[string, string]> = [];
418
441
  if (creds) {
419
- // Label first, with a short id to disambiguate; the bare id is the fallback
420
- // for credentials written before labels existed.
421
- const shownAs = describeMachine(creds.machineId, creds.machineLabel, verbose);
422
- lines.push(`Cloud: connected to ${creds.url} as ${shownAs} (token ${maskToken(creds.token)}).`);
423
- lines.push(` Policy pulling centrally-managed policies.`);
442
+ detail.push(["cloud", `connected to ${creds.url}`]);
443
+ detail.push(["machine", describeMachine(creds.machineId, creds.machineLabel, verbose)]);
444
+ detail.push(["token", maskToken(creds.token)]);
445
+ detail.push(["policy", "pulling centrally-managed policies"]);
424
446
  } else {
425
- lines.push(`Cloud: connected to ${cloudBaseFor(ingest!.url)} for reporting only.`);
426
- lines.push(` Policy NOT pulling — this machine enforces only its local policies.`);
447
+ detail.push(["cloud", `connected to ${cloudBaseFor(ingest!.url)} for reporting only`]);
448
+ detail.push(["policy", "NOT pulling — this machine enforces only its local policies"]);
427
449
  }
428
450
 
429
- if (orgLine) lines.push(` Org ${orgLine}`);
451
+ if (orgLine) detail.push(["org", orgLine]);
430
452
 
431
453
  if (ingest) {
432
- // Everything above this line is read from the credential FILE, which
454
+ // Everything above this row is read from the credential FILE, which
433
455
  // records what was true at `--connect` time and is never revisited. A key
434
456
  // that has since been revoked, expired, or had its org disabled leaves that
435
457
  // file byte-for-byte correct while nothing arrives — which is how a machine
@@ -439,16 +461,33 @@ export function connectionStatusLines(
439
461
  // so it overrides the cheerful line rather than being appended after it.
440
462
  const health = deliveryHealth();
441
463
  const rejection = deliveryHealthLine(health);
442
- if (rejection) {
443
- lines.push(` Dashboard ${rejection}`);
444
- } else {
445
- lines.push(` Dashboard sending hook activity to ${ingest.url}.`);
446
- }
464
+ detail.push(["dashboard", rejection ?? `sending hook activity to ${ingest.url}`]);
447
465
  } else {
448
- lines.push(` Dashboard NOT sending — nothing from this machine appears in the dashboard.`);
449
- lines.push(` Re-run: failproofai config --connect ${creds!.url} --token <key>`);
466
+ detail.push([
467
+ "dashboard",
468
+ "NOT sending — nothing from this machine appears in the dashboard",
469
+ ]);
470
+ detail.push(["", `re-run: failproofai config --connect ${creds!.url} --token <key>`]);
450
471
  }
451
472
 
452
- lines.push(...daemonWarning(daemonStatus()).map((l) => (l === "" ? "" : ` ${l.trim()}`)));
453
- return lines;
473
+ // The daemon block is a warning, so it takes the one warning shape rather than
474
+ // its own indented prose.
475
+ const daemonLines = daemonWarning(daemonStatus())
476
+ .map((l) => l.replace(/^[!\s]+/, "").trim())
477
+ .filter((l) => l.length > 0);
478
+ return { rows: detail, warnings: daemonLines };
454
479
  }
480
+
481
+ /** The same report, rendered on its own — for any caller printing only this. */
482
+ export function connectionStatusLines(
483
+ daemonStatus = daemonServiceStatus,
484
+ /** Print the full machine id rather than a short prefix. */
485
+ verbose = false,
486
+ ): string[] {
487
+ const opts = optsFor(process.stdout);
488
+ const report = connectionStatusReport(daemonStatus, verbose);
489
+ return stack(
490
+ kitRows(report.rows, opts),
491
+ report.warnings.length > 0 ? warning(report.warnings, opts) : null,
492
+ );
493
+ }
@@ -102,7 +102,12 @@ function parseManifest(value: unknown): ActiveManifest {
102
102
  return { schemaVersion: raw.schemaVersion as number, deployment: deployment as number, policies };
103
103
  }
104
104
 
105
- function resolveManagedPath(root: string, candidate: string): string {
105
+ /**
106
+ * Shared with `pack-manifest.ts` deliberately. This is a path-escape guard on a
107
+ * file that is about to be IMPORTED; two copies of it would be two things to
108
+ * harden and one to forget.
109
+ */
110
+ export function resolveManagedPath(root: string, candidate: string): string {
106
111
  if (!candidate || isAbsolute(candidate)) throw new Error(`unsafe managed policy path ${JSON.stringify(candidate)}`);
107
112
  const absolute = resolve(root, candidate);
108
113
  const lexicalRelative = relative(root, absolute);
@@ -6,7 +6,7 @@
6
6
  * 0. Daemon — REQUIRED. Asks for sudo first, on a clean terminal.
7
7
  * 1. Where — inferred from cwd, then confirmed (global / project / both)
8
8
  * 2. Policies — multi-select of themed presets (combine any) or Everything
9
- * 3. Assistants— multi-select of agent CLIs (detected + install-ahead)
9
+ * 3. Assistants— multi-select of agent harnesses (detected + install-ahead)
10
10
  * 4. Connect — paste an API key, or stay fully local
11
11
  * 5. Review — shows exactly which files change, then Apply.
12
12
  *
@@ -31,6 +31,7 @@ import { trackHookEvent } from "./hook-telemetry";
31
31
  import { getInstanceId } from "../../lib/telemetry-id";
32
32
  import type { CustomHook } from "./policy-types";
33
33
  import type { CloudManagedPolicyArtifact } from "./cloud-managed-policies";
34
+ import type { ResolvedPack } from "./pack-manifest";
34
35
  import { customPoliciesDir, shimsDir } from "./fp-home";
35
36
 
36
37
  const LOADING_KEY = "__FAILPROOFAI_LOADING_HOOKS__";
@@ -172,6 +173,11 @@ async function importWithDeadline(fileUrl: string): Promise<void> {
172
173
  * Load a single policy file into the globalThis custom hooks registry.
173
174
  * Does NOT clear the registry — caller is responsible for that.
174
175
  */
176
+ export interface PolicyLoadFailure {
177
+ type: "module_not_found" | "syntax_error" | "load_timeout" | "runtime_error" | "path_missing";
178
+ reason: string;
179
+ }
180
+
175
181
  async function loadSingleFile(
176
182
  absPath: string,
177
183
  opts?: {
@@ -180,7 +186,7 @@ async function loadSingleFile(
180
186
  /** Cloud-managed policies pass their pinned digest for load-time re-verification. */
181
187
  verifyEntrySha?: string;
182
188
  },
183
- ): Promise<void> {
189
+ ): Promise<PolicyLoadFailure | null> {
184
190
  const g = globalThis as Record<string, unknown>;
185
191
  g[LOADING_KEY] = true;
186
192
 
@@ -208,7 +214,7 @@ async function loadSingleFile(
208
214
  const cached = policyModuleCache.get(absPath);
209
215
  if (cached?.fingerprint === fingerprint) {
210
216
  for (const hook of cached.hooks) customPolicies.add({ ...hook });
211
- return;
217
+ return null;
212
218
  }
213
219
 
214
220
  const entryTmp = absPath + tmpSuffix;
@@ -222,6 +228,7 @@ async function loadSingleFile(
222
228
  .slice(hooksBefore)
223
229
  .map((hook) => ({ ...hook })),
224
230
  });
231
+ return null;
225
232
  } catch (err) {
226
233
  const msg = err instanceof Error ? err.message : String(err);
227
234
  const errorType = /Cannot find module|MODULE_NOT_FOUND|ENOENT/i.test(msg)
@@ -239,6 +246,7 @@ async function loadSingleFile(
239
246
  });
240
247
  if (opts?.strict) throw new Error(`Failed to load custom hooks from ${absPath}: ${msg}`);
241
248
  hookLogError(`failed to load custom hooks from ${absPath}: ${msg}`);
249
+ return { type: errorType, reason: msg };
242
250
  } finally {
243
251
  g[LOADING_KEY] = false;
244
252
  await cleanupTmpFiles(tmpFiles);
@@ -293,6 +301,8 @@ export interface ConventionSource {
293
301
  export interface LoadAllResult {
294
302
  hooks: CustomHook[];
295
303
  conventionSources: ConventionSource[];
304
+ /** Import failures keyed by pack id, including artifacts that registered no hooks. */
305
+ packFailures: Map<string, PolicyLoadFailure>;
296
306
  }
297
307
 
298
308
  export function customPolicyId(file: string, name: string): string {
@@ -330,17 +340,53 @@ function warnSkippedPolicyFiles(dir: string, scope: "project" | "user"): void {
330
340
  );
331
341
  }
332
342
 
343
+ /**
344
+ * A pack's manifest declares what it contains; its artifact decides what runs.
345
+ * Nothing binds the two, so they can disagree — and the disagreement is silent
346
+ * in both directions and worse in one.
347
+ *
348
+ * A policy the artifact registers but the manifest omits is enforcement that no
349
+ * `failproofai policies` listing will ever show. A policy the manifest declares
350
+ * but the artifact never registers is the dangerous one: the listing says the
351
+ * machine is protected against something nothing is checking.
352
+ *
353
+ * Both are announced rather than corrected. The artifact is digest-pinned, so
354
+ * what it registers IS what the publisher shipped and dropping any of it would
355
+ * be inventing a third answer; the manifest is what needs fixing, upstream.
356
+ */
357
+ function reconcilePackManifest(pack: ResolvedPack | undefined, loaded: CustomHook[]): void {
358
+ if (!pack || pack.policies.length === 0) return;
359
+ const declared = new Set(pack.policies.map((p) => p.name));
360
+ const registered = new Set(loaded.map((h) => h.name));
361
+ const missing = [...declared].filter((n) => !registered.has(n));
362
+ const extra = [...registered].filter((n) => !declared.has(n));
363
+ if (missing.length > 0) {
364
+ hookLogWarn(
365
+ `pack ${pack.id}@${pack.version} declares ${missing.join(", ")} but its artifact does not ` +
366
+ `register ${missing.length === 1 ? "it" : "them"} — listed as protection that never runs`,
367
+ );
368
+ }
369
+ if (extra.length > 0) {
370
+ hookLogWarn(
371
+ `pack ${pack.id}@${pack.version} registers undeclared ${extra.join(", ")} — ` +
372
+ `${extra.length === 1 ? "it enforces" : "they enforce"} but will not appear in listings`,
373
+ );
374
+ }
375
+ }
376
+
333
377
  export async function loadAllCustomHooks(
334
378
  customPoliciesPaths: string | string[] | undefined,
335
379
  opts?: {
336
380
  sessionCwd?: string;
337
381
  customPoliciesEnabled?: boolean;
338
382
  cloudManagedPolicies?: CloudManagedPolicyArtifact[];
383
+ packs?: ResolvedPack[];
339
384
  },
340
385
  ): Promise<LoadAllResult> {
341
386
  clearCustomHooks();
342
387
 
343
388
  const conventionSources: ConventionSource[] = [];
389
+ const packFailures = new Map<string, PolicyLoadFailure>();
344
390
 
345
391
  const projectRoot = findProjectConfigDir(opts?.sessionCwd ?? process.cwd());
346
392
 
@@ -395,6 +441,30 @@ export async function loadAllCustomHooks(
395
441
  }
396
442
  }
397
443
 
444
+ // Installed packs, keyed by artifact path — the same content-addressing, and
445
+ // therefore the same collision, as the cloud map above: two packs whose entry
446
+ // file is byte-identical resolve to ONE artifact, `loadedPaths` imports it
447
+ // once, and the loser would vanish silently with its effect deciding nothing.
448
+ // Resolved the same way and for the same reason — toward ENFORCEMENT, because
449
+ // over-enforcing is visible to whoever hits it and under-enforcing is the
450
+ // silent failure — and announced, so an operator can act on it.
451
+ const packByPath = new Map<string, ResolvedPack>();
452
+ for (const pack of opts?.packs ?? []) {
453
+ const key = resolve(pack.path);
454
+ const existing = packByPath.get(key);
455
+ if (!existing) {
456
+ packByPath.set(key, pack);
457
+ continue;
458
+ }
459
+ hookLogWarn(
460
+ `packs ${existing.id} and ${pack.id} have identical source, so they share one artifact ` +
461
+ `and load as one pack; enforcing it if either asks to enforce`,
462
+ );
463
+ if (existing.effect !== "enforce" && pack.effect === "enforce") {
464
+ packByPath.set(key, pack);
465
+ }
466
+ }
467
+
398
468
  // 1. Explicit custom policy paths. Accept a string for callers/configs using
399
469
  // the legacy singular form.
400
470
  for (const customPoliciesPath of typeof customPoliciesPaths === "string"
@@ -403,31 +473,44 @@ export async function loadAllCustomHooks(
403
473
  // resolve() also normalizes absolute paths, so aliases containing `.` or
404
474
  // `..` share a dedup key with convention-discovered canonical paths.
405
475
  const absPath = resolve(projectRoot, customPoliciesPath);
476
+ const cloudManaged = cloudManagedByPath.get(absPath);
477
+ const pack = packByPath.get(absPath);
406
478
  if (existsSync(absPath)) {
407
479
  if (!loadedPaths.has(absPath)) {
408
480
  loadedPaths.add(absPath);
409
481
  const hooksBefore = getCustomHooks().length;
410
482
  // A cloud-managed policy re-verifies its pinned digest at load, binding
411
483
  // the imported bytes to what desired-state promised.
412
- await loadSingleFile(absPath, {
413
- verifyEntrySha: cloudManagedByPath.get(absPath)?.sha256,
484
+ // A pack re-verifies its pinned digest at load for the same reason a
485
+ // cloud policy does: the manifest read and the import are two moments,
486
+ // and only this one binds the bytes actually executed to what was
487
+ // promised.
488
+ const failure = await loadSingleFile(absPath, {
489
+ verifyEntrySha:
490
+ cloudManaged?.sha256 ?? pack?.sha256,
414
491
  });
492
+ if (failure && pack) packFailures.set(pack.id, failure);
415
493
  for (const hook of getCustomHooks().slice(hooksBefore)) {
416
- const cloudManaged = cloudManagedByPath.get(absPath);
417
494
  const tagged = hook as CustomHook & {
418
495
  __policyId?: string;
419
496
  __cloudManaged?: CloudManagedPolicyArtifact;
497
+ __pack?: ResolvedPack;
420
498
  };
421
499
  if (cloudManaged) {
422
500
  tagged.__cloudManaged = cloudManaged;
423
501
  tagged.__policyId = `cloud:${cloudManaged.id}@${cloudManaged.version}:${hook.name}`;
502
+ } else if (pack) {
503
+ tagged.__pack = pack;
504
+ tagged.__policyId = `pack:${pack.id}@${pack.version}:${hook.name}`;
424
505
  } else {
425
506
  tagged.__policyId = customPolicyId(absPath, hook.name);
426
507
  }
427
508
  }
509
+ reconcilePackManifest(pack, getCustomHooks().slice(hooksBefore));
428
510
  }
429
511
  } else {
430
512
  hookLogWarn(`custom policy path not found: ${absPath}`);
513
+ if (pack) packFailures.set(pack.id, { type: "path_missing", reason: `path missing: ${absPath}` });
431
514
  }
432
515
  }
433
516
 
@@ -569,5 +652,5 @@ export async function loadAllCustomHooks(
569
652
  }
570
653
  }
571
654
 
572
- return { hooks: allHooks, conventionSources };
655
+ return { hooks: allHooks, conventionSources, packFailures };
573
656
  }
@@ -210,6 +210,26 @@ export const globalPolicyConfigFile = (home?: string) =>
210
210
  */
211
211
  export const cloudPoliciesDir = (home?: string) => resolve(policiesDir(home), "cloud-policies");
212
212
 
213
+ /**
214
+ * Installed policy packs — a sibling of `cloudPoliciesDir` and flat for the same
215
+ * reason: `artifacts/<sha256>.mjs` is content-addressed, so an install can only
216
+ * ever write a file that does not exist yet and is structurally incapable of
217
+ * disturbing what is currently live. `installed.json` names which artifacts are
218
+ * active and is written last, so activation is one atomic flip.
219
+ *
220
+ * Living under `policies/` is safe ONLY because the convention loader does not
221
+ * recurse — `discoverPolicyFiles` and `findSkippedPolicyFiles` both filter on
222
+ * `isFile()`, so nothing under `packs/` can be picked up as an unverified
223
+ * convention policy. `fp-home.test.ts` pins that non-recursion.
224
+ */
225
+ export const packsDir = (home?: string) => resolve(policiesDir(home), "packs");
226
+
227
+ /** The activation pointer. Written last and atomically. */
228
+ export const packsInstalledFile = (home?: string) => resolve(packsDir(home), "installed.json");
229
+
230
+ /** Content-addressed pack artifacts, shared across packs and versions. */
231
+ export const packArtifactsDir = (home?: string) => resolve(packsDir(home), "artifacts");
232
+
213
233
  // ── Collector ────────────────────────────────────────────────────────────────
214
234
 
215
235
  /** Per-source watermarks. One directory per source — never shared: the cursor
@@ -218,7 +238,14 @@ export const cloudPoliciesDir = (home?: string) => resolve(policiesDir(home), "c
218
238
  export const cursorsDir = (source?: string, home?: string) =>
219
239
  source ? resolve(atHome(home, "cursors"), source) : atHome(home, "cursors");
220
240
 
221
- /** The SDK spool root. Mirrors `~/.agenteye/`, which stays supported. */
241
+ /** The SDK spool root, and the ONLY root `failproofai-sdk` writes to.
242
+ *
243
+ * The daemon additionally watches `~/.agenteye/events` (see `spool_dirs` in
244
+ * `crates/fpai-collect/src/config.rs`) so that SDKs old enough to write there,
245
+ * and batches already sitting there, keep being collected. But no current SDK
246
+ * puts anything in it: `$AGENTEYE_HOME` used to redirect the spool and no
247
+ * longer does, precisely so that exporting it for the older
248
+ * `agenteye-collector` cannot relocate the SDK as a side effect. */
222
249
  export const customAgentsDir = (home?: string) => atHome(home, "custom-agents");
223
250
  export const customAgentsEventsDir = (home?: string) => resolve(customAgentsDir(home), "events");
224
251
  export const customAgentsFailedDir = (home?: string) => resolve(customAgentsDir(home), "failed");
@@ -273,6 +300,48 @@ export const auditSessionFile = (home?: string) => resolve(auditDir(home), "sess
273
300
  export const auditMachineFile = (home?: string) => resolve(auditDir(home), "machine.json");
274
301
 
275
302
 
303
+ // ── fp-cloud-cli ───────────────────────────────────────────────────────────────────
304
+
305
+ /**
306
+ * The Cloud CLI's own directory (`fp-cloud-cli` on PyPI, command `fp`).
307
+ *
308
+ * Written by PYTHON, not by anything in this repo's TypeScript or Rust — the
309
+ * CLI resolves it independently in `fp-cloud-cli/fp_cli/config.py`. It is declared
310
+ * here anyway because this file is the register of what may exist in the home,
311
+ * and a path absent from it is only safe by accident: `resettablePaths()` is a
312
+ * filter over `HOME_CLASSES`, so an unregistered directory survives today and
313
+ * survives the next migration only until someone lists its parent.
314
+ *
315
+ * Not classified itself — `auditDir`'s rule applies, classify the children. The
316
+ * directory may grow a cache later; the credential in it must never be dropped.
317
+ */
318
+ export const fpcliDir = (home?: string) => atHome(home, "fpcli");
319
+
320
+ /**
321
+ * The CLI's signed-in session. `0600`, written only by `fp login` / `fp logout`.
322
+ *
323
+ * Was `~/.fp/cli.json` — a third top-level dotfile for one product. The old
324
+ * file is deliberately left where it is: `load_config` in
325
+ * `fp-cloud-cli/fp_cli/config.py` reads it when nothing is here yet, writes the
326
+ * session to this path, and does NOT delete the original, so downgrading to a
327
+ * previous `fp` finds its session intact. Adoption is best-effort — an
328
+ * unwritable home hands back the session it found rather than logging the
329
+ * machine out — and it costs the user no login.
330
+ *
331
+ * This paragraph said the opposite until it was checked against the code: that
332
+ * there was no migration and the upgrade cost a login. There is one, it is
333
+ * covered by `fp-cloud-cli/tests/test_failproofai_home.py`, and the only true half
334
+ * was that the old file survives.
335
+ *
336
+ * `user-typed` for the same reason as `auditSessionFile` beside it: nothing
337
+ * regenerates a session, and dropping it silently signs the machine out.
338
+ *
339
+ * TS-side only, like `auditSessionFile`, and absent from `paths.rs` by design —
340
+ * the daemon has no reason to open a human credential, and mirroring a path
341
+ * only Python writes would give `paths.rs` an entry nothing there reads.
342
+ */
343
+ export const fpcliAuthFile = (home?: string) => resolve(fpcliDir(home), "cli-auth.json");
344
+
276
345
  // ── Hook activity ────────────────────────────────────────────────────────────
277
346
 
278
347
  /** The decision log: page-sized JSONL the dashboard's activity tab reads. */
@@ -469,9 +538,15 @@ export type DataClass =
469
538
  * else under it is scratch. Listing the parent is exactly how a reset came
470
539
  * to delete undelivered events and the machine's own telemetry identity.
471
540
  *
472
- * `home-classification.test.ts` asserts every exported path function in this
473
- * module is either classified here or covered by a classified parent, so the
474
- * next path added to the home cannot skip the one question that matters.
541
+ * `__tests__/hooks/fp-home.test.ts` asserts every exported path function in
542
+ * this module is either classified here or covered by a classified parent, so
543
+ * the next path added to the home cannot skip the one question that matters.
544
+ *
545
+ * It cited `home-classification.test.ts` until that was checked — a file that
546
+ * has never existed. The guard was real and in the wrong place, which is the
547
+ * failure this header already describes happening once before: a citation is
548
+ * only load-bearing if somebody follows it, and the person who does is looking
549
+ * for the rule they are about to break.
475
550
  */
476
551
  export const HOME_CLASSES: readonly { path: (home?: string) => string; class: DataClass }[] = [
477
552
  // ── Never deleted: a person typed it ──
@@ -498,6 +573,11 @@ export const HOME_CLASSES: readonly { path: (home?: string) => string; class: Da
498
573
  // with no notice, and the machine only finds out the next time it tries to
499
574
  // report.
500
575
  { path: auditSessionFile, class: "user-typed" },
576
+ // The Cloud CLI's session, written by Python (`fp-cloud-cli/fp_cli/config.py`). The
577
+ // one entry here whose writer is outside this repo's TS and Rust, which is
578
+ // exactly why it needs listing: nothing in a migration would otherwise know a
579
+ // credential lives under `fpcli/`.
580
+ { path: fpcliAuthFile, class: "user-typed" },
501
581
 
502
582
  // ── Never deleted: recorded and not yet shipped ──
503
583
  // Batches read out of transcripts and queued for upload. The reason losing
@@ -574,6 +654,14 @@ export const HOME_CLASSES: readonly { path: (home?: string) => string; class: Da
574
654
  // directory holds both the files a person wrote and the ones the fleet sent,
575
655
  // and only the second kind may be thrown away.
576
656
  { path: cloudPoliciesDir, class: "refetchable" },
657
+ // Installed packs. Third-party packs are re-fetchable by `failproofai pack
658
+ // add`; the bundled default pack is restored from the package immediately
659
+ // after reset. So this is the fleet's argument again: one directory holds both
660
+ // what a person wrote and what a command fetched, and only the second kind may
661
+ // be thrown away. Without this row `packs/` inherits `policiesDir`'s
662
+ // `user-typed` and survives a reset that is supposed to clear re-fetchable
663
+ // state.
664
+ { path: packsDir, class: "refetchable" },
577
665
 
578
666
  // ── Never touched ──
579
667
  // A downloaded daemon binary is large, version-pinned and re-verified on use,
@@ -98,6 +98,8 @@ import {
98
98
  isDaemonSupportedPlatform,
99
99
  probeDaemonEndToEnd,
100
100
  } from "./daemon-service";
101
+ import { installBundledPack } from "./pack-store";
102
+ import { readHooksConfig } from "./hooks-config";
101
103
 
102
104
  export interface ResetOutcome {
103
105
  /** Paths that existed and were removed. */
@@ -964,6 +966,24 @@ export function resetHome(from: number, to: number = LAYOUT_VERSION): ResetOutco
964
966
  // straight out of the same file. Both paths end at the same key, and only one
965
967
  // of them represents something a person typed.
966
968
  if (telemetryOptOut) updateConfig({ telemetry: { enabled: false } });
969
+ // `packs/` is resettable, but the package's default pack is also the offline
970
+ // enforcement floor. Restore it from the installed package before declaring
971
+ // the migration complete; third-party packs remain explicitly re-fetchable.
972
+ //
973
+ // Carrying `enabledPolicies` INTO the selection, not installing defaults over
974
+ // it. This is the upgrade path every existing user takes, and installing
975
+ // defaults meant a machine that had switched `block-force-push` and
976
+ // `block-kubectl` on came back with them off — guards that were denying
977
+ // before the upgrade and allowing after, with nothing said.
978
+ const carried = (() => {
979
+ try {
980
+ const names = readHooksConfig().enabledPolicies ?? [];
981
+ return names.length > 0 ? { only: names } : undefined;
982
+ } catch {
983
+ return undefined;
984
+ }
985
+ })();
986
+ installBundledPack(carried);
967
987
  // The step's OWN target, not LAYOUT_VERSION.
968
988
  //
969
989
  // Every step used to end stamping the current layout, which was harmless
@@ -1344,8 +1364,12 @@ function staleDaemonHint(): string[] {
1344
1364
  `[failproofai] daemon is ${skew.installed}, CLI is ${skew.expected}.`,
1345
1365
  `This machine is configured to REQUIRE the daemon. A daemon built against a`,
1346
1366
  `different on-disk layout refuses to start, and this version moved it — so the`,
1347
- `next reboot or restart can leave the service down, which denies every tool`,
1348
- `call until it is fixed.`,
1367
+ // The wrap is load-bearing: "denies every tool call" is the consequence
1368
+ // this message exists to state, and splitting it across two lines is
1369
+ // what made the test asserting that phrase fail while the text looked
1370
+ // perfectly correct to a human reading it.
1371
+ `next reboot or restart can leave the service down, which`,
1372
+ `denies every tool call until it is fixed.`,
1349
1373
  `Run \`failproofai update\` now to bring the daemon in line.`,
1350
1374
  ``,
1351
1375
  ];