failproofai 1.0.1 → 1.0.2-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (389) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +3 -3
  3. package/.next/standalone/.next/prerender-manifest.json +6 -6
  4. package/.next/standalone/.next/required-server-files.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  6. package/.next/standalone/.next/server/app/_global-error/page.js +2 -2
  7. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  11. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
  12. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  13. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page.js +2 -2
  16. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  17. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  18. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  19. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  20. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  21. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -14
  22. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  23. package/.next/standalone/.next/server/app/api/audit/invite/route.js +3 -2
  24. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/audit/run/route.js +5 -4
  26. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/auth/login-request/route.js +2 -2
  29. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +4 -3
  31. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/api/auth/logout/route.js +4 -4
  33. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/api/auth/status/route.js +4 -4
  35. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  38. package/.next/standalone/.next/server/app/audit/page.js +2 -2
  39. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  41. package/.next/standalone/.next/server/app/index.html +1 -1
  42. package/.next/standalone/.next/server/app/index.rsc +15 -15
  43. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +14 -14
  44. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  45. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  46. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  47. package/.next/standalone/.next/server/app/page.js +2 -2
  48. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  49. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  50. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +66 -22
  51. package/.next/standalone/.next/server/app/policies/page.js +5 -4
  52. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  53. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  54. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  55. package/.next/standalone/.next/server/app/project/[name]/page.js +2 -2
  56. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  57. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  58. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  59. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  60. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +2 -2
  61. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  62. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  63. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  64. package/.next/standalone/.next/server/app/projects/page.js +2 -2
  65. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  66. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  67. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +4 -4
  68. package/.next/standalone/.next/server/app/settings/page.js +1 -1
  69. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  70. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  71. package/.next/standalone/.next/server/chunks/{[externals]__1qzqcio._.js → [externals]__0e32-7c._.js} +1 -1
  72. package/.next/standalone/.next/server/chunks/[externals]__1s462yl._.js +3 -0
  73. package/.next/standalone/.next/server/chunks/[root-of-the-server]__01eqny5._.js +3 -0
  74. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_0xu5z._.js +1 -1
  75. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1p8poxd._.js → [root-of-the-server]__0igxt32._.js} +2 -2
  76. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0neqlu-._.js +3 -0
  77. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +3 -0
  78. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t9oqnn._.js +3 -0
  79. package/.next/standalone/.next/server/chunks/_0bs-v8p._.js +3 -0
  80. package/.next/standalone/.next/server/chunks/_0tovk6q._.js +3 -0
  81. package/.next/standalone/.next/server/chunks/_0trp3yc._.js +3 -0
  82. package/.next/standalone/.next/server/chunks/_185gyk9._.js +3 -0
  83. package/.next/standalone/.next/server/chunks/_1ek68ln._.js +5 -6
  84. package/.next/standalone/.next/server/chunks/lib_telemetry-id_ts_1k8gj9o._.js +3 -0
  85. package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_09d5c79._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_04op_ou._.js} +1 -1
  86. package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_1d2g73o._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_0dr20uz._.js} +1 -1
  87. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  88. package/.next/standalone/.next/server/chunks/src_hooks_0xbw3bu._.js +12 -0
  89. package/.next/standalone/.next/server/chunks/src_hooks_fp-home_ts_09kv0bn._.js +1 -1
  90. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013jr2b._.js +4 -0
  91. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01wy8d-._.js +4 -0
  92. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02npjtd._.js +4 -0
  93. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0spkm68._.js → [root-of-the-server]__07gm3zl._.js} +21 -20
  94. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0da85px._.js +4 -0
  95. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ftmoxc._.js +4 -0
  96. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oa1lav._.js +1 -1
  97. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0p-5p8u._.js +4 -0
  98. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s740oi._.js +6 -0
  99. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__07tbbf3._.js → [root-of-the-server]__0zig5sv._.js} +2 -2
  100. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__192nhvh._.js +5 -0
  101. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1p2otjt._.js +4 -0
  102. package/.next/standalone/.next/server/chunks/ssr/{_0lvyuv4._.js → _00e9tnf._.js} +2 -2
  103. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  104. package/.next/standalone/.next/server/chunks/ssr/{_0u5zauv._.js → _12l4a_k._.js} +1 -1
  105. package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.js +1 -1
  106. package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
  107. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +13 -13
  108. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  109. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
  110. package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +1 -1
  111. package/.next/standalone/.next/server/chunks/ssr/src_hooks_08o7bqo._.js +10 -0
  112. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +1 -1
  113. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
  114. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  115. package/.next/standalone/.next/server/middleware.js +1 -1
  116. package/.next/standalone/.next/server/pages/404.html +1 -1
  117. package/.next/standalone/.next/server/pages/500.html +1 -1
  118. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  119. package/.next/standalone/.next/server/server-reference-manifest.json +71 -27
  120. package/.next/standalone/.next/static/chunks/{37fcpc36x9gpe.js → 0eqky-7n7dgdm.js} +1 -1
  121. package/.next/standalone/.next/static/chunks/{1ide1wl2f7zi1.js → 0sa9v5mhc8861.js} +13 -13
  122. package/.next/standalone/.next/static/chunks/1mfzsja6ftim5.css +2 -0
  123. package/.next/standalone/.next/static/chunks/{3k7mxbp9hiom0.js → 1nuqytbta44af.js} +1 -1
  124. package/.next/standalone/.next/static/chunks/1sl2xmn9inx3y.js +6 -0
  125. package/.next/standalone/.next/static/chunks/{2_2lhuojq2xop.js → 2aawsjld9ied_.js} +1 -1
  126. package/.next/standalone/.next/static/chunks/2gn7ut4svofm2.js +1 -0
  127. package/.next/standalone/.next/static/chunks/{31s1smp-g7gks.js → 2hs7ycvsav7v2.js} +1 -1
  128. package/.next/standalone/.next/static/chunks/{0k5050ezjvv49.js → 2i2yt3hzjredm.js} +1 -1
  129. package/.next/standalone/.next/static/chunks/{3c808qrfcq0im.js → 35xg6retpe6rp.js} +1 -1
  130. package/.next/standalone/.next/static/chunks/{2zpp1we2jv6tb.js → 3y54nw0i7dsjl.js} +1 -1
  131. package/.next/standalone/SECURITY.md +5 -4
  132. package/.next/standalone/app/actions/get-hooks-config.ts +108 -17
  133. package/.next/standalone/app/actions/pack-actions.ts +153 -0
  134. package/.next/standalone/app/audit/_components/run-progress.tsx +1 -1
  135. package/.next/standalone/app/audit/_components/share-templates.ts +13 -13
  136. package/.next/standalone/app/policies/hooks-client.tsx +320 -14
  137. package/.next/standalone/components/navbar.tsx +2 -28
  138. package/.next/standalone/components/reach-developers.tsx +8 -1
  139. package/.next/standalone/docs-old/agenteye/python-sdk-skill.mdx +1 -1
  140. package/.next/standalone/docs-old/agenteye/python-sdk.mdx +59 -35
  141. package/.next/standalone/docs-old/i18n/README.ar.md +1 -0
  142. package/.next/standalone/docs-old/i18n/README.de.md +1 -0
  143. package/.next/standalone/docs-old/i18n/README.es.md +1 -0
  144. package/.next/standalone/docs-old/i18n/README.fr.md +1 -0
  145. package/.next/standalone/docs-old/i18n/README.he.md +1 -0
  146. package/.next/standalone/docs-old/i18n/README.hi.md +1 -0
  147. package/.next/standalone/docs-old/i18n/README.it.md +1 -0
  148. package/.next/standalone/docs-old/i18n/README.ja.md +1 -0
  149. package/.next/standalone/docs-old/i18n/README.ko.md +1 -0
  150. package/.next/standalone/docs-old/i18n/README.pt-br.md +1 -0
  151. package/.next/standalone/docs-old/i18n/README.ru.md +1 -0
  152. package/.next/standalone/docs-old/i18n/README.tr.md +1 -0
  153. package/.next/standalone/docs-old/i18n/README.vi.md +1 -0
  154. package/.next/standalone/docs-old/i18n/README.zh.md +1 -0
  155. package/.next/standalone/fp-cloud-cli/CHANGELOG.md +431 -0
  156. package/.next/standalone/fp-cloud-cli/LICENSE +42 -0
  157. package/.next/standalone/fp-cloud-cli/MANIFEST.in +10 -0
  158. package/.next/standalone/fp-cloud-cli/README.md +259 -0
  159. package/.next/standalone/fp-cloud-cli/fp_cli/__init__.py +10 -0
  160. package/.next/standalone/fp-cloud-cli/fp_cli/__main__.py +4 -0
  161. package/.next/standalone/fp-cloud-cli/fp_cli/_click_compat.py +64 -0
  162. package/.next/standalone/fp-cloud-cli/fp_cli/_context.py +332 -0
  163. package/.next/standalone/fp-cloud-cli/fp_cli/_version.py +1 -0
  164. package/.next/standalone/fp-cloud-cli/fp_cli/analytics.py +432 -0
  165. package/.next/standalone/fp-cloud-cli/fp_cli/analytics_config.py +77 -0
  166. package/.next/standalone/fp-cloud-cli/fp_cli/analytics_registry.py +83 -0
  167. package/.next/standalone/fp-cloud-cli/fp_cli/app.py +492 -0
  168. package/.next/standalone/fp-cloud-cli/fp_cli/auth.py +160 -0
  169. package/.next/standalone/fp-cloud-cli/fp_cli/client.py +1694 -0
  170. package/.next/standalone/fp-cloud-cli/fp_cli/commands/__init__.py +0 -0
  171. package/.next/standalone/fp-cloud-cli/fp_cli/commands/_write.py +214 -0
  172. package/.next/standalone/fp-cloud-cli/fp_cli/commands/agent_cmds.py +407 -0
  173. package/.next/standalone/fp-cloud-cli/fp_cli/commands/alerts_cmds.py +445 -0
  174. package/.next/standalone/fp-cloud-cli/fp_cli/commands/audits_cmds.py +1054 -0
  175. package/.next/standalone/fp-cloud-cli/fp_cli/commands/auth_cmds.py +512 -0
  176. package/.next/standalone/fp-cloud-cli/fp_cli/commands/errors_cmds.py +190 -0
  177. package/.next/standalone/fp-cloud-cli/fp_cli/commands/evals_cmds.py +161 -0
  178. package/.next/standalone/fp-cloud-cli/fp_cli/commands/events_cmds.py +159 -0
  179. package/.next/standalone/fp-cloud-cli/fp_cli/commands/fleet_cmds.py +416 -0
  180. package/.next/standalone/fp-cloud-cli/fp_cli/commands/guardrails_cmds.py +148 -0
  181. package/.next/standalone/fp-cloud-cli/fp_cli/commands/incidents_cmds.py +472 -0
  182. package/.next/standalone/fp-cloud-cli/fp_cli/commands/keys_cmds.py +407 -0
  183. package/.next/standalone/fp-cloud-cli/fp_cli/commands/list_cmds.py +63 -0
  184. package/.next/standalone/fp-cloud-cli/fp_cli/commands/orgs_cmds.py +319 -0
  185. package/.next/standalone/fp-cloud-cli/fp_cli/commands/policies_cmds.py +499 -0
  186. package/.next/standalone/fp-cloud-cli/fp_cli/commands/queries_cmds.py +378 -0
  187. package/.next/standalone/fp-cloud-cli/fp_cli/commands/sessions_cmds.py +151 -0
  188. package/.next/standalone/fp-cloud-cli/fp_cli/commands/settings_cmds.py +150 -0
  189. package/.next/standalone/fp-cloud-cli/fp_cli/commands/usage_cmds.py +35 -0
  190. package/.next/standalone/fp-cloud-cli/fp_cli/commands/users_cmds.py +404 -0
  191. package/.next/standalone/fp-cloud-cli/fp_cli/config.py +330 -0
  192. package/.next/standalone/fp-cloud-cli/fp_cli/dates.py +78 -0
  193. package/.next/standalone/fp-cloud-cli/fp_cli/enforcement.py +345 -0
  194. package/.next/standalone/fp-cloud-cli/fp_cli/errors.py +98 -0
  195. package/.next/standalone/fp-cloud-cli/fp_cli/models.py +891 -0
  196. package/.next/standalone/fp-cloud-cli/fp_cli/orgs.py +30 -0
  197. package/.next/standalone/fp-cloud-cli/fp_cli/output.py +6593 -0
  198. package/.next/standalone/fp-cloud-cli/fp_cli/permissions.py +208 -0
  199. package/.next/standalone/fp-cloud-cli/fp_cli/policy_check.py +290 -0
  200. package/.next/standalone/fp-cloud-cli/fp_cli/py.typed +0 -0
  201. package/.next/standalone/fp-cloud-cli/fp_cli/select.py +322 -0
  202. package/.next/standalone/fp-cloud-cli/fp_cli/theme.py +53 -0
  203. package/.next/standalone/fp-cloud-cli/pyproject.toml +106 -0
  204. package/.next/standalone/fp-cloud-cli/skill/SKILL.md +302 -0
  205. package/.next/standalone/fp-cloud-cli/skill/agents/openai.yaml +8 -0
  206. package/.next/standalone/fp-cloud-cli/skill/references/commands.md +254 -0
  207. package/.next/standalone/fp-cloud-cli/tests/__init__.py +0 -0
  208. package/.next/standalone/fp-cloud-cli/tests/conftest.py +92 -0
  209. package/.next/standalone/fp-cloud-cli/tests/test_alerting.py +644 -0
  210. package/.next/standalone/fp-cloud-cli/tests/test_analytics.py +385 -0
  211. package/.next/standalone/fp-cloud-cli/tests/test_audits.py +950 -0
  212. package/.next/standalone/fp-cloud-cli/tests/test_auth.py +98 -0
  213. package/.next/standalone/fp-cloud-cli/tests/test_auth_mode.py +272 -0
  214. package/.next/standalone/fp-cloud-cli/tests/test_click_compat.py +118 -0
  215. package/.next/standalone/fp-cloud-cli/tests/test_client.py +299 -0
  216. package/.next/standalone/fp-cloud-cli/tests/test_commands.py +814 -0
  217. package/.next/standalone/fp-cloud-cli/tests/test_config.py +99 -0
  218. package/.next/standalone/fp-cloud-cli/tests/test_dashboards_agent.py +340 -0
  219. package/.next/standalone/fp-cloud-cli/tests/test_dates.py +76 -0
  220. package/.next/standalone/fp-cloud-cli/tests/test_enforcement_logic.py +481 -0
  221. package/.next/standalone/fp-cloud-cli/tests/test_facets.py +170 -0
  222. package/.next/standalone/fp-cloud-cli/tests/test_failproofai_home.py +722 -0
  223. package/.next/standalone/fp-cloud-cli/tests/test_fp_home_contract.py +198 -0
  224. package/.next/standalone/fp-cloud-cli/tests/test_hardening.py +186 -0
  225. package/.next/standalone/fp-cloud-cli/tests/test_help_table_coverage.py +127 -0
  226. package/.next/standalone/fp-cloud-cli/tests/test_keys_queries.py +496 -0
  227. package/.next/standalone/fp-cloud-cli/tests/test_list.py +59 -0
  228. package/.next/standalone/fp-cloud-cli/tests/test_multivalue.py +183 -0
  229. package/.next/standalone/fp-cloud-cli/tests/test_no_customer_identifiers.py +168 -0
  230. package/.next/standalone/fp-cloud-cli/tests/test_operator.py +492 -0
  231. package/.next/standalone/fp-cloud-cli/tests/test_orgs.py +692 -0
  232. package/.next/standalone/fp-cloud-cli/tests/test_output.py +1732 -0
  233. package/.next/standalone/fp-cloud-cli/tests/test_policy_check.py +191 -0
  234. package/.next/standalone/fp-cloud-cli/tests/test_readme_matches_reality.py +125 -0
  235. package/.next/standalone/fp-cloud-cli/tests/test_review_fixes.py +161 -0
  236. package/.next/standalone/fp-cloud-cli/tests/test_telemetry_completeness.py +90 -0
  237. package/.next/standalone/fp-cloud-cli/tests/test_usage.py +115 -0
  238. package/.next/standalone/fp-cloud-cli/tests/test_v1_origin_diagnostic.py +70 -0
  239. package/.next/standalone/fp-cloud-cli/tests/test_v1_routing.py +214 -0
  240. package/.next/standalone/fp-cloud-cli/tests/test_whoami.py +104 -0
  241. package/.next/standalone/fp-cloud-cli/uv.lock +552 -0
  242. package/.next/standalone/package.json +29 -22
  243. package/.next/standalone/sdk/python/CHANGELOG.md +70 -0
  244. package/.next/standalone/sdk/python/LICENSE +42 -0
  245. package/.next/standalone/sdk/python/MANIFEST.in +21 -0
  246. package/.next/standalone/sdk/python/README.md +466 -0
  247. package/.next/standalone/sdk/python/docs/README.md +249 -0
  248. package/.next/standalone/sdk/python/docs/_shared/README.md +43 -0
  249. package/.next/standalone/sdk/python/docs/_shared/__init__.py +195 -0
  250. package/.next/standalone/sdk/python/docs/crewai/README.md +328 -0
  251. package/.next/standalone/sdk/python/docs/crewai/examples/quickstart.py +61 -0
  252. package/.next/standalone/sdk/python/docs/crewai/examples/research_crew.py +92 -0
  253. package/.next/standalone/sdk/python/docs/langgraph/README.md +481 -0
  254. package/.next/standalone/sdk/python/docs/langgraph/examples/quickstart.py +51 -0
  255. package/.next/standalone/sdk/python/docs/langgraph/examples/research_agent.py +86 -0
  256. package/.next/standalone/sdk/python/docs/langgraph/examples/supervisor_handoff.py +83 -0
  257. package/.next/standalone/sdk/python/docs/llama_index/README.md +332 -0
  258. package/.next/standalone/sdk/python/docs/llama_index/examples/quickstart.py +62 -0
  259. package/.next/standalone/sdk/python/docs/llama_index/examples/research_agent.py +93 -0
  260. package/.next/standalone/sdk/python/docs/manual/README.md +491 -0
  261. package/.next/standalone/sdk/python/docs/manual/examples/quickstart.py +57 -0
  262. package/.next/standalone/sdk/python/docs/manual/examples/research_agent.py +133 -0
  263. package/.next/standalone/sdk/python/docs/pydantic_ai/README.md +323 -0
  264. package/.next/standalone/sdk/python/docs/pydantic_ai/examples/quickstart.py +48 -0
  265. package/.next/standalone/sdk/python/docs/pydantic_ai/examples/research_agent.py +94 -0
  266. package/.next/standalone/sdk/python/failproofai_sdk/__init__.py +131 -0
  267. package/.next/standalone/sdk/python/failproofai_sdk/_context.py +218 -0
  268. package/.next/standalone/sdk/python/failproofai_sdk/_environment.py +78 -0
  269. package/.next/standalone/sdk/python/failproofai_sdk/_events.py +752 -0
  270. package/.next/standalone/sdk/python/failproofai_sdk/_resolver.py +118 -0
  271. package/.next/standalone/sdk/python/failproofai_sdk/_runtime.py +21 -0
  272. package/.next/standalone/sdk/python/failproofai_sdk/_schema.py +317 -0
  273. package/.next/standalone/sdk/python/failproofai_sdk/_scopes.py +422 -0
  274. package/.next/standalone/sdk/python/failproofai_sdk/_version.py +1 -0
  275. package/.next/standalone/sdk/python/failproofai_sdk/_writer.py +750 -0
  276. package/.next/standalone/sdk/python/failproofai_sdk/integrations/__init__.py +274 -0
  277. package/.next/standalone/sdk/python/failproofai_sdk/integrations/_compat.py +247 -0
  278. package/.next/standalone/sdk/python/failproofai_sdk/integrations/_core.py +1076 -0
  279. package/.next/standalone/sdk/python/failproofai_sdk/integrations/crewai.py +1669 -0
  280. package/.next/standalone/sdk/python/failproofai_sdk/integrations/langchain.py +2151 -0
  281. package/.next/standalone/sdk/python/failproofai_sdk/integrations/llama_index.py +1588 -0
  282. package/.next/standalone/sdk/python/failproofai_sdk/integrations/pydantic_ai.py +977 -0
  283. package/.next/standalone/sdk/python/failproofai_sdk/py.typed +0 -0
  284. package/.next/standalone/sdk/python/pyproject.toml +92 -0
  285. package/.next/standalone/sdk/python/skill/SKILL.md +399 -0
  286. package/.next/standalone/sdk/python/skill/agents/openai.yaml +8 -0
  287. package/.next/standalone/sdk/python/skill/references/events.md +234 -0
  288. package/.next/standalone/sdk/python/skill/references/frameworks.md +314 -0
  289. package/.next/standalone/sdk/python/skill/references/install.md +100 -0
  290. package/.next/standalone/sdk/python/skill/references/integration.md +352 -0
  291. package/.next/standalone/sdk/python/tests/__init__.py +0 -0
  292. package/.next/standalone/sdk/python/tests/conftest.py +169 -0
  293. package/.next/standalone/sdk/python/tests/integrations/__init__.py +6 -0
  294. package/.next/standalone/sdk/python/tests/integrations/test_crewai.py +1299 -0
  295. package/.next/standalone/sdk/python/tests/integrations/test_langchain.py +2338 -0
  296. package/.next/standalone/sdk/python/tests/integrations/test_llama_index.py +1576 -0
  297. package/.next/standalone/sdk/python/tests/integrations/test_pydantic_ai.py +1102 -0
  298. package/.next/standalone/sdk/python/tests/test_context.py +410 -0
  299. package/.next/standalone/sdk/python/tests/test_docs.py +411 -0
  300. package/.next/standalone/sdk/python/tests/test_durability.py +1352 -0
  301. package/.next/standalone/sdk/python/tests/test_encoding.py +571 -0
  302. package/.next/standalone/sdk/python/tests/test_integrations.py +1127 -0
  303. package/.next/standalone/sdk/python/tests/test_no_customer_identifiers.py +214 -0
  304. package/.next/standalone/sdk/python/tests/test_packaging.py +185 -0
  305. package/.next/standalone/sdk/python/tests/test_resolver_umbrella.py +178 -0
  306. package/.next/standalone/sdk/python/tests/test_scopes.py +487 -0
  307. package/.next/standalone/sdk/python/tests/test_sdk.py +923 -0
  308. package/.next/standalone/sdk/python/tests/test_server_contract.py +650 -0
  309. package/.next/standalone/sdk/python/tests/test_site_docs.py +371 -0
  310. package/.next/standalone/sdk/python/tests/test_skill_snippets.py +165 -0
  311. package/.next/standalone/sdk/python/tests/test_spool_contract.py +287 -0
  312. package/.next/standalone/sdk/python/tests/test_spool_creation.py +360 -0
  313. package/.next/standalone/sdk/python/tests/test_wire_format.py +279 -0
  314. package/.next/standalone/sdk/python/tests/test_zero_dependencies.py +378 -0
  315. package/.next/standalone/sdk/python/uv.lock +6005 -0
  316. package/.next/standalone/server.js +1 -1
  317. package/README.md +77 -21
  318. package/bin/failproofai.mjs +145 -11
  319. package/dist/cli.mjs +4482 -2205
  320. package/dist/index.js +5 -5
  321. package/dist/worker.mjs +2399 -1978
  322. package/package.json +29 -22
  323. package/policy-pack/SHA256SUMS +2 -0
  324. package/policy-pack/failproofai-pack.json +732 -0
  325. package/policy-pack/failproofai-pack.mjs +2017 -0
  326. package/scripts/build-policy-pack.mjs +121 -0
  327. package/scripts/changelog-section.py +77 -0
  328. package/scripts/prune-standalone.mjs +3 -0
  329. package/scripts/python-version.py +232 -0
  330. package/scripts/translate-docs/cli.ts +21 -0
  331. package/scripts/translate-docs/mintlify-nav.ts +85 -13
  332. package/scripts/translate-docs/translator.ts +66 -11
  333. package/src/audit/cache.ts +40 -3
  334. package/src/audit/cli.ts +1 -1
  335. package/src/audit/index.ts +1 -1
  336. package/src/audit/replay.ts +89 -3
  337. package/src/audit/report.ts +5 -5
  338. package/src/audit/schedule-cli.ts +49 -53
  339. package/src/hooks/builtin-policies.ts +217 -579
  340. package/src/hooks/cloud-enrollment-cli.ts +66 -27
  341. package/src/hooks/cloud-managed-policies.ts +6 -1
  342. package/src/hooks/configure-wizard.ts +1 -1
  343. package/src/hooks/custom-hooks-loader.ts +89 -6
  344. package/src/hooks/fp-home.ts +92 -4
  345. package/src/hooks/fp-reset.ts +26 -2
  346. package/src/hooks/handler.ts +181 -11
  347. package/src/hooks/harness-cli.ts +79 -25
  348. package/src/hooks/hook-activity-store.ts +13 -3
  349. package/src/hooks/install-prompt.ts +25 -3
  350. package/src/hooks/manager.ts +418 -172
  351. package/src/hooks/migrations.ts +2 -2
  352. package/src/hooks/pack-cli.ts +505 -0
  353. package/src/hooks/pack-failclosed.ts +189 -0
  354. package/src/hooks/pack-manifest.ts +344 -0
  355. package/src/hooks/pack-store.ts +930 -0
  356. package/src/hooks/policy-catalog.ts +535 -0
  357. package/src/hooks/policy-evaluator.ts +24 -16
  358. package/src/hooks/policy-presets.ts +4 -2
  359. package/src/hooks/policy-registry.ts +8 -2
  360. package/src/hooks/policy-types.ts +26 -0
  361. package/src/hooks/session-pause-cli.ts +33 -9
  362. package/src/hooks/tui.ts +570 -0
  363. package/src/hooks/types.ts +15 -1
  364. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_usx0j._.js +0 -3
  365. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_zk340._.js +0 -3
  366. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0agdw2a._.js +0 -3
  367. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d1u_na._.js +0 -3
  368. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0oy4kxb._.js +0 -3
  369. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zf034w._.js +0 -3
  370. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tvn4wf._.js +0 -3
  371. package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +0 -3
  372. package/.next/standalone/.next/server/chunks/_1ger0a2._.js +0 -3
  373. package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +0 -3
  374. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_1iiwm5e._.js +0 -3
  375. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0kc8_v5._.js +0 -4
  376. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0kgy9da._.js +0 -4
  377. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0mhqk5a._.js +0 -4
  378. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0pltpn8._.js +0 -4
  379. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qkcyf-._.js +0 -4
  380. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0w0x_ok._.js +0 -4
  381. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1_dfocn._.js +0 -4
  382. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1bfex62._.js +0 -5
  383. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1kzapg5._.js +0 -6
  384. package/.next/standalone/.next/static/chunks/36fw6yk1s6x_f.js +0 -1
  385. package/.next/standalone/.next/static/chunks/3tzq0260n17ae.js +0 -6
  386. package/.next/standalone/.next/static/chunks/3wq9x0c-7ld5d.css +0 -2
  387. /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → nwbyWT06Ud0XdXOrVJyvS}/_buildManifest.js +0 -0
  388. /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → nwbyWT06Ud0XdXOrVJyvS}/_clientMiddlewareManifest.js +0 -0
  389. /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → nwbyWT06Ud0XdXOrVJyvS}/_ssgManifest.js +0 -0
@@ -0,0 +1,189 @@
1
+ /**
2
+ * What a machine does when a pack it was told to enforce will not load.
3
+ *
4
+ * ## Why this exists at all
5
+ *
6
+ * Every content-load failure in this codebase fails OPEN, and that was sound
7
+ * only while the builtin policies shipped compiled in and kept enforcing
8
+ * underneath. Once the builtins ARE a pack, the same behaviour becomes zero
9
+ * enforcement at exit 0 on a machine that reports healthy — so the layer that
10
+ * used to be allowed to degrade quietly now has to deny.
11
+ *
12
+ * ## The line: recorded expectation, never an empty manifest
13
+ *
14
+ * A machine with no packs is a fresh machine, not a broken one. `installed.json`
15
+ * being ABSENT is silence; being present and unreadable is a failure. So the
16
+ * trigger is always "something was declared and is not running", never
17
+ * "nothing is running".
18
+ *
19
+ * ## Why the deny is narrow
20
+ *
21
+ * An unreachable daemon denies everything, correctly: no evaluation happened, so
22
+ * nothing can be known safe. An unloadable pack is different — the missing
23
+ * guards are ENUMERABLE, because every declared policy must carry a `match`. So
24
+ * the deny matches only the events and tools those policies claimed, and
25
+ * `getPoliciesForEvent` narrows it for free.
26
+ *
27
+ * `UserPromptSubmit` is exempt no matter what a missing policy declared, and
28
+ * instructs instead. handler.ts records why from a real machine: a blanket deny
29
+ * takes `UserPromptSubmit` with it and locks the user out of their agent
30
+ * entirely. The one event that can tell a human what happened is the one event
31
+ * that must never deny.
32
+ */
33
+ import type { PackError, ResolvedPack } from "./pack-manifest";
34
+ import type { PolicyLoadFailure } from "./custom-hooks-loader";
35
+ import type { HookEventType } from "./types";
36
+ import type { PolicyMatcher } from "./policy-types";
37
+
38
+ /** A guard that was expected to run and did not. */
39
+ export interface MissingGuard {
40
+ packId: string;
41
+ packVersion: string | null;
42
+ policies: string[];
43
+ match: PolicyMatcher;
44
+ reason: string;
45
+ }
46
+
47
+ /**
48
+ * Load classifications that are PERMANENT, and so may deny.
49
+ *
50
+ * `load_timeout` is deliberately absent. It is transient and load-dependent, and
51
+ * a machine-wide deny triggered by one slow disk moment persists until a human
52
+ * intervenes — in the warm worker, where every evaluation is serialized behind
53
+ * one queue, the denials themselves add load. Timeouts warn and are recorded.
54
+ */
55
+ export const PERMANENT_LOAD_FAILURES: ReadonlySet<string> = new Set([
56
+ "module_not_found",
57
+ "syntax_error",
58
+ "runtime_error",
59
+ "path_missing",
60
+ ]);
61
+
62
+ function unionMatch(matchers: PolicyMatcher[]): PolicyMatcher {
63
+ const events = new Set<HookEventType>();
64
+ const toolNames = new Set<string>();
65
+ let anyEvent = false;
66
+ let anyTool = false;
67
+ for (const m of matchers) {
68
+ if (!m.events || m.events.length === 0) anyEvent = true;
69
+ else for (const e of m.events) events.add(e);
70
+ if (!m.toolNames || m.toolNames.length === 0) anyTool = true;
71
+ else for (const t of m.toolNames) toolNames.add(t);
72
+ }
73
+ const scoped: PolicyMatcher = {};
74
+ // Every declared event is kept, INCLUDING UserPromptSubmit. This says where
75
+ // the missing guards applied; how to answer there is the caller's decision —
76
+ // and on UserPromptSubmit the answer is `instruct`, so the human is told
77
+ // without being locked out of the agent that could fix it. Filtering the event
78
+ // out here instead made that branch unreachable.
79
+ if (!anyEvent) scoped.events = [...events];
80
+ if (!anyTool) scoped.toolNames = [...toolNames];
81
+ return scoped;
82
+ }
83
+
84
+ /**
85
+ * Work out which guards a machine expected and is not running.
86
+ *
87
+ * `enabledFor` answers "did the user actually take this policy" — a pack the
88
+ * user took 3 of 40 from is not a failure because the other 37 did not load.
89
+ * `disabled` is the `disabledCustomPolicies` set, keyed `pack:<id>@<ver>:<name>`.
90
+ */
91
+ export function missingGuards(input: {
92
+ errors: PackError[];
93
+ packs: ResolvedPack[];
94
+ /** Policy names a pack registered, keyed by pack id. */
95
+ registered: Map<string, Set<string>>;
96
+ /** Packs handed to the loader whose entry artifact failed to import. */
97
+ failed: Map<string, PolicyLoadFailure>;
98
+ disabled: ReadonlySet<string>;
99
+ }): MissingGuard[] {
100
+ const out: MissingGuard[] = [];
101
+
102
+ // (a) Declared in installed.json, never resolved.
103
+ for (const err of input.errors) {
104
+ // An observe pack denying on failure would deny for something that, had it
105
+ // loaded, would have allowed.
106
+ if (err.effect === "observe") continue;
107
+ const declared = err.declared ?? [];
108
+ out.push({
109
+ packId: err.id ?? "(unnamed pack)",
110
+ packVersion: null,
111
+ policies: declared.map((p) => p.name),
112
+ // No declared policies means nothing to narrow with, so this one is
113
+ // unavoidably blanket — minus the never-deny events.
114
+ match: declared.length > 0 ? unionMatch(declared.map((p) => p.match)) : unionMatch([{}]),
115
+ reason: err.reason,
116
+ });
117
+ }
118
+
119
+ // (c) Resolved, but registered less than it declared.
120
+ for (const pack of input.packs) {
121
+ if (pack.effect === "observe") continue;
122
+ const loadFailure = input.failed.get(pack.id);
123
+ if (loadFailure && PERMANENT_LOAD_FAILURES.has(loadFailure.type)) {
124
+ const taken = pack.enabled ?? pack.policies.map((p) => p.name);
125
+ const unavailable = pack.policies.filter(
126
+ (p) =>
127
+ taken.includes(p.name) &&
128
+ !input.disabled.has(`pack:${pack.id}@${pack.version}:${p.name}`),
129
+ );
130
+ if (unavailable.length > 0) {
131
+ out.push({
132
+ packId: pack.id,
133
+ packVersion: pack.version,
134
+ policies: unavailable.map((p) => p.name),
135
+ match: unionMatch(unavailable.map((p) => p.match)),
136
+ reason: `artifact failed to load: ${loadFailure.reason}`,
137
+ });
138
+ }
139
+ continue;
140
+ }
141
+ const registered = input.registered.get(pack.id);
142
+ // A pack absent from both maps was never handed to the loader at all.
143
+ // Guessing failure from "no registrations" cannot distinguish that from a
144
+ // pause skip or a pack that legitimately registers nothing.
145
+ if (!registered) continue;
146
+
147
+ const taken = pack.enabled ?? pack.policies.map((p) => p.name);
148
+ const missing = pack.policies.filter(
149
+ (p) =>
150
+ taken.includes(p.name) &&
151
+ !registered.has(p.name) &&
152
+ !input.disabled.has(`pack:${pack.id}@${pack.version}:${p.name}`),
153
+ );
154
+ if (missing.length === 0) continue;
155
+ out.push({
156
+ packId: pack.id,
157
+ packVersion: pack.version,
158
+ policies: missing.map((p) => p.name),
159
+ match: unionMatch(missing.map((p) => p.match)),
160
+ reason: `declared ${missing.length} polic${missing.length === 1 ? "y" : "ies"} its artifact did not register`,
161
+ });
162
+ }
163
+
164
+ // A guard that ended up matching no event at all cannot say anything.
165
+ return out.filter((g) => !(g.match.events && g.match.events.length === 0));
166
+ }
167
+
168
+ /**
169
+ * The message a human reads.
170
+ *
171
+ * Recovery is a HUMAN terminal action and the text has to name the command,
172
+ * because the agent cannot run it: `block-failproofai-commands` denies every
173
+ * `failproofai` invocation from a tool call, deliberately and unconditionally.
174
+ */
175
+ export function packFailureReason(guards: MissingGuard[]): string {
176
+ const named = guards
177
+ .map((g) => {
178
+ const where = g.packVersion ? `${g.packId}@${g.packVersion}` : g.packId;
179
+ const what = g.policies.length > 0 ? `: ${g.policies.slice(0, 4).join(", ")}` : "";
180
+ return `${where} (${g.reason})${what}`;
181
+ })
182
+ .join("; ");
183
+ return (
184
+ `Blocked because a policy pack this machine is configured to enforce is not running — ${named}. ` +
185
+ `Enforcement you were told you had is missing, so this is refused rather than allowed silently. ` +
186
+ `A human needs to run: failproofai pack list, then failproofai pack add <source> (or failproofai config). ` +
187
+ `The agent cannot run those itself.`
188
+ );
189
+ }
@@ -0,0 +1,344 @@
1
+ /**
2
+ * Reads the installed policy packs a machine has on disk.
3
+ *
4
+ * A pack is the delivery unit for policies that did not ship compiled into this
5
+ * build: `failproofai pack add` writes the artifact and records it here, and the
6
+ * loader imports it through the same path custom policies already use.
7
+ *
8
+ * ## Why this is not `cloud-managed-policies.ts`
9
+ *
10
+ * It is modelled on it closely — same content-addressed artifacts, same
11
+ * verify-immediately-before-import boundary, same shared `resolveManagedPath`.
12
+ * Three things differ, each for a reason:
13
+ *
14
+ * - **Failure is PER PACK, not per manifest.** The cloud reader throws on the
15
+ * first bad entry, which is right for a fleet deployment: a manifest the
16
+ * server sent is one unit and half of it is not a deployment. Packs come from
17
+ * unrelated publishers, so one malformed third-party pack must not switch off
18
+ * every other pack on the machine.
19
+ * - **It never throws.** A caller gets `{packs, errors}`. See the fail-open note
20
+ * below — it is a load-bearing assumption, not a convenience.
21
+ * - **Two refusals cloud does not need**, both closing silent failures:
22
+ * a pack may not claim `alwaysOn`, and a pack policy name may not contain `/`.
23
+ *
24
+ * ## Fail-open, and the condition that makes it sound
25
+ *
26
+ * An unreadable manifest, a bad digest or a corrupt artifact yields zero packs
27
+ * and a recorded error — it does not deny. That is only defensible **while the
28
+ * builtin policies still ship compiled into the package and keep enforcing
29
+ * underneath**. The day builtins become a fetched pack, this exact behaviour
30
+ * becomes "zero enforcement on a machine reporting healthy", and this comment is
31
+ * the reason that must be revisited rather than inherited.
32
+ */
33
+ import { createHash } from "node:crypto";
34
+ import { existsSync, readFileSync } from "node:fs";
35
+ import { resolve } from "node:path";
36
+ import { packsDir, packsInstalledFile } from "./fp-home";
37
+ import { resolveManagedPath } from "./cloud-managed-policies";
38
+ import type { PolicyCatalogEntry } from "./policy-types";
39
+ import type { PolicyEffect } from "./cloud-managed-policies";
40
+
41
+ /** Manifest schemas this reader accepts. */
42
+ const ACCEPTED_PACK_SCHEMA_VERSIONS: readonly number[] = [1];
43
+
44
+ const SHA256_RE = /^[a-f0-9]{64}$/;
45
+ /** `<publisher>/<name>`, the shape a marketplace id takes. */
46
+ export const PACK_ID_RE = /^[A-Za-z0-9._-]{1,64}\/[A-Za-z0-9._-]{1,64}$/;
47
+ /** A version string, kept loose enough for semver and a tag. */
48
+ export const PACK_VERSION_RE = /^[A-Za-z0-9][A-Za-z0-9._+-]{0,63}$/;
49
+ /**
50
+ * A pack policy's own name. `/` is REFUSED, and that is the important character:
51
+ * `normalizePolicyName` passes any name containing one straight through, and
52
+ * `registerPolicy` REPLACES by canonical name — so a pack shipping a policy
53
+ * literally called `failproofai/block-sudo` would silently overwrite the
54
+ * compiled builtin with its own code. Names here are prefixed by the loader
55
+ * instead, which is what keeps a pack unable to reach the builtin namespace.
56
+ */
57
+ const PACK_POLICY_NAME_RE = /^[A-Za-z0-9._-]{1,128}$/;
58
+
59
+ export interface InstalledPackRecord {
60
+ id: string;
61
+ version: string;
62
+ /** Where it came from, verbatim, e.g. `github:acme/pack@v2.1.0`. */
63
+ source: string;
64
+ /** Path to the single entry artifact, relative to `packsDir()`. */
65
+ entry: string;
66
+ sha256: string;
67
+ effect?: string;
68
+ policies?: unknown;
69
+ /**
70
+ * Which of the pack's policies to register. Absent means ALL of them.
71
+ *
72
+ * Stored here rather than as `disabledCustomPolicies` entries because those
73
+ * are keyed by `pack:<id>@<version>:<name>` — so an upgrade to a new version
74
+ * stops matching and everything the user opted out of silently comes back on.
75
+ * A choice about what to take from a pack has to outlive the version it was
76
+ * made against.
77
+ */
78
+ enabled?: string[];
79
+ }
80
+
81
+ export interface ResolvedPack {
82
+ id: string;
83
+ version: string;
84
+ source: string;
85
+ /** Absolute, real, verified-to-be-inside-the-root path to the entry module. */
86
+ path: string;
87
+ sha256: string;
88
+ effect: PolicyEffect;
89
+ /** The pack's own catalog, in declared order. */
90
+ policies: PolicyCatalogEntry[];
91
+ /** Selected policy names, or null when the user took the whole pack. */
92
+ enabled: string[] | null;
93
+ }
94
+
95
+ export interface PackError {
96
+ /** The pack's id when it was readable enough to have one. */
97
+ id: string | null;
98
+ reason: string;
99
+ /**
100
+ * The effect the failed pack asked for, when it got far enough to say.
101
+ *
102
+ * Carried because an `observe` pack that fails to load must NOT make the
103
+ * machine deny: an observe pack evaluates and discards by construction, so
104
+ * denying on its behalf denies for something that would have allowed. Effect
105
+ * is validated BEFORE the digest check, so for every failure at or after that
106
+ * point it was already known — and was previously thrown away with the
107
+ * exception.
108
+ */
109
+ effect?: PolicyEffect;
110
+ /**
111
+ * Policy names the entry declared, when it parsed far enough to list them.
112
+ * Lets the deny name what is missing instead of being blanket.
113
+ */
114
+ declared?: PolicyCatalogEntry[];
115
+ }
116
+
117
+ export interface PackReadResult {
118
+ packs: ResolvedPack[];
119
+ /** Every pack that was declared and refused, and why. Never silently dropped. */
120
+ errors: PackError[];
121
+ }
122
+
123
+ export function packsRoot(): string {
124
+ return process.env.FAILPROOFAI_PACK_DIR ?? packsDir();
125
+ }
126
+
127
+ /** Validate the identity fields shared by installed and incoming manifests. */
128
+ export function parsePackIdentity(value: {
129
+ id?: unknown;
130
+ version?: unknown;
131
+ effect?: unknown;
132
+ }): { id: string; version: string; effect: PolicyEffect } {
133
+ if (typeof value.id !== "string" || !PACK_ID_RE.test(value.id)) {
134
+ throw new Error(`unsafe pack id ${JSON.stringify(value.id)}`);
135
+ }
136
+ if (typeof value.version !== "string" || !PACK_VERSION_RE.test(value.version)) {
137
+ throw new Error(`invalid version for pack ${value.id}`);
138
+ }
139
+ if (value.effect !== undefined && value.effect !== "enforce" && value.effect !== "observe") {
140
+ throw new Error(`unknown effect ${JSON.stringify(value.effect)} for pack ${value.id}`);
141
+ }
142
+ return {
143
+ id: value.id,
144
+ version: value.version,
145
+ effect: (value.effect as PolicyEffect | undefined) ?? "enforce",
146
+ };
147
+ }
148
+
149
+ /**
150
+ * Whether this machine has any pack installed at all.
151
+ *
152
+ * Cheap on purpose — the hook path asks this on every event to decide whether it
153
+ * still needs the migration shim, and reading + verifying every artifact digest
154
+ * to answer "is there one" would be the wrong price.
155
+ */
156
+ export function hasInstalledPacks(): boolean {
157
+ try {
158
+ const raw = JSON.parse(readFileSync(installedFilePath(), "utf8")) as { packs?: unknown };
159
+ return Array.isArray(raw.packs) && raw.packs.length > 0;
160
+ } catch {
161
+ return false;
162
+ }
163
+ }
164
+
165
+ function installedFilePath(): string {
166
+ return process.env.FAILPROOFAI_PACK_DIR
167
+ ? resolve(process.env.FAILPROOFAI_PACK_DIR, "installed.json")
168
+ : packsInstalledFile();
169
+ }
170
+
171
+ /** Validate one serialized catalog entry carried by a pack. */
172
+ export function parsePackPolicy(packId: string, value: unknown, index: number): PolicyCatalogEntry {
173
+ const where = `${packId} policy #${index}`;
174
+ if (!value || typeof value !== "object") throw new Error(`${where} is not an object`);
175
+ const raw = value as Record<string, unknown>;
176
+
177
+ const name = raw.name;
178
+ if (typeof name !== "string" || !PACK_POLICY_NAME_RE.test(name)) {
179
+ throw new Error(`${where} has an unsafe name ${JSON.stringify(name)}`);
180
+ }
181
+ if ("alwaysOn" in raw) {
182
+ // `alwaysOn` means "registers regardless of the enabled set, and cannot be
183
+ // disabled or paused". It is reserved for the guard that stops an agent
184
+ // switching failproofai off, which ships compiled in. A pack granting it to
185
+ // itself would be a downloaded file that no local command can turn off.
186
+ throw new Error(`${where} declares alwaysOn, which packs may not set`);
187
+ }
188
+ if (typeof raw.description !== "string" || raw.description.length === 0) {
189
+ throw new Error(`${where} is missing a description`);
190
+ }
191
+ if (typeof raw.category !== "string" || raw.category.length === 0) {
192
+ throw new Error(`${where} is missing a category`);
193
+ }
194
+ if (typeof raw.defaultEnabled !== "boolean") {
195
+ throw new Error(`${where} is missing defaultEnabled`);
196
+ }
197
+ if (!raw.match || typeof raw.match !== "object") {
198
+ throw new Error(`${where} is missing a match`);
199
+ }
200
+ return raw as unknown as PolicyCatalogEntry;
201
+ }
202
+
203
+ function parsePack(root: string, value: unknown): ResolvedPack {
204
+ if (!value || typeof value !== "object") throw new Error("pack entry is not an object");
205
+ const raw = value as InstalledPackRecord;
206
+
207
+ const identity = parsePackIdentity(raw);
208
+ if (typeof raw.source !== "string" || raw.source.length === 0) {
209
+ throw new Error(`pack ${raw.id} has no source`);
210
+ }
211
+ if (typeof raw.sha256 !== "string" || !SHA256_RE.test(raw.sha256)) {
212
+ throw new Error(`invalid SHA-256 for pack ${raw.id}`);
213
+ }
214
+ // Recorded before anything that can fail, so a later throw can still say what
215
+ // this pack was for.
216
+ const effect = identity.effect;
217
+
218
+ const path = resolveManagedPath(root, raw.entry);
219
+ const actual = createHash("sha256").update(readFileSync(path)).digest("hex");
220
+ if (actual !== raw.sha256) {
221
+ throw new Error(
222
+ `pack ${raw.id} failed integrity verification: expected ${raw.sha256}, got ${actual}`,
223
+ );
224
+ }
225
+
226
+ if (!Array.isArray(raw.policies)) throw new Error(`pack ${raw.id} policies is not an array`);
227
+ const policies = raw.policies.map((p, i) => parsePackPolicy(raw.id, p, i));
228
+ const names = new Set<string>();
229
+ for (const p of policies) {
230
+ if (names.has(p.name)) throw new Error(`pack ${raw.id} declares ${p.name} twice`);
231
+ names.add(p.name);
232
+ }
233
+
234
+ let enabled: string[] | null = null;
235
+ if (raw.enabled !== undefined) {
236
+ if (!Array.isArray(raw.enabled) || raw.enabled.some((n) => typeof n !== "string")) {
237
+ throw new Error(`pack ${raw.id} enabled is not an array of names`);
238
+ }
239
+ // A name here that the pack no longer declares is not an error — a publisher
240
+ // may have removed a policy between versions — but it must not silently
241
+ // become "select nothing", so unknown names are simply dropped.
242
+ enabled = raw.enabled.filter((n) => names.has(n));
243
+ }
244
+
245
+ return {
246
+ id: identity.id,
247
+ version: identity.version,
248
+ source: raw.source,
249
+ path,
250
+ sha256: raw.sha256,
251
+ effect,
252
+ policies,
253
+ enabled,
254
+ };
255
+ }
256
+
257
+ /**
258
+ * Read every installed pack, verifying each artifact's digest immediately before
259
+ * its path is handed to a caller that will import it.
260
+ *
261
+ * Never throws. A pack that fails any check is omitted and recorded in `errors`;
262
+ * a manifest that cannot be read at all yields no packs and one error.
263
+ */
264
+ export function readInstalledPacks(): PackReadResult {
265
+ const manifestPath = installedFilePath();
266
+ if (!existsSync(manifestPath)) return { packs: [], errors: [] };
267
+
268
+ let raw: unknown;
269
+ try {
270
+ raw = JSON.parse(readFileSync(manifestPath, "utf8"));
271
+ } catch (err) {
272
+ return {
273
+ packs: [],
274
+ errors: [{ id: null, reason: `unreadable pack manifest: ${errText(err)}` }],
275
+ };
276
+ }
277
+ if (!raw || typeof raw !== "object") {
278
+ return { packs: [], errors: [{ id: null, reason: "pack manifest is not an object" }] };
279
+ }
280
+ const manifest = raw as { schemaVersion?: unknown; packs?: unknown };
281
+ if (!ACCEPTED_PACK_SCHEMA_VERSIONS.includes(manifest.schemaVersion as number)) {
282
+ return {
283
+ packs: [],
284
+ errors: [
285
+ {
286
+ id: null,
287
+ reason:
288
+ `unsupported pack manifest schema ${String(manifest.schemaVersion)} ` +
289
+ `(supported: ${ACCEPTED_PACK_SCHEMA_VERSIONS.join(", ")})`,
290
+ },
291
+ ],
292
+ };
293
+ }
294
+ if (!Array.isArray(manifest.packs)) {
295
+ return { packs: [], errors: [{ id: null, reason: "pack manifest packs is not an array" }] };
296
+ }
297
+
298
+ const root = packsRoot();
299
+ const packs: ResolvedPack[] = [];
300
+ const errors: PackError[] = [];
301
+ const seen = new Set<string>();
302
+
303
+ for (const entry of manifest.packs) {
304
+ const declaredId =
305
+ entry && typeof entry === "object" && typeof (entry as InstalledPackRecord).id === "string"
306
+ ? (entry as InstalledPackRecord).id
307
+ : null;
308
+ try {
309
+ const pack = parsePack(root, entry);
310
+ if (seen.has(pack.id)) throw new Error(`duplicate pack id ${pack.id}`);
311
+ seen.add(pack.id);
312
+ packs.push(pack);
313
+ } catch (err) {
314
+ const rec = entry as InstalledPackRecord | null;
315
+ const declaredEffect =
316
+ rec && (rec.effect === "observe" || rec.effect === "enforce") ? rec.effect : "enforce";
317
+ errors.push({
318
+ id: declaredId,
319
+ reason: errText(err),
320
+ effect: declaredEffect,
321
+ // Best effort: an entry too malformed to list policies yields nothing
322
+ // here, and a deny built from it is unavoidably blanket.
323
+ ...(Array.isArray(rec?.policies) ? { declared: safeDeclared(rec.policies) } : {}),
324
+ });
325
+ }
326
+ }
327
+ return { packs, errors };
328
+ }
329
+
330
+ /** Policy entries that at least carry a name and a match, for narrowing a deny. */
331
+ function safeDeclared(raw: unknown[]): PolicyCatalogEntry[] {
332
+ const out: PolicyCatalogEntry[] = [];
333
+ for (const value of raw) {
334
+ if (!value || typeof value !== "object") continue;
335
+ const p = value as Record<string, unknown>;
336
+ if (typeof p.name !== "string" || !p.match || typeof p.match !== "object") continue;
337
+ out.push(p as unknown as PolicyCatalogEntry);
338
+ }
339
+ return out;
340
+ }
341
+
342
+ function errText(err: unknown): string {
343
+ return err instanceof Error ? err.message : String(err);
344
+ }