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
@@ -44,6 +44,24 @@ const MAX_ATTEMPTS =
44
44
  ? parsedMaxAttempts
45
45
  : 3;
46
46
 
47
+ // How far past the source an output may run before a max_tokens stop reads as a
48
+ // repetition loop rather than a large page. Translations of the verbose targets
49
+ // (hi, vi, ja) sit near 2x the source's token estimate; 6x is far outside that
50
+ // band and was ~16x in the observed failure.
51
+ // Validated the same way MAX_TOKENS and MAX_ATTEMPTS above are, and for a
52
+ // sharper reason: `parseInt(...) || 6` accepts a NEGATIVE, and a negative ratio
53
+ // makes `output > source * ratio` true for every response — so a genuinely
54
+ // oversized page would be classified as a runaway and burn all three attempts
55
+ // to arrive exactly where it started.
56
+ const parsedRunawayRatio = Number.parseInt(
57
+ process.env.TRANSLATE_RUNAWAY_RATIO ?? "",
58
+ 10,
59
+ );
60
+ const RUNAWAY_RATIO =
61
+ Number.isInteger(parsedRunawayRatio) && parsedRunawayRatio > 0
62
+ ? parsedRunawayRatio
63
+ : 6;
64
+
47
65
  function getClient(): Anthropic {
48
66
  if (!client) {
49
67
  // Default 5 retries (up from SDK default of 2) so transient
@@ -151,10 +169,32 @@ export async function translateContent(
151
169
  // consolidate publish step. If a page ever legitimately needs more than
152
170
  // MAX_TOKENS, raise TRANSLATE_MAX_TOKENS or split the source.
153
171
  if (response.stop_reason === "max_tokens") {
154
- throw new Error(
172
+ // TWO different failures wear this stop_reason, and only one of them is
173
+ // "the page is too big". A 16 KB source whose Vietnamese translation
174
+ // emitted 64 000 output tokens — observed on the box, 2026-08-18,
175
+ // reference/cloud-cli.mdx [vi] — is a DEGENERATE SAMPLE: the model fell
176
+ // into a repetition loop. Resampling fixes that; splitting the source does
177
+ // not, and treating it as a size problem sent one page's hiccup on to fail
178
+ // the whole nightly run.
179
+ //
180
+ // The tell is the ratio. Source bytes / 4 is a rough token count, and a
181
+ // faithful translation lands within a small multiple of it — even for the
182
+ // verbose target languages. Far beyond that is the model talking to
183
+ // itself, so the error is marked RETRYABLE and translateValidated spends
184
+ // an attempt on it. A source that genuinely approaches the ceiling keeps
185
+ // the old fail-loud behaviour, because retrying it would burn the budget
186
+ // three times to reach the same place.
187
+ const sourceTokensApprox = Math.max(1, Math.ceil(content.length / 4));
188
+ const runaway = response.usage.output_tokens > sourceTokensApprox * RUNAWAY_RATIO;
189
+ const err = new Error(
155
190
  `translation truncated at max_tokens=${MAX_TOKENS} ` +
156
- `(output ${response.usage.output_tokens} tokens) source too large to translate in one request`,
191
+ `(output ${response.usage.output_tokens} tokens, source ~${sourceTokensApprox}) ` +
192
+ (runaway
193
+ ? "output dwarfs the source, which is a runaway sample rather than an oversized page"
194
+ : "source too large to translate in one request"),
157
195
  );
196
+ (err as Error & { retryable?: boolean }).retryable = runaway;
197
+ throw err;
158
198
  }
159
199
 
160
200
  const translated =
@@ -211,15 +251,30 @@ export async function translateValidated(opts: {
211
251
  ? { attempt, maxAttempts: MAX_ATTEMPTS, error: lastError }
212
252
  : undefined;
213
253
 
214
- // No try/catch: a transport/auth/max_tokens throw is not a validity
215
- // failure let it propagate so it is never silently retried as one.
216
- const result = await translateContent(
217
- opts.source,
218
- opts.lang,
219
- opts.langName,
220
- opts.model,
221
- feedback,
222
- );
254
+ // Transport/auth throws still propagate untouched — they are not validity
255
+ // failures and must never be silently retried as one. The ONE exception is
256
+ // a truncation flagged `retryable` (a runaway sample, see translateContent):
257
+ // that is a bad draw, and a bad draw is exactly what this loop is for.
258
+ let result: Awaited<ReturnType<typeof translateContent>>;
259
+ try {
260
+ result = await translateContent(
261
+ opts.source,
262
+ opts.lang,
263
+ opts.langName,
264
+ opts.model,
265
+ feedback,
266
+ );
267
+ } catch (e) {
268
+ const err = e as Error & { retryable?: boolean };
269
+ if (!err.retryable || attempt === MAX_ATTEMPTS) throw err;
270
+ lastError =
271
+ "The previous attempt ran past the output limit by repeating itself. " +
272
+ "Translate the document once, completely, and stop.";
273
+ console.warn(
274
+ ` ${opts.label} -> attempt ${attempt}/${MAX_ATTEMPTS} overran the output limit; retrying`,
275
+ );
276
+ continue;
277
+ }
223
278
  inputTokens += result.inputTokens;
224
279
  outputTokens += result.outputTokens;
225
280
 
@@ -13,6 +13,7 @@ import { createHash } from "node:crypto";
13
13
  import { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync } from "node:fs";
14
14
  import { join } from "node:path";
15
15
  import { BUILTIN_POLICIES } from "../hooks/builtin-policies";
16
+ import { readInstalledPacks } from "../hooks/pack-manifest";
16
17
  import { AUDIT_DETECTORS } from "./detectors";
17
18
  import type { TranscriptAuditResult } from "./types";
18
19
  import { auditCacheDir } from "../hooks/fp-home";
@@ -20,14 +21,43 @@ import { auditCacheDir } from "../hooks/fp-home";
20
21
  let cachedEngineVersion: string | null = null;
21
22
  let cachedDetectorVersion: string | null = null;
22
23
 
23
- /** Hash of every builtin policy's name + function body. Changes when policy
24
- * code changes, invalidating downstream caches. */
24
+ /**
25
+ * Hash of every builtin policy's name + function body, PLUS the identity of every
26
+ * installed pack. Changes when policy code changes, invalidating downstream
27
+ * caches.
28
+ *
29
+ * Packs belong in this key because they change what a machine would have caught,
30
+ * which is exactly what a cached audit result claims to know. They are folded in
31
+ * by `id|version|sha256` rather than by source text: the pack's bytes are already
32
+ * digest-pinned, and hashing the loaded source instead would drag in the
33
+ * per-load temporary filename the loader rewrites into every import specifier —
34
+ * which changes on every single run and would cold-rescan the whole history each
35
+ * time.
36
+ *
37
+ * **A machine with no packs must hash byte-identically to a build with no pack
38
+ * support at all.** Otherwise merely shipping this feature invalidates every
39
+ * user's audit cache and forces a ~104-second cold rescan on upgrade, for a
40
+ * capability they are not using. Hence the empty pack set contributes nothing —
41
+ * not an empty line, not a separator.
42
+ */
25
43
  function getEngineVersion(): string {
26
44
  if (cachedEngineVersion) return cachedEngineVersion;
27
- const blob = BUILTIN_POLICIES
45
+ const builtinBlob = BUILTIN_POLICIES
28
46
  .map((p) => `${p.name}|${p.fn.toString()}`)
29
47
  .sort()
30
48
  .join("\n");
49
+ // Never throws by contract, but this runs inside the audit's own try/catch-free
50
+ // path and a cache key is not worth taking the run down for.
51
+ let packBlob = "";
52
+ try {
53
+ packBlob = readInstalledPacks()
54
+ .packs.map((pack) => `${pack.id}|${pack.version}|${pack.sha256}`)
55
+ .sort()
56
+ .join("\n");
57
+ } catch {
58
+ packBlob = "";
59
+ }
60
+ const blob = packBlob ? `${builtinBlob}\n${packBlob}` : builtinBlob;
31
61
  cachedEngineVersion = createHash("sha1").update(blob).digest("hex").slice(0, 16);
32
62
  return cachedEngineVersion;
33
63
  }
@@ -43,6 +73,13 @@ function getDetectorVersion(): string {
43
73
  return cachedDetectorVersion;
44
74
  }
45
75
 
76
+ /** Exposed for `engine-version-packs.test.ts`, which pins the upgrade-cost
77
+ * guarantee: a machine with no packs must hash exactly as it did before packs
78
+ * existed. Nothing else should call this. */
79
+ export function getEngineVersionForTest(): string {
80
+ return getEngineVersion();
81
+ }
82
+
46
83
  function getCachePathFor(transcriptPath: string): string {
47
84
  const root = auditCacheDir();
48
85
  const key = createHash("sha1").update(transcriptPath).digest("hex");
package/src/audit/cli.ts CHANGED
@@ -58,7 +58,7 @@ export const EXIT_AUDIT_ALREADY_RUNNING = 75;
58
58
  export const AUDIT_STAGES: ReadonlyArray<{ label: string; detail: string }> = [
59
59
  { label: "discovering transcripts", detail: "walking ~/.claude, ~/.codex, ~/.cursor, …" },
60
60
  { label: "parsing session logs", detail: "reading JSONL + sqlite session stores" },
61
- { label: "running policy checks", detail: "replaying through 30 builtin policies" },
61
+ { label: "running policy checks", detail: "replaying every policy against each tool call" },
62
62
  { label: "aggregating results", detail: "counting hits, ranking by frequency" },
63
63
  ];
64
64
 
@@ -261,7 +261,7 @@ function aggregateResults(
261
261
 
262
262
  export async function runAudit(opts: RunAuditOptions = {}): Promise<AuditResult> {
263
263
  const startedAt = Date.now();
264
- initReplay();
264
+ await initReplay();
265
265
  try {
266
266
  return await runAuditInner(opts, startedAt);
267
267
  } finally {
@@ -13,13 +13,19 @@
13
13
  * execSync against live git, so they never fire on PreToolUse/PostToolUse
14
14
  * replay — no explicit skip needed.
15
15
  */
16
+ import { resolve } from "node:path";
17
+ import { existsSync } from "node:fs";
16
18
  import type { EvaluationResult } from "../hooks/policy-evaluator";
17
19
  import { evaluatePolicies } from "../hooks/policy-evaluator";
18
20
  import { BUILTIN_POLICIES, registerBuiltinPolicies } from "../hooks/builtin-policies";
21
+ import { PACK_ENTRY_ASSET, bundledPackDir } from "../hooks/pack-store";
22
+ import { loadCustomHooks } from "../hooks/custom-hooks-loader";
23
+ import { clearCustomHooks } from "../hooks/custom-hooks-registry";
19
24
  import {
20
25
  clearPolicies,
21
26
  getAllPolicies,
22
27
  normalizePolicyName,
28
+ registerPolicy,
23
29
  setAllPolicies,
24
30
  } from "../hooks/policy-registry";
25
31
  import type { RegisteredPolicy } from "../hooks/policy-types";
@@ -44,17 +50,97 @@ let savedSnapshot: RegisteredPolicy[] | null = null;
44
50
  * shows what *could* be caught, not just what's currently enabled. Called
45
51
  * once per `runAudit` invocation. Snapshots the existing registry so it can
46
52
  * be restored by `restoreReplay()` once the audit is done. */
47
- export function initReplay(): void {
53
+ export async function initReplay(): Promise<void> {
48
54
  if (initialized) return;
49
55
  savedSnapshot = getAllPolicies();
50
56
  clearPolicies();
51
57
  const enabled = BUILTIN_POLICIES
52
58
  .map((p) => p.name)
53
59
  .filter((n) => !SKIP_POLICIES.has(normalizePolicyName(n)));
54
- registerBuiltinPolicies(enabled);
60
+ if (!(await registerFromVendoredPack(enabled))) registerBuiltinPolicies(enabled);
55
61
  initialized = true;
56
62
  }
57
63
 
64
+ /**
65
+ * Register the audit's policies from the pack that ships inside the package,
66
+ * rather than from implementations compiled into this build.
67
+ *
68
+ * The audit scores by RUNNING the policies — three of its four penalty buckets
69
+ * are replay hits — so the day the builtins stop being compiled in, this is
70
+ * what keeps `failproofai audit` reporting the same findings and the same score
71
+ * for the same transcripts. The pack carries the identical functions:
72
+ * `builtin-pack-conformance.test.ts` replays a corpus through both and asserts
73
+ * the verdicts do not diverge.
74
+ *
75
+ * Two things it must get right, or the audit quietly changes:
76
+ *
77
+ * - The pack cannot carry `block-failproofai-commands`, because `alwaysOn` is
78
+ * refused by the pack loader by design — a downloaded file that no local
79
+ * command can switch off. It is registered from the compiled side, so the
80
+ * replayed set is the same 39 either way.
81
+ * - The skip list still applies. `warn-repeated-tool-calls` writes a per-session
82
+ * sidecar into the user's real transcript directory on every evaluation.
83
+ *
84
+ * Returns false when there is no vendored pack to read — a source checkout that
85
+ * has not run `build:pack`, or a tarball packed without it — and the caller
86
+ * falls back to the compiled implementations. An audit that silently scored on
87
+ * fewer policies would be worse than either.
88
+ */
89
+ async function registerFromVendoredPack(enabled: string[]): Promise<boolean> {
90
+ const dir = bundledPackDir();
91
+ if (!dir) return false;
92
+ const entry = resolve(dir, PACK_ENTRY_ASSET);
93
+ if (!existsSync(entry)) return false;
94
+
95
+ const wanted = new Set(enabled);
96
+ let hooks;
97
+ try {
98
+ clearCustomHooks();
99
+ hooks = await loadCustomHooks(entry, { strict: true });
100
+ } catch {
101
+ return false;
102
+ } finally {
103
+ clearCustomHooks();
104
+ }
105
+ if (hooks.length === 0) return false;
106
+ const fromPack = new Map(hooks.map((hook) => [hook.name, hook]));
107
+
108
+ // Registered in CATALOG ORDER, taking the pack's function where it has one and
109
+ // the compiled one for the guard the pack may not carry.
110
+ //
111
+ // Order is not cosmetic here. `getPoliciesForEvent` sorts by priority only and
112
+ // V8's sort is stable, so registration order decides EVALUATION order, and
113
+ // `evaluatePolicies` stops at the first deny — which means the order decides
114
+ // which policy is CREDITED for a hit. Appending the always-on guard after the
115
+ // pack instead of at its catalog position moved it from index 11 to last, and
116
+ // re-attributed 3 events in a 23,477-event corpus: 456 -> 453 for the guard,
117
+ // with the denies it used to shadow surfacing as block-force-push and
118
+ // block-gh-pipeline. The audit's per-policy counts are what a user reads, so
119
+ // that is a changed audit, not a changed internal.
120
+ let registered = 0;
121
+ for (const policy of BUILTIN_POLICIES) {
122
+ if (!wanted.has(policy.name)) continue;
123
+ const packHook = fromPack.get(policy.name);
124
+ if (policy.alwaysOn || !packHook) {
125
+ registerPolicy(policy.name, policy.description, policy.fn, policy.match, 0, policy.params);
126
+ continue;
127
+ }
128
+ registerPolicy(
129
+ packHook.name,
130
+ packHook.description ?? policy.description,
131
+ packHook.fn,
132
+ packHook.match ?? policy.match,
133
+ 0,
134
+ policy.params,
135
+ );
136
+ registered += 1;
137
+ }
138
+ // Nothing came from the pack: it loaded but carried none of the names the
139
+ // audit replays. Falling back is more honest than scoring on the compiled set
140
+ // while claiming the pack lane ran.
141
+ return registered > 0;
142
+ }
143
+
58
144
  /** Restore the registry to whatever was there before `initReplay()`. Safe to
59
145
  * call when not initialized (no-op). Always paired with `initReplay()` in a
60
146
  * try/finally inside `runAudit()`. */
@@ -87,7 +173,7 @@ export interface ReplayHit {
87
173
  * is reported too, so sanitize policies that emit informational notes still
88
174
  * surface in the audit. */
89
175
  export async function replayEvent(event: NormalizedToolEvent): Promise<ReplayHit[]> {
90
- if (!initialized) initReplay();
176
+ if (!initialized) await initReplay();
91
177
 
92
178
  const session: SessionMetadata = {
93
179
  sessionId: event.sessionId,
@@ -263,16 +263,16 @@ export function formatMarkdown(result: AuditResult): string {
263
263
  out.push("## TL;DR");
264
264
  out.push("");
265
265
  if (totalHits === 0) {
266
- out.push("Clean run — the AI coding agent didn't do anything `failproofai` catches in this window.");
266
+ out.push("Clean run — the agent didn't do anything `failproofai` catches in this window.");
267
267
  } else {
268
268
  out.push(
269
- `Over ${result.transcripts.scanned} sessions, my AI coding agent did **${totalHits} things \`failproofai\` would have stopped**: ` +
270
- `${totalProtected} were already blocked in real time by my current config; ` +
271
- `**${totalSlipping} slipped through** (would've been caught if more policies were on).`,
269
+ `Over ${result.transcripts.scanned} sessions, my agent did **${totalHits} things \`failproofai\` caught**: ` +
270
+ `${totalProtected} were blocked in real time by my current config; ` +
271
+ `**${totalSlipping} slipped through** and were only caught by the audit.`,
272
272
  );
273
273
  }
274
274
  out.push("");
275
- out.push("> [failproofai](https://github.com/FailproofAI/failproofai) is a hook-based policy engine for Claude Code, Codex, Copilot, Cursor, OpenCode, and Pi. The `audit` command replays past agent sessions through every builtin policy to surface patterns that were (or could've been) stopped.");
275
+ out.push("> [failproofai](https://github.com/FailproofAI/failproofai) is a hook-based policy engine for 12 agent harnesses coding CLIs, chat gateways, and self-hosted assistants. The `audit` command replays past agent sessions through every builtin policy to surface patterns that were (or could've been) stopped.");
276
276
  out.push("");
277
277
 
278
278
  if (totalHits === 0) return out.join("\n");
@@ -37,8 +37,13 @@ import {
37
37
  ANSI_RESET,
38
38
  brandAnsi,
39
39
  colorsEnabled,
40
+ optsFor,
40
41
  outro,
42
+ printBlock,
43
+ rows as kitRows,
44
+ stack,
41
45
  step,
46
+ title,
42
47
  } from "../hooks/tui";
43
48
 
44
49
  /** Mirrors `fp-config`'s own bounds so the error can name them before writing. */
@@ -62,30 +67,6 @@ const green = (s: string) => wrap(brandAnsi("guide"), s);
62
67
  const dim = (s: string) => wrap(ANSI_DIM, s);
63
68
  const bold = (s: string) => wrap(ANSI_BOLD, s);
64
69
 
65
- /**
66
- * The readout's left margin.
67
- *
68
- * Deliberately NOT the `│` spine the sign-in uses. A spine means "a flow is
69
- * happening, with a beginning and an end"; `--status` is a snapshot of a
70
- * machine, and hanging one off a frame that never opened reads as an unfinished
71
- * wizard. Alignment does the work here instead.
72
- */
73
- const rail = () => " ";
74
-
75
- /**
76
- * One labelled row of the `--status` readout.
77
- *
78
- * A fixed label column so the values line up into a second column that can be
79
- * read straight down — the whole point of this command is answering "what is
80
- * this machine doing" at a glance, and a ragged left edge makes four facts read
81
- * as four sentences.
82
- */
83
- const LABEL_WIDTH = 15;
84
- function row(label: string, value: string, note?: string): string {
85
- const gap = " ".repeat(Math.max(1, LABEL_WIDTH - label.length));
86
- return `${rail()} ${dim(label)}${gap}${value}${note ? ` ${dim(note)}` : ""}`;
87
- }
88
-
89
70
  /**
90
71
  * Turn scheduled audits on, signing in first if needed.
91
72
  *
@@ -219,62 +200,77 @@ export function runScheduleStatus(): void {
219
200
  const daemon = daemonServiceStatus();
220
201
 
221
202
  const on = config.audit.auto;
222
- const out: string[] = [""];
203
+ const opts = optsFor(process.stdout);
204
+ const detail: Array<[string, string]> = [];
223
205
 
224
- // The state first and alone, in the accent that matches it everything below
225
- // is detail about a machine that is either doing this or not, and reading the
226
- // detail first is reading the answer to a question nobody asked yet.
227
- out.push(
228
- `${rail()} ${bold("scheduled audit")} ${on ? green("on") : dim("off")}` +
229
- (on ? dim(` every ${config.audit.intervalDays} days`) : ""),
230
- );
231
- out.push(rail());
206
+ // The state first, because everything below is detail about a machine that is
207
+ // either doing this or not, and reading the detail first answers a question
208
+ // nobody has asked yet. It is a ROW like the rest, though: the headline used
209
+ // to be hand-padded to a different column than `row()` used, which is why this
210
+ // readout printed its first value at column 21 and every other at 18.
211
+ detail.push([
212
+ "scheduled audit",
213
+ on
214
+ ? `${green("on")}${dim(` every ${config.audit.intervalDays} days`)}`
215
+ : dim("off"),
216
+ ]);
232
217
 
233
218
  // A session whose refresh window has closed cannot mint another access token,
234
219
  // so it is a destination in name only. Showing the address for one would tell
235
220
  // somebody their digests are going somewhere they are not.
236
221
  const live = auth && auth.refresh_expires_at * 1000 > Date.now() ? auth : null;
237
- out.push(row("reports to", live ? live.user.email : dim("— signed out")));
222
+ detail.push(["reports to", live ? live.user.email : dim("— signed out")]);
238
223
  if (on && !live) {
239
224
  // The state the reporter surfaces as "signed-out". Named here for the same
240
225
  // reason the settings panel names it: the scans keep running, so silence
241
226
  // about the digests would look like the feature failing.
242
- out.push(row("", pink("scans continue; digests are paused until you sign in")));
227
+ detail.push(["", pink("scans continue; digests are paused until you sign in")]);
243
228
  } else if (on && config.audit.reportsConsentedAt === undefined) {
244
229
  // Signed in, scheduled, and still not sending: this machine set `audit.auto`
245
230
  // when it only meant "scan locally", so nothing has consented to the digest
246
231
  // leaving the box. Without this row the status screen would show a healthy
247
232
  // schedule and a live address and still mail nothing, with no explanation
248
233
  // anywhere the user can see.
249
- out.push(
250
- row("", pink("scans continue; digests need a fresh opt-in — run `--schedule` to turn them on")),
251
- );
234
+ detail.push([
235
+ "",
236
+ pink("scans continue; digests need a fresh opt-in — run `--schedule` to turn them on"),
237
+ ]);
252
238
  }
253
239
 
254
- out.push(row("daemon", describeDaemon(daemon)));
240
+ detail.push(["daemon", describeDaemon(daemon)]);
255
241
 
256
242
  if (sched?.nextDueAtMs != null && on) {
257
- out.push(row("next scan", untilPhrase(sched.nextDueAtMs)));
243
+ detail.push(["next scan", untilPhrase(sched.nextDueAtMs)]);
258
244
  }
259
245
  if (sched?.lastRunAtMs != null) {
260
246
  const exit = sched.lastExitCode;
261
- out.push(
262
- row(
263
- "last scheduled",
264
- agoPhrase(sched.lastRunAtMs),
265
- exit != null && exit !== 0 && exit !== 75 ? pink(`exit ${exit}`) : undefined,
266
- ),
267
- );
247
+ const failed = exit != null && exit !== 0 && exit !== 75;
248
+ detail.push([
249
+ "last scheduled",
250
+ agoPhrase(sched.lastRunAtMs) + (failed ? ` ${pink(`exit ${exit}`)}` : ""),
251
+ ]);
268
252
  }
269
- out.push(
270
- row("last result", meta?.cachedAt ? agoPhrase(Date.parse(meta.cachedAt)) : dim("none yet")),
271
- );
253
+ detail.push([
254
+ "last result",
255
+ meta?.cachedAt ? agoPhrase(Date.parse(meta.cachedAt)) : dim("none yet"),
256
+ ]);
272
257
  if (machine?.last_reported_at) {
273
- out.push(row("last reported", agoPhrase(Date.parse(machine.last_reported_at))));
258
+ detail.push(["last reported", agoPhrase(Date.parse(machine.last_reported_at))]);
274
259
  }
275
- out.push("");
276
260
 
277
- process.stdout.write(out.join("\n"));
261
+ printBlock(
262
+ process.stdout,
263
+ stack(
264
+ // The meta carries a fact, not the word "status" — a heading that repeats
265
+ // the command name tells the reader nothing they did not just type.
266
+ title(
267
+ "failproofai audit",
268
+ on ? `scheduled · every ${config.audit.intervalDays} days` : "not scheduled",
269
+ opts,
270
+ ),
271
+ kitRows(detail, opts),
272
+ ),
273
+ );
278
274
  }
279
275
 
280
276
  function describeDaemon(status: ReturnType<typeof daemonServiceStatus>): string {