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,121 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Emit the builtin policies AS a policy pack.
4
+ *
5
+ * This is the dress rehearsal for builtins leaving the npm package. It produces
6
+ * exactly what a third-party publisher would upload to a GitHub release — a
7
+ * manifest, ONE bundled entry artifact, and a SHA256SUMS — so the same lane that
8
+ * loads a stranger's pack can be pointed at ours and proved to produce identical
9
+ * enforcement.
10
+ *
11
+ * Nothing on the hook path reads the output. `builtin-pack-conformance.test.ts`
12
+ * loads it into a scratch registry and compares. That is the point: it turns the
13
+ * eventual switch-over into a comparison someone already ran, rather than a leap.
14
+ *
15
+ * ## Two things it deliberately does
16
+ *
17
+ * **One file.** Transitive local imports are rewritten by the loader with no
18
+ * integrity check of their own — only the ENTRY is content-addressed — so a
19
+ * multi-file pack could not honestly claim to be digest-pinned. Bundling is what
20
+ * makes the digest mean what it says.
21
+ *
22
+ * ## Runs under bun, not node
23
+ *
24
+ * It imports `policy-catalog.ts` directly for the manifest. Node cannot resolve
25
+ * an extensionless TypeScript specifier at all before 22, and this repo targets
26
+ * node >= 20.9 — on 22 it "works" while printing a reparse warning, which is the
27
+ * worst of both: green here, broken on a supported version. bun reads TS
28
+ * natively, and every other build step in this repo is already bun.
29
+ *
30
+ * **It omits the `alwaysOn` policy.** `block-failproofai-commands` is the guard
31
+ * that stops an agent disabling failproofai, it ships compiled in, and
32
+ * `pack-manifest.ts` REFUSES any pack that declares `alwaysOn`. A pack containing
33
+ * it would be rejected by our own loader — correctly.
34
+ */
35
+ import { execFileSync } from "node:child_process";
36
+ import { createHash } from "node:crypto";
37
+ import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
38
+ import { dirname, join, resolve } from "node:path";
39
+ import { fileURLToPath } from "node:url";
40
+
41
+ const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
42
+ // `--out <dir>` lets the conformance test generate into a temp directory rather
43
+ // than depending on a build step having run first — the unit suite and the build
44
+ // are separate CI jobs, so a test that assumed `policy-pack/` existed would be
45
+ // green locally and skipped-or-broken in CI.
46
+ const outArg = process.argv.indexOf("--out");
47
+ const OUT_DIR = outArg !== -1 && process.argv[outArg + 1]
48
+ ? resolve(process.argv[outArg + 1])
49
+ : join(ROOT, "policy-pack");
50
+ // Not `failproofai/builtins`. These stop being builtins the moment they ship as
51
+ // a pack, and an id is the most durable place a retired word can hide — it ends
52
+ // up in every machine's installed.json and in the listing every user reads.
53
+ const PACK_ID = "failproofai/core";
54
+ const ENTRY_ASSET = "failproofai-pack.mjs";
55
+ const MANIFEST_ASSET = "failproofai-pack.json";
56
+ const CHECKSUMS_ASSET = "SHA256SUMS";
57
+
58
+ const version = JSON.parse(readFileSync(join(ROOT, "package.json"), "utf8")).version;
59
+
60
+ // A generated entry that registers every non-alwaysOn builtin through the public
61
+ // policy API — the same API a third-party pack uses. `failproofai` stays external
62
+ // so the loader's shim resolves it, exactly as it does for any other pack.
63
+ const entrySource = `
64
+ import { customPolicies } from "failproofai";
65
+ import { BUILTIN_POLICIES } from ${JSON.stringify(join(ROOT, "src/hooks/builtin-policies.ts"))};
66
+
67
+ for (const policy of BUILTIN_POLICIES) {
68
+ if (policy.alwaysOn) continue;
69
+ customPolicies.add({
70
+ name: policy.name,
71
+ description: policy.description,
72
+ match: policy.match,
73
+ fn: policy.fn,
74
+ });
75
+ }
76
+ `;
77
+
78
+ rmSync(OUT_DIR, { recursive: true, force: true });
79
+ mkdirSync(OUT_DIR, { recursive: true });
80
+
81
+ const tempEntry = join(OUT_DIR, ".entry.generated.ts");
82
+ writeFileSync(tempEntry, entrySource, "utf8");
83
+ try {
84
+ execFileSync(
85
+ "bun",
86
+ ["build", "--target=node", "--format=esm", "--external", "failproofai",
87
+ "--outfile", join(OUT_DIR, ENTRY_ASSET), tempEntry],
88
+ { cwd: ROOT, stdio: ["pipe", "pipe", "inherit"] },
89
+ );
90
+ } finally {
91
+ rmSync(tempEntry, { force: true });
92
+ }
93
+
94
+ // The manifest's policy list comes from the CATALOG, never from the bundle —
95
+ // which is the whole reason the catalog is pure literal data. `pack add`
96
+ // validates these with the loader's own rules, so a shape the loader would
97
+ // refuse fails this build rather than shipping.
98
+ const { POLICY_CATALOG } = await import(join(ROOT, "src/hooks/policy-catalog.ts"));
99
+ const policies = POLICY_CATALOG.filter((p) => !p.alwaysOn).map((p) => ({ ...p }));
100
+
101
+ const manifest = JSON.stringify(
102
+ { id: PACK_ID, version, effect: "enforce", policies },
103
+ null,
104
+ 2,
105
+ ) + "\n";
106
+ writeFileSync(join(OUT_DIR, MANIFEST_ASSET), manifest, "utf8");
107
+
108
+ const sha = (bytes) => createHash("sha256").update(bytes).digest("hex");
109
+ const entryBytes = readFileSync(join(OUT_DIR, ENTRY_ASSET));
110
+ writeFileSync(
111
+ join(OUT_DIR, CHECKSUMS_ASSET),
112
+ `${sha(Buffer.from(manifest))} ${MANIFEST_ASSET}\n${sha(entryBytes)} ${ENTRY_ASSET}\n`,
113
+ "utf8",
114
+ );
115
+
116
+ const omitted = POLICY_CATALOG.filter((p) => p.alwaysOn).map((p) => p.name);
117
+ console.log(
118
+ `[policy-pack] ${PACK_ID}@${version} — ${policies.length} policies, ` +
119
+ `${(entryBytes.length / 1024).toFixed(1)} KB entry` +
120
+ (omitted.length ? `; omitted alwaysOn: ${omitted.join(", ")}` : ""),
121
+ );
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env python3
2
+ """Print one version's section out of a CHANGELOG, for a GitHub Release body.
3
+
4
+ changelog-section.py <changelog> <version>
5
+
6
+ Both PyPI publish workflows call this from `preflight` — BEFORE anything is built
7
+ and long before anything is uploaded — so a release with no notes fails at the one
8
+ point in the pipeline where failing is free. It cannot be fixed afterwards: PyPI
9
+ never releases a version for reuse, so "publish it again, with notes this time" is
10
+ not an available remedy, and the GitHub Release would stand empty against a
11
+ version that is permanently on the index.
12
+
13
+ The heading grammar is the one CLAUDE.md fixes for the root changelog and which
14
+ the per-package files follow:
15
+
16
+ ## 0.0.1b1 — 2026-08-24
17
+
18
+ The date is not parsed; only the version is matched, and it is matched with a
19
+ trailing word boundary so a request for `0.0.1b1` cannot be answered by
20
+ `0.0.1b10`'s section — which is a real hazard once a beta counter passes nine,
21
+ and one that would put the WRONG release's notes on a tag with no error anywhere.
22
+
23
+ Stdlib only, same reason as `python-version.py`: it runs in the job that holds no
24
+ publishing identity precisely because it installs nothing.
25
+ """
26
+
27
+ from __future__ import annotations
28
+
29
+ import re
30
+ import sys
31
+
32
+
33
+ class SectionError(Exception):
34
+ """A message a maintainer can act on, printed without a traceback."""
35
+
36
+
37
+ def extract(text: str, version: str) -> str:
38
+ """The body under `## <version>`, up to the next `## ` heading."""
39
+ heading = re.compile(rf"^##[ \t]+{re.escape(version)}\b.*$", re.MULTILINE)
40
+ match = heading.search(text)
41
+ if not match:
42
+ raise SectionError(
43
+ f"no '## {version}' section — add one before releasing, or the tag "
44
+ f"gets a release with nothing in it"
45
+ )
46
+
47
+ rest = text[match.end():]
48
+ nxt = re.search(r"^##[ \t]", rest, re.MULTILINE)
49
+ body = (rest[: nxt.start()] if nxt else rest).strip()
50
+
51
+ if not body:
52
+ # A heading with nothing under it is the same failure as no heading at
53
+ # all, and is what you get from stamping a version onto an empty section.
54
+ raise SectionError(f"the '## {version}' section is empty")
55
+ return body
56
+
57
+
58
+ def main(argv: list[str]) -> int:
59
+ if len(argv) < 3:
60
+ print(__doc__ or "", file=sys.stderr)
61
+ return 2
62
+ path, version = argv[1], argv[2]
63
+ try:
64
+ with open(path, encoding="utf-8") as handle:
65
+ text = handle.read()
66
+ except OSError as exc:
67
+ raise SectionError(f"cannot read {path}: {exc}") from exc
68
+ print(extract(text, version))
69
+ return 0
70
+
71
+
72
+ if __name__ == "__main__":
73
+ try:
74
+ raise SystemExit(main(sys.argv))
75
+ except SectionError as error:
76
+ print(f"error: {error}", file=sys.stderr)
77
+ raise SystemExit(1) from None
@@ -119,6 +119,9 @@ const STANDALONE_ROOT_PRUNE = [
119
119
  // plugin/extension dirs are shipped from the package root by `files`, not
120
120
  // from inside the standalone bundle.
121
121
  "integration-suite", "pi-extension", "openclaw-plugin", "docker-hook-sync",
122
+ // Generated by build:pack and shipped from the root by `files`, same as the
123
+ // two above — without this it lands in the tarball twice.
124
+ "policy-pack",
122
125
  ];
123
126
  const STANDALONE_ROOT_PRUNE_FILES = [
124
127
  // Top-level markdown / licenses / docs
@@ -0,0 +1,232 @@
1
+ #!/usr/bin/env python3
2
+ """Version arithmetic for the two Python packages, `fp-cloud-cli` and `failproofai-sdk`.
3
+
4
+ Both publish workflows call this; it is the ONE place the release scheme is written
5
+ down, so the two pipelines cannot drift into disagreeing about what comes next.
6
+
7
+ resolve <version-file> [<dist>] -> key=value lines for $GITHUB_OUTPUT
8
+ write <version-file> <version> -> rewrite __version__ in place
9
+
10
+ Given a dist name, `resolve` also emits the release tag: `<dist>-v<version>`, e.g.
11
+ `fp-cloud-cli-v0.0.1b1`. Namespaced rather than the bare `vX.Y.Z` the npm package uses,
12
+ because three release lines share one repository and one tag namespace — a bare
13
+ `v0.0.1b1` would read as a release of `failproofai` itself, and `gh release list`
14
+ would interleave all three with no way to tell them apart.
15
+
16
+ THE SCHEME. It mirrors `publish.yml`'s npm rule, spelled in PEP 440 rather than
17
+ semver, because PyPI has no dist-tags: there is no movable `beta` pointer to
18
+ publish behind, so the pre-release marker in the version string is the entire
19
+ channel mechanism.
20
+
21
+ beta X.Y.ZbN -> X.Y.Zb(N+1) another beta off the same base
22
+ stable X.Y.Z -> X.Y.(Z+1)b0 open the next patch's beta line
23
+
24
+ `b` and not `-beta.`: `0.1.0-beta.1` is not a PEP 440 version at all, and pip
25
+ would reject the sdist name. `b0` and not `b1` after a stable, because that is
26
+ what npm's rule does (`X.Y.(Z+1)-beta.0`) and a release scheme that differs
27
+ between two of this repo's registries for no reason is a scheme nobody can
28
+ recite from memory.
29
+
30
+ WHY NON-CANONICAL SPELLINGS ARE REJECTED RATHER THAN ACCEPTED. `0.0.01b1`,
31
+ `0.0.1b01`, `1.2.3-beta.1` and `v1.2.3` are all legal PEP 440 and all normalise to
32
+ something else on the way to PyPI — so the file would say one thing, the wheel
33
+ another, and preflight's "is this already published" check would ask PyPI about a
34
+ third. Every consumer here compares version STRINGS, so this module normalises and
35
+ refuses anything that is not already in its final form, naming what PyPI would have
36
+ turned it into.
37
+
38
+ Stdlib only, and deliberately: this runs in the preflight job, which is the one
39
+ job in those workflows that has no publishing identity precisely BECAUSE it runs
40
+ before anything is installed. A dependency here would put third-party code back
41
+ into it.
42
+ """
43
+
44
+ from __future__ import annotations
45
+
46
+ import re
47
+ import sys
48
+
49
+ # `__version__ = "..."` — matched, never exec'd. Importing the module would run
50
+ # whatever else the file grew, in a job that is about to be handed a token.
51
+ _ASSIGNMENT = re.compile(r"""(__version__\s*=\s*)(["'])([^"']+)(\2)""")
52
+
53
+ # The two shapes the scheme knows how to advance.
54
+ _STABLE = re.compile(r"^(\d+)\.(\d+)\.(\d+)$")
55
+ _BETA = re.compile(r"^(\d+)\.(\d+)\.(\d+)b(\d+)$")
56
+
57
+ # PEP 440's own pre-release spellings, and the canonical form each collapses to.
58
+ _PRE_LABELS = {
59
+ "alpha": "a",
60
+ "a": "a",
61
+ "beta": "b",
62
+ "b": "b",
63
+ "c": "rc",
64
+ "pre": "rc",
65
+ "preview": "rc",
66
+ "rc": "rc",
67
+ }
68
+
69
+ # PEP 440, verbatim from the spec's appendix. Used to normalise, and to tell "a
70
+ # version this scheme will not advance" (an rc, a .post, a .dev — publishable, no
71
+ # auto-bump) apart from "not a version at all" (a typo — refuse before a build).
72
+ _PEP440 = re.compile(
73
+ r"""^\s*v?
74
+ (?:(?P<epoch>[0-9]+)!)?
75
+ (?P<release>[0-9]+(?:\.[0-9]+)*)
76
+ (?P<pre>[-_.]?(?P<pre_l>alpha|a|beta|b|preview|pre|c|rc)[-_.]?(?P<pre_n>[0-9]+)?)?
77
+ (?P<post>(?:-(?P<post_n1>[0-9]+))|(?:[-_.]?(?P<post_l>post|rev|r)[-_.]?(?P<post_n2>[0-9]+)?))?
78
+ (?P<dev>[-_.]?dev[-_.]?(?P<dev_n>[0-9]+)?)?
79
+ (?:\+(?P<local>[a-z0-9]+(?:[-_.][a-z0-9]+)*))?
80
+ \s*$""",
81
+ re.VERBOSE | re.IGNORECASE,
82
+ )
83
+
84
+
85
+ class VersionError(Exception):
86
+ """A message a maintainer can act on, printed without a traceback."""
87
+
88
+
89
+ def read_version(path: str) -> str:
90
+ """The `__version__` literal in a `_version.py`, exactly as written."""
91
+ try:
92
+ with open(path, encoding="utf-8") as handle:
93
+ text = handle.read()
94
+ except OSError as exc:
95
+ raise VersionError(f"cannot read {path}: {exc}") from exc
96
+
97
+ found = _ASSIGNMENT.findall(text)
98
+ if not found:
99
+ raise VersionError(f"no __version__ assignment in {path}")
100
+ if len(found) > 1:
101
+ # Two assignments means the last one wins at import time and the first
102
+ # one is what a careless regex edit would rewrite. Refuse rather than
103
+ # guess which is live.
104
+ raise VersionError(f"{len(found)} __version__ assignments in {path}; expected exactly 1")
105
+ return found[0][2]
106
+
107
+
108
+ def normalize(version: str) -> str:
109
+ """The form PyPI will store, per PEP 440's normalisation rules."""
110
+ match = _PEP440.match(version)
111
+ if not match:
112
+ raise VersionError(f"'{version}' is not a valid PEP 440 version")
113
+
114
+ out = ""
115
+ epoch = match.group("epoch")
116
+ if epoch and int(epoch):
117
+ out += f"{int(epoch)}!"
118
+ out += ".".join(str(int(part)) for part in match.group("release").split("."))
119
+ if match.group("pre"):
120
+ out += _PRE_LABELS[match.group("pre_l").lower()] + str(int(match.group("pre_n") or 0))
121
+ if match.group("post"):
122
+ out += f".post{int(match.group('post_n1') or match.group('post_n2') or 0)}"
123
+ if match.group("dev"):
124
+ out += f".dev{int(match.group('dev_n') or 0)}"
125
+ local = match.group("local")
126
+ if local:
127
+ out += "+" + local.lower().replace("_", ".").replace("-", ".")
128
+ return out
129
+
130
+
131
+ def classify(version: str) -> tuple[str, str]:
132
+ """`(scheme, next_version)`. `next_version` is empty when the scheme cannot advance."""
133
+ canonical = normalize(version)
134
+ if canonical != version:
135
+ # Checked before the scheme, not inside it, so it also catches the shapes
136
+ # the scheme does not advance — `1.2.3-beta.1` publishes as `1.2.3b1`, and
137
+ # a preflight that asked PyPI about the former learned nothing about the
138
+ # version actually going up.
139
+ raise VersionError(
140
+ f"'{version}' is not canonical — PyPI would normalise it to '{canonical}', "
141
+ "so the file, the wheel and the published version would disagree"
142
+ )
143
+
144
+ match = _BETA.match(version)
145
+ if match:
146
+ major, minor, patch, beta = (int(g) for g in match.groups())
147
+ return "beta", f"{major}.{minor}.{patch}b{beta + 1}"
148
+
149
+ match = _STABLE.match(version)
150
+ if match:
151
+ major, minor, patch = (int(g) for g in match.groups())
152
+ return "stable", f"{major}.{minor}.{patch + 1}b0"
153
+
154
+ # Canonical, valid, and not one of the two shapes: an rc, a .post, a .dev, an
155
+ # epoch. PyPI takes it, so publishing is not blocked — but nothing here knows
156
+ # what should follow it, and inventing a successor is how a release line
157
+ # silently forks. The workflow warns and leaves main's version for a human.
158
+ return "other", ""
159
+
160
+
161
+ def is_prerelease(version: str) -> bool:
162
+ match = _PEP440.match(version)
163
+ if not match:
164
+ raise VersionError(f"'{version}' is not a valid PEP 440 version")
165
+ return bool(match.group("pre") or match.group("dev"))
166
+
167
+
168
+ #: Tag prefixes this repository already uses, and must not be confused with. The
169
+ #: npm package tags bare `vX.Y.Z`; a Python release tag must never be mistakable
170
+ #: for one, in `gh release list`, in the repo's release feed, or by the CLI, which
171
+ #: builds its daemon download URLs out of `v<version>` tags.
172
+ _RESERVED_TAG_PREFIX = "v"
173
+
174
+
175
+ def release_tag(dist: str, version: str) -> str:
176
+ tag = f"{dist}-v{version}"
177
+ if not dist or dist.startswith(_RESERVED_TAG_PREFIX) and dist[1:2].isdigit():
178
+ raise VersionError(f"dist name '{dist}' would produce a tag mistakable for an npm release tag")
179
+ return tag
180
+
181
+
182
+ def resolve(path: str, dist: str | None = None) -> str:
183
+ version = read_version(path)
184
+ scheme, following = classify(version)
185
+ lines = [
186
+ f"version={version}",
187
+ f"scheme={scheme}",
188
+ f"is_prerelease={'true' if is_prerelease(version) else 'false'}",
189
+ f"next_version={following}",
190
+ ]
191
+ if dist:
192
+ lines.append(f"tag={release_tag(dist, version)}")
193
+ return "\n".join(lines)
194
+
195
+
196
+ def write(path: str, version: str) -> str:
197
+ """Rewrite the literal in place, leaving every other byte of the file alone."""
198
+ scheme, _ = classify(version) # refuses a typo before it reaches a commit
199
+ if scheme == "other":
200
+ # `write` is only ever called with a version this module computed, so
201
+ # reaching here means someone wired it to an arbitrary string.
202
+ raise VersionError(f"'{version}' is outside the release scheme; set it by hand")
203
+
204
+ with open(path, encoding="utf-8") as handle:
205
+ text = handle.read()
206
+ replaced, count = _ASSIGNMENT.subn(
207
+ lambda m: f"{m.group(1)}{m.group(2)}{version}{m.group(4)}", text
208
+ )
209
+ if count != 1:
210
+ raise VersionError(f"expected exactly 1 __version__ assignment in {path}, found {count}")
211
+ with open(path, "w", encoding="utf-8") as handle:
212
+ handle.write(replaced)
213
+ return version
214
+
215
+
216
+ def main(argv: list[str]) -> int:
217
+ if len(argv) >= 3 and argv[1] == "resolve":
218
+ print(resolve(argv[2], argv[3] if len(argv) >= 4 else None))
219
+ return 0
220
+ if len(argv) >= 4 and argv[1] == "write":
221
+ print(write(argv[2], argv[3]))
222
+ return 0
223
+ print(__doc__ or "", file=sys.stderr)
224
+ return 2
225
+
226
+
227
+ if __name__ == "__main__":
228
+ try:
229
+ raise SystemExit(main(sys.argv))
230
+ except VersionError as error:
231
+ print(f"error: {error}", file=sys.stderr)
232
+ raise SystemExit(1) from None
@@ -39,6 +39,11 @@ const { values: args } = parseArgs({
39
39
  validate: { type: "boolean", default: false },
40
40
  prune: { type: "boolean", default: false },
41
41
  "no-prune": { type: "boolean", default: false },
42
+ // Publish what succeeded instead of discarding it. One page failing used to
43
+ // exit 1, which made the box job die before its push — on 2026-08-18 that
44
+ // threw away 782 good translations (2.7M tokens) because ONE page overran
45
+ // the output limit. Opt-in, so CI and hand runs keep failing loudly.
46
+ "allow-partial": { type: "boolean", default: false },
42
47
  model: { type: "string", short: "m" },
43
48
  help: { type: "boolean", short: "h", default: false },
44
49
  },
@@ -56,6 +61,8 @@ Options:
56
61
  --readme-only Only translate the README
57
62
  --docs-only Only translate Mintlify docs
58
63
  --dry-run Show what would be translated without calling the API
64
+ --allow-partial Exit 0 when SOME pages translated, listing the failures
65
+ (default: any failure exits 1 and publishes nothing)
59
66
  -f, --force Ignore cache, re-translate everything
60
67
  --update-nav Regenerate docs.json navigation after translation
61
68
  --validate Check all nav references resolve to files
@@ -441,6 +448,20 @@ async function main() {
441
448
  }
442
449
 
443
450
  if (errors.length > 0) {
451
+ // Printed either way — a partial run must never read as a clean one.
452
+ console.log(`\nFAILED PAGES (${errors.length}):`);
453
+ for (const e of errors) {
454
+ console.log(` ${e.source} [${e.lang}]: ${e.error}`);
455
+ }
456
+ if (args["allow-partial"] && translated.length > 0) {
457
+ // A stable marker the box job greps for, so the failure reaches Slack and
458
+ // the PR body instead of being buried in a 700-line log.
459
+ console.log(
460
+ `\nPARTIAL RUN — ${translated.length} page(s) translated, ${errors.length} failed. ` +
461
+ `Publishing what succeeded.`,
462
+ );
463
+ return;
464
+ }
444
465
  process.exit(1);
445
466
  }
446
467
  }
@@ -1,19 +1,29 @@
1
- import { readFileSync, writeFileSync } from "node:fs";
1
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { dirname, join } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { getLanguageByCode, NAV_TRANSLATIONS } from "./config";
5
5
 
6
6
  const __dirname = dirname(fileURLToPath(import.meta.url));
7
- const DOCS_JSON_PATH = join(__dirname, "..", "..", "docs", "docs.json");
7
+ const DOCS_DIR = join(__dirname, "..", "..", "docs");
8
+ const DOCS_JSON_PATH = join(DOCS_DIR, "docs.json");
8
9
 
9
10
  interface NavGroup {
10
11
  group: string;
11
- pages: string[];
12
+ // OPTIONAL, and both of these are why: a Mintlify group may carry `pages`, or
13
+ // nested `groups`, or neither — the docs rebuild introduced a group whose
14
+ // content is an `openapi` spec and has no pages at all. `pages` entries are
15
+ // likewise strings OR nested groups. Typing these as required is what let
16
+ // `group.pages.map` crash the nightly run.
17
+ pages?: (string | NavGroup)[];
18
+ groups?: NavGroup[];
19
+ // Everything else (expanded, icon, openapi, …) rides along untouched.
20
+ [key: string]: unknown;
12
21
  }
13
22
 
14
23
  interface NavTab {
15
24
  tab: string;
16
25
  groups: NavGroup[];
26
+ [key: string]: unknown;
17
27
  }
18
28
 
19
29
  interface LanguageNav {
@@ -76,9 +86,33 @@ export function getNavigationPageReferences(
76
86
  * Build a navigation entry for a specific language by transforming the
77
87
  * English navigation structure.
78
88
  */
89
+ /**
90
+ * Does the localized file for a nav entry exist on disk?
91
+ *
92
+ * Defaults to "yes" so the pure transform stays testable with fixtures, and the
93
+ * REAL check is injected by updateDocsJson / localizeProductsNavigation, which
94
+ * are the two paths that write docs.json.
95
+ */
96
+ export type PageExists = (relativePath: string) => boolean;
97
+
98
+ const fileOnDisk: PageExists = (rel) => existsSync(join(DOCS_DIR, rel));
99
+
100
+ /**
101
+ * Keep a group only if it still carries something to render. Dropping every
102
+ * missing page can empty a group, and an empty group is its own validation
103
+ * error — but a group whose content is an `openapi` spec has no pages by
104
+ * design and must survive.
105
+ */
106
+ function hasContent(group: NavGroup): boolean {
107
+ if (Array.isArray(group.pages) && group.pages.length > 0) return true;
108
+ if (Array.isArray(group.groups) && group.groups.length > 0) return true;
109
+ return !Array.isArray(group.pages) && !Array.isArray(group.groups);
110
+ }
111
+
79
112
  export function buildLanguageNav(
80
113
  englishTabs: NavTab[],
81
114
  lang: string,
115
+ exists: PageExists = () => true,
82
116
  ): LanguageNav {
83
117
  const t = NAV_TRANSLATIONS[lang];
84
118
  if (!t) throw new Error(`No nav translations for language: ${lang}`);
@@ -97,13 +131,47 @@ export function buildLanguageNav(
97
131
  Examples: t.examples,
98
132
  };
99
133
 
100
- const tabs: NavTab[] = englishTabs.map((tab) => ({
101
- tab: tabNameMap[tab.tab] || tab.tab,
102
- groups: tab.groups.map((group) => ({
103
- group: groupNameMap[group.group] || group.group,
104
- pages: group.pages.map((page) => `${lang}/${page}`),
105
- })),
106
- }));
134
+ // Rebuilt by SPREADING the English group, not by picking two fields off it.
135
+ // The old form silently dropped every other key — `expanded`, `icon`,
136
+ // `openapi` so a localized nav quietly lost them, and it crashed outright
137
+ // on the first group that had no `pages` at all.
138
+ const localizeGroup = (group: NavGroup): NavGroup => {
139
+ const out: NavGroup = { ...group, group: groupNameMap[group.group] || group.group };
140
+ if (Array.isArray(group.pages)) {
141
+ // A page entry is a path to prefix, or a nested group to recurse into.
142
+ //
143
+ // A path is DROPPED when its localized file is not on disk. The English
144
+ // tree is the source of the nav, so without this every English page gets
145
+ // an entry in all fourteen languages whether or not it was translated —
146
+ // and `mintlify validate` rejects the run. That took down a nightly job
147
+ // that had already translated 784 pages: one page failed, the nav still
148
+ // referenced it in that language, and every successful page was discarded
149
+ // with it. Omitting the entry is the honest state: the page does not
150
+ // exist in that language yet.
151
+ out.pages = group.pages
152
+ .map((page) =>
153
+ typeof page === "string" ? `${lang}/${page}` : localizeGroup(page),
154
+ )
155
+ .filter((page) =>
156
+ typeof page === "string" ? exists(`${page}.mdx`) : hasContent(page),
157
+ );
158
+ }
159
+ if (Array.isArray(group.groups)) {
160
+ out.groups = group.groups.map(localizeGroup).filter(hasContent);
161
+ }
162
+ // No pages and no groups (an `openapi` group): carried through as-is. The
163
+ // spec is not translated, and dropping the group would remove the API
164
+ // reference from every non-English nav.
165
+ return out;
166
+ };
167
+
168
+ const tabs: NavTab[] = englishTabs
169
+ .map((tab) => ({
170
+ ...tab,
171
+ tab: tabNameMap[tab.tab] || tab.tab,
172
+ groups: (tab.groups ?? []).map(localizeGroup).filter(hasContent),
173
+ }))
174
+ .filter((tab) => tab.groups.length > 0);
107
175
 
108
176
  return {
109
177
  language: getLanguageByCode(lang)?.mintlifyCode ?? lang,
@@ -125,10 +193,11 @@ export function readDocsConfig(): Record<string, unknown> {
125
193
  export function generateLanguagesArray(
126
194
  englishTabs: NavTab[],
127
195
  langCodes: string[],
196
+ exists: PageExists = () => true,
128
197
  ): LanguageNav[] {
129
198
  // English first (default)
130
199
  const english: LanguageNav = { language: "en", tabs: englishTabs };
131
- const others = langCodes.map((code) => buildLanguageNav(englishTabs, code));
200
+ const others = langCodes.map((code) => buildLanguageNav(englishTabs, code, exists));
132
201
  return [english, ...others];
133
202
  }
134
203
 
@@ -136,6 +205,9 @@ export function generateLanguagesArray(
136
205
  export function localizeProductsNavigation(
137
206
  products: unknown[],
138
207
  langCodes: string[],
208
+ // Defaults to the real disk check, like updateDocsJson — injectable so the
209
+ // pure transform can be exercised against fixtures that are not on disk.
210
+ exists: PageExists = fileOnDisk,
139
211
  ): Record<string, unknown>[] {
140
212
  return products.map((value) => {
141
213
  const product = value as Record<string, unknown>;
@@ -149,7 +221,7 @@ export function localizeProductsNavigation(
149
221
  const { tabs: _tabs, ...rest } = product;
150
222
  return {
151
223
  ...rest,
152
- languages: generateLanguagesArray(englishTabs, langCodes),
224
+ languages: generateLanguagesArray(englishTabs, langCodes, exists),
153
225
  };
154
226
  });
155
227
  }
@@ -177,7 +249,7 @@ export function updateDocsJson(langCodes: string[]): void {
177
249
  }
178
250
 
179
251
  const newNav: Record<string, unknown> = {
180
- languages: generateLanguagesArray(englishTabs, langCodes),
252
+ languages: generateLanguagesArray(englishTabs, langCodes, fileOnDisk),
181
253
  };
182
254
  if (nav.global) {
183
255
  newNav.global = nav.global;