failproofai 0.0.13 → 0.0.14-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 (283) hide show
  1. package/.next/standalone/.factory/hooks.json +112 -0
  2. package/.next/standalone/.next/BUILD_ID +1 -1
  3. package/.next/standalone/.next/build-manifest.json +3 -3
  4. package/.next/standalone/.next/prerender-manifest.json +3 -3
  5. package/.next/standalone/.next/required-server-files.json +1 -1
  6. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  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 +2 -2
  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/_head.segment.rsc +3 -3
  14. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  15. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  16. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  17. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  18. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  19. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  20. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  21. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  22. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  23. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
  24. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  25. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  26. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  27. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/audit/run/route.js +3 -3
  29. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  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.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js +2 -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.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  40. package/.next/standalone/.next/server/app/index.html +1 -1
  41. package/.next/standalone/.next/server/app/index.rsc +15 -15
  42. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  43. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  44. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  45. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
  46. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  47. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  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 +8 -8
  51. package/.next/standalone/.next/server/app/policies/page.js +1 -1
  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 +3 -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 +5 -3
  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 +1 -1
  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/chunks/[root-of-the-server]__0--lkk6._.js +3 -0
  68. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-219ec._.js +3 -0
  69. package/.next/standalone/.next/server/chunks/[root-of-the-server]__04_h-a5._.js +3 -0
  70. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06cuf1y._.js +3 -0
  71. package/.next/standalone/.next/server/chunks/[root-of-the-server]__08w4wmd._.js +3 -0
  72. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0g6bbuw._.js +3 -0
  73. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0jllheg._.js +3 -0
  74. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0jnjf2t._.js +3 -0
  75. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q-v9z2._.js +1 -1
  76. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q0qzx1._.js +3 -0
  77. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q2nbsl._.js +3 -0
  78. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0rv7m0k._.js +1 -1
  79. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0xuaoik._.js +3 -3
  80. package/.next/standalone/.next/server/chunks/[root-of-the-server]__16le-kd._.js +3 -0
  81. package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +1 -1
  82. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1d9qen3._.js +3 -0
  83. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ffkmds._.js +3 -0
  84. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1fwl2mz._.js +1 -1
  85. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1legmza._.js +1 -1
  86. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1mrihkj._.js +1 -1
  87. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1myjm-d._.js +1 -1
  88. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1qb590j._.js +3 -0
  89. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1qxztj-._.js +1 -1
  90. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1shcqgr._.js +3 -0
  91. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1xuedea._.js +3 -0
  92. package/.next/standalone/.next/server/chunks/{_1z062h5._.js → _1vslkoe._.js} +2 -2
  93. package/.next/standalone/.next/server/chunks/lib_factory-projects_ts_1eo_bk-._.js +3 -0
  94. package/.next/standalone/.next/server/chunks/lib_openclaw-projects_ts_0gc-p24._.js +3 -0
  95. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +24 -12
  96. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  97. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__00cz9as._.js +3 -0
  98. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__015_i4t._.js +2 -2
  99. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__030k0c6._.js +3 -0
  100. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__03lv-pe._.js +2 -2
  101. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__042d3cd._.js +3 -0
  102. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__05r_17v._.js +3 -0
  103. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__07iom4f._.js → [root-of-the-server]__07qfsfa._.js} +2 -2
  104. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__09q1168._.js +3 -0
  105. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e2l3c1._.js +3 -0
  106. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ge8e7w._.js +3 -0
  107. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h12me5._.js +1 -1
  108. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0hci7t3._.js +3 -0
  109. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0hdsupo._.js +2 -2
  110. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0p84xee._.js +3 -0
  111. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qeuy9c._.js +2 -2
  112. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s89hoe._.js +2 -2
  113. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ynf7tx._.js +2 -2
  114. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11rtg6s._.js +1 -1
  115. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__14dd6h8._.js +1 -1
  116. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__170799-._.js +12 -9
  117. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17ai7sy._.js +4 -0
  118. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1d8omgc._.js +1 -1
  119. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1dky4g0._.js +1 -1
  120. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1nq7ivq._.js +3 -0
  121. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1tkjqka._.js +2 -2
  122. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__212nf49._.js +1 -1
  123. package/.next/standalone/.next/server/chunks/ssr/_05whahf._.js +1 -1
  124. package/.next/standalone/.next/server/chunks/ssr/_0_9_ytf._.js +3 -0
  125. package/.next/standalone/.next/server/chunks/ssr/_11_p9y8._.js +1 -1
  126. package/.next/standalone/.next/server/chunks/ssr/{_0ul5rf_._.js → _1_ozgif._.js} +2 -2
  127. package/.next/standalone/.next/server/chunks/ssr/_1p0-leb._.js +1 -1
  128. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +2 -2
  129. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  130. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
  131. package/.next/standalone/.next/server/chunks/ssr/lib_0xkhw_v._.js +3 -0
  132. package/.next/standalone/.next/server/chunks/ssr/lib_antigravity-projects_ts_0_6zf11._.js +3 -0
  133. package/.next/standalone/.next/server/chunks/ssr/lib_devin-projects_ts_0a64qdy._.js +3 -0
  134. package/.next/standalone/.next/server/chunks/ssr/lib_factory-projects_ts_1uyaahq._.js +3 -0
  135. package/.next/standalone/.next/server/chunks/ssr/lib_goose-projects_ts_0zkscri._.js +3 -0
  136. package/.next/standalone/.next/server/chunks/ssr/lib_openclaw-projects_ts_0qxq3bp._.js +3 -0
  137. package/.next/standalone/.next/server/chunks/ssr/{node_modules_html-to-image_es_index_13p7zob.js → node_modules_html-to-image_es_index_0g5r64e.js} +1 -1
  138. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0-uvagv.js +1 -1
  139. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_03c7gi5.js +1 -1
  140. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_09p-8om.js +1 -1
  141. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0v-kfiu.js +1 -1
  142. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0xrgzyz.js +1 -1
  143. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_1806lsc.js +1 -1
  144. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_1j6dd-e.js +1 -1
  145. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_1sa65r-.js +1 -1
  146. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1ezd2jf._.js +1 -1
  147. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1tnuifj._.js +1 -1
  148. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  149. package/.next/standalone/.next/server/pages/404.html +1 -1
  150. package/.next/standalone/.next/server/pages/500.html +1 -1
  151. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  152. package/.next/standalone/.next/server/server-reference-manifest.json +10 -10
  153. package/.next/standalone/.next/static/chunks/{23c7v2svx90dp.js → 003uz088wbmz7.js} +1 -1
  154. package/.next/standalone/.next/static/chunks/{0vc0eak148vo6.js → 0405htbxay9vd.js} +1 -1
  155. package/.next/standalone/.next/static/chunks/0iinhn4417nk1.js +1 -0
  156. package/.next/standalone/.next/static/chunks/1374x9bv_s_vg.js +6 -0
  157. package/.next/standalone/.next/static/chunks/{30ysv-_8jj052.js → 17sdztgbcc0fi.js} +1 -1
  158. package/.next/standalone/.next/static/chunks/{2cejn75gug3j8.js → 2m_tbl39fcedn.js} +1 -1
  159. package/.next/standalone/.next/static/chunks/{36wdtkgdf0zrd.js → 2o3ql0n5owqsw.js} +1 -1
  160. package/.next/standalone/.next/static/chunks/{0wtagd8a5gwq-.js → 2ufuwhv03yvtb.js} +1 -1
  161. package/.next/standalone/.next/static/chunks/35-90m9py64d4.js +1 -0
  162. package/.next/standalone/.next/static/chunks/3r--yyjkp9_7b.css +2 -0
  163. package/.next/standalone/.next/static/chunks/43weu8f59tlix.js +1 -0
  164. package/.next/standalone/.next/static/chunks/{05apzuand0c22.js → 454dyizqik6t9.js} +2 -2
  165. package/.next/standalone/app/api/audit/run/route.ts +2 -0
  166. package/.next/standalone/app/audit/_components/empty-state.tsx +1 -1
  167. package/.next/standalone/app/globals.css +25 -1
  168. package/.next/standalone/app/policies/hooks-client.tsx +2 -4
  169. package/.next/standalone/app/project/[name]/page.tsx +30 -10
  170. package/.next/standalone/app/project/[name]/session/[sessionId]/page.tsx +71 -21
  171. package/.next/standalone/assets/logos/antigravity.svg +1 -0
  172. package/.next/standalone/assets/logos/devin.svg +1 -0
  173. package/.next/standalone/assets/logos/factory-dark.png +0 -0
  174. package/.next/standalone/assets/logos/factory-light.png +0 -0
  175. package/.next/standalone/assets/logos/goose-dark.svg +1 -0
  176. package/.next/standalone/assets/logos/goose-light.svg +1 -0
  177. package/.next/standalone/assets/logos/openclaw.svg +22 -0
  178. package/.next/standalone/components/navbar.tsx +5 -11
  179. package/.next/standalone/components/reach-developers.tsx +1 -1
  180. package/.next/standalone/lib/antigravity-projects.ts +224 -0
  181. package/.next/standalone/lib/antigravity-sessions.ts +283 -0
  182. package/.next/standalone/lib/cli-registry.ts +26 -6
  183. package/.next/standalone/lib/devin-projects.ts +141 -0
  184. package/.next/standalone/lib/devin-sessions.ts +343 -0
  185. package/.next/standalone/lib/download-session.ts +56 -5
  186. package/.next/standalone/lib/factory-projects.ts +109 -0
  187. package/.next/standalone/lib/factory-sessions.ts +312 -0
  188. package/.next/standalone/lib/goose-projects.ts +148 -0
  189. package/.next/standalone/lib/goose-sessions.ts +296 -0
  190. package/.next/standalone/lib/openclaw-projects.ts +182 -0
  191. package/.next/standalone/lib/openclaw-sessions.ts +284 -0
  192. package/.next/standalone/lib/projects.ts +33 -9
  193. package/.next/standalone/lib/telemetry-sanitize.ts +43 -0
  194. package/.next/standalone/openclaw-plugin/index.js +223 -0
  195. package/.next/standalone/openclaw-plugin/openclaw.plugin.json +6 -0
  196. package/.next/standalone/openclaw-plugin/package.json +12 -0
  197. package/.next/standalone/package.json +2 -1
  198. package/.next/standalone/server.js +1 -1
  199. package/README.md +105 -57
  200. package/bin/failproofai.mjs +87 -29
  201. package/dist/cli.mjs +12803 -9809
  202. package/lib/antigravity-projects.ts +224 -0
  203. package/lib/antigravity-sessions.ts +283 -0
  204. package/lib/cli-registry.ts +26 -6
  205. package/lib/devin-projects.ts +141 -0
  206. package/lib/devin-sessions.ts +343 -0
  207. package/lib/download-session.ts +56 -5
  208. package/lib/factory-projects.ts +109 -0
  209. package/lib/factory-sessions.ts +312 -0
  210. package/lib/goose-projects.ts +148 -0
  211. package/lib/goose-sessions.ts +296 -0
  212. package/lib/openclaw-projects.ts +182 -0
  213. package/lib/openclaw-sessions.ts +284 -0
  214. package/lib/projects.ts +33 -9
  215. package/lib/telemetry-sanitize.ts +43 -0
  216. package/openclaw-plugin/index.js +223 -0
  217. package/openclaw-plugin/openclaw.plugin.json +6 -0
  218. package/openclaw-plugin/package.json +12 -0
  219. package/package.json +2 -1
  220. package/scripts/launch.ts +4 -8
  221. package/scripts/postinstall.mjs +3 -4
  222. package/scripts/sync-agent-cli-harnesses-prompt.md +7 -10
  223. package/scripts/translate-docs/cli.ts +73 -52
  224. package/scripts/translate-docs/config.ts +57 -13
  225. package/scripts/translate-docs/mdx-translator.ts +51 -31
  226. package/scripts/translate-docs/mintlify-nav.ts +91 -10
  227. package/scripts/translate-docs/types.ts +3 -0
  228. package/src/audit/cli-adapters/antigravity.ts +87 -0
  229. package/src/audit/cli-adapters/devin.ts +53 -0
  230. package/src/audit/cli-adapters/factory.ts +75 -0
  231. package/src/audit/cli-adapters/goose.ts +53 -0
  232. package/src/audit/cli-adapters/index.ts +30 -6
  233. package/src/audit/cli-adapters/openclaw.ts +56 -0
  234. package/src/audit/cli.ts +44 -1
  235. package/src/audit/report.ts +1 -1
  236. package/src/audit/types.ts +1 -1
  237. package/src/hooks/builtin-policies.ts +5 -5
  238. package/src/hooks/configure-wizard.ts +356 -0
  239. package/src/hooks/handler.ts +283 -218
  240. package/src/hooks/hook-telemetry.ts +43 -3
  241. package/src/hooks/install-prompt.ts +92 -173
  242. package/src/hooks/integrations.ts +739 -138
  243. package/src/hooks/manager.ts +46 -2
  244. package/src/hooks/policy-evaluator.ts +301 -121
  245. package/src/hooks/policy-presets.ts +71 -0
  246. package/src/hooks/resolve-cwd.ts +1 -1
  247. package/src/hooks/resolve-permission-mode.ts +1 -5
  248. package/src/hooks/resolve-transcript-path.ts +25 -7
  249. package/src/hooks/tool-name-canonicalize.ts +36 -3
  250. package/src/hooks/tui.ts +578 -0
  251. package/src/hooks/types.ts +447 -109
  252. package/.next/standalone/.gemini/settings.json +0 -147
  253. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cag8qd._.js +0 -3
  254. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cefjd9._.js +0 -3
  255. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ekj92q._.js +0 -3
  256. package/.next/standalone/.next/server/chunks/[root-of-the-server]__12v-lma._.js +0 -3
  257. package/.next/standalone/.next/server/chunks/[root-of-the-server]__136y39g._.js +0 -3
  258. package/.next/standalone/.next/server/chunks/[root-of-the-server]__13h8pzr._.js +0 -3
  259. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1hgv_75._.js +0 -3
  260. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04bqvos._.js +0 -3
  261. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0dqgs96._.js +0 -3
  262. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0q5rfxg._.js +0 -3
  263. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qukut7._.js +0 -4
  264. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__108slqn._.js +0 -3
  265. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ql-mch._.js +0 -3
  266. package/.next/standalone/.next/server/chunks/ssr/_11v0g3z._.js +0 -3
  267. package/.next/standalone/.next/server/chunks/ssr/lib_gemini-projects_ts_1c7bgx-._.js +0 -3
  268. package/.next/standalone/.next/static/chunks/0fa7j157kg9_d.js +0 -1
  269. package/.next/standalone/.next/static/chunks/0nrah-qv6smeg.js +0 -6
  270. package/.next/standalone/.next/static/chunks/1c8i78p7t1i-5.js +0 -1
  271. package/.next/standalone/.next/static/chunks/25qr0e6ez0ei0.js +0 -1
  272. package/.next/standalone/.next/static/chunks/25s52un3k_wht.css +0 -2
  273. package/.next/standalone/assets/logos/gemini-dark.svg +0 -13
  274. package/.next/standalone/assets/logos/gemini-light.svg +0 -13
  275. package/.next/standalone/lib/gemini-projects.ts +0 -243
  276. package/.next/standalone/lib/gemini-sessions.ts +0 -365
  277. package/lib/gemini-projects.ts +0 -243
  278. package/lib/gemini-sessions.ts +0 -365
  279. package/src/audit/cli-adapters/gemini.ts +0 -51
  280. package/src/hooks/first-run-nudge.ts +0 -146
  281. /package/.next/standalone/.next/static/{kmzdjTLVs6LqsfyOaUf69 → MNJWFb2jLRrxRKGFNK6Hy}/_buildManifest.js +0 -0
  282. /package/.next/standalone/.next/static/{kmzdjTLVs6LqsfyOaUf69 → MNJWFb2jLRrxRKGFNK6Hy}/_clientMiddlewareManifest.js +0 -0
  283. /package/.next/standalone/.next/static/{kmzdjTLVs6LqsfyOaUf69 → MNJWFb2jLRrxRKGFNK6Hy}/_ssgManifest.js +0 -0
@@ -144,10 +144,9 @@ try {
144
144
 
145
145
  if (!hooksResult.configured && !hooksResult.registered) {
146
146
  console.log(
147
- `\n[failproofai] Installed. Next steps:\n` +
148
- ` 1. Run \`failproofai policies --install\` to enable safety policies.\n` +
149
- ` 2. Run \`failproofai\` to open the dashboard (or just \`failproofai\` to start now — it'll offer to set up policies for you).\n` +
150
- ` Disable first-run prompt: FAILPROOFAI_NO_FIRST_RUN=1\n`
147
+ `\n[failproofai] Installed ✓\n` +
148
+ ` 👋 Hi! Run \`failproofai config\` to set it up.\n` +
149
+ ` (Disable this prompt: FAILPROOFAI_NO_FIRST_RUN=1)\n`
151
150
  );
152
151
  }
153
152
 
@@ -32,7 +32,6 @@ tracked in `src/hooks/types.ts` and written to disk by `src/hooks/integrations.t
32
32
  | Cursor Agent | `CURSOR_HOOK_EVENT_TYPES` | `CURSOR_EVENT_MAP` | `.cursor/hooks.json` |
33
33
  | OpenCode | `OPENCODE_HOOK_EVENT_TYPES` | `OPENCODE_EVENT_MAP` | `.opencode/opencode.json` + `.opencode/plugins/failproofai.mjs` |
34
34
  | Pi | `PI_HOOK_EVENT_TYPES` | `PI_EVENT_MAP` | `.pi/settings.json` |
35
- | Gemini CLI | `GEMINI_HOOK_EVENT_TYPES` | `GEMINI_EVENT_MAP` | `.gemini/settings.json` |
36
35
 
37
36
  ## What "drift" means — three scopes
38
37
 
@@ -62,7 +61,7 @@ For each verified CLI, compare the upstream docs to this repo across three scope
62
61
  when you only need to **inspect** a committed fixture, prefer
63
62
  `git show HEAD:<path>` (e.g. `git show HEAD:.codex/hooks.json`) — it is never
64
63
  blocked and is the reliable way to read `.claude/settings.json`, `.codex/hooks.json`,
65
- `.cursor/hooks.json`, `.github/hooks/failproofai.json`, `.gemini/settings.json`,
64
+ `.cursor/hooks.json`, `.github/hooks/failproofai.json`,
66
65
  `.pi/settings.json`, and `.opencode/*`.
67
66
  - Do **NOT** run `failproofai policies --install` (or any `failproofai` subcommand)
68
67
  to regenerate a fixture — it is blocked. Edit fixtures by hand.
@@ -76,7 +75,7 @@ Spawn one subagent per CLI (seven, in parallel). Each subagent, for its CLI:
76
75
  **settings-file schema** (top-level keys, per-entry shape, command field name,
77
76
  timeout field name **and unit**, and whether `matcher` / `version` / `$schema`
78
77
  are present). **Use upstream casing exactly** — Codex snake_case, Cursor
79
- camelCase, OpenCode dot.namespaced, Pi snake_case, Claude/Copilot/Gemini
78
+ camelCase, OpenCode dot.namespaced, Pi snake_case, Claude/Copilot
80
79
  PascalCase. Do **not** normalize.
81
80
  2. Compare against this repo: the CLI's `*HOOK_EVENT_TYPES` array + paired
82
81
  `*EVENT_MAP` (scope 1); its `*_TOOL_MAP` / `*_TOOL_INPUT_MAP` and its branch in
@@ -98,7 +97,6 @@ surface is documented in the package source, not a clean enumeration).
98
97
  | Cursor | https://cursor.com/docs/hooks |
99
98
  | OpenCode | https://opencode.ai/docs/plugins/ |
100
99
  | Pi | https://www.npmjs.com/package/@mariozechner/pi-coding-agent |
101
- | Gemini | https://geminicli.com/docs/hooks/ · https://geminicli.com/docs/reference/tools/ (tool names) |
102
100
 
103
101
  ## Phase 2 — Decide what to do (do this BEFORE editing any files)
104
102
 
@@ -122,7 +120,6 @@ changes that block a clean stop on the comment / no-op paths below.
122
120
 
123
121
  > This open sync PR is missing newly-detected drift:
124
122
  > - **Cursor**: upstream added event `afterEdit` — append to `CURSOR_HOOK_EVENT_TYPES` (+ a `CURSOR_EVENT_MAP` entry).
125
- > - **Gemini**: the `run_shell_command` tool was renamed to `shell` — the `GEMINI_TOOL_MAP` key is stale.
126
123
  >
127
124
  > (hook-sync bot — please fold these into this PR rather than opening a second sync PR.)
128
125
 
@@ -140,7 +137,7 @@ requires.
140
137
  - **Append** new events just before `] as const`, preserving upstream casing.
141
138
  - **Delete** removed events; if the CLI has an `*EVENT_MAP`, also delete the same
142
139
  key from that map (the `Record` is exhaustive — a stale key fails `tsc`).
143
- - For **map-bearing CLIs** (Codex, Cursor, OpenCode, Pi, Gemini), do **NOT** invent
140
+ - For **map-bearing CLIs** (Codex, Cursor, OpenCode, Pi), do **NOT** invent
144
141
  the canonical mapping for a newly-added event — leave it out of the `*EVENT_MAP`
145
142
  so `tsc` fails intentionally, and add a reviewer-checklist item to the PR body
146
143
  (see below). For **Claude and Copilot** (no map), the build stays green.
@@ -148,9 +145,9 @@ requires.
148
145
  - If `HOOK_EVENT_TYPES` (Claude) changed: in `__tests__/hooks/manager.test.ts`,
149
146
  update the `installs hooks for all <N> event types` description AND both
150
147
  `expect(Object.keys(written.hooks)).toHaveLength(<N>)` assertions.
151
- - If `GEMINI_HOOK_EVENT_TYPES` changed: in `__tests__/hooks/integrations.test.ts`,
152
- update the `expect(gemini.eventTypes).toHaveLength(<N>)` assertion AND the
153
- matching description string.
148
+ - If a CLI's `*_HOOK_EVENT_TYPES` changed: in `__tests__/hooks/integrations.test.ts`,
149
+ update the matching `expect(<cli>.eventTypes).toHaveLength(<N>)` assertion AND the
150
+ description string.
154
151
  - Locate these by searching for the current count number.
155
152
 
156
153
  ### Scope 2 / Scope 3 (tool schema / settings-file shape)
@@ -211,7 +208,7 @@ The PR **body** must contain, in order:
211
208
  `__tests__/e2e/hooks/<cli>-integration.e2e.test.ts`, the seven dogfood fixtures
212
209
  (`.claude/settings.json`, `.codex/hooks.json`, `.cursor/hooks.json`,
213
210
  `.github/hooks/failproofai.json`, `.opencode/opencode.json`,
214
- `.opencode/plugins/failproofai.mjs`, `.pi/settings.json`, `.gemini/settings.json`),
211
+ `.opencode/plugins/failproofai.mjs`, `.pi/settings.json`),
215
212
  and `CHANGELOG.md`.
216
213
  - Do **NOT** edit `.failproofai/policies-config.json` (the entrypoint manages it),
217
214
  `src/hooks/handler.ts`, `src/hooks/manager.ts`, or any other source file.
@@ -3,10 +3,19 @@ import { parseArgs } from "node:util";
3
3
  import { existsSync, readdirSync, readFileSync } from "node:fs";
4
4
  import { dirname, join, relative } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
- import { LANGUAGES, getLanguagesByTier, getLanguageByCode, getModelForTier } from "./config";
6
+ import {
7
+ LANGUAGES,
8
+ getLanguagesByTier,
9
+ getLanguageByCode,
10
+ getModelForTier,
11
+ } from "./config";
7
12
  import { getEnglishMdxPages, translateMdxPage } from "./mdx-translator";
8
13
  import { translateReadme } from "./readme-translator";
9
- import { updateDocsJson, readDocsConfig } from "./mintlify-nav";
14
+ import {
15
+ getNavigationPageReferences,
16
+ updateDocsJson,
17
+ readDocsConfig,
18
+ } from "./mintlify-nav";
10
19
  import { readCache, writeCache, isCached, setCacheEntry } from "./cache";
11
20
  import type { TranslationResult } from "./types";
12
21
 
@@ -87,44 +96,14 @@ async function validateNavReferences(): Promise<boolean> {
87
96
  let total = 0;
88
97
  let missing = 0;
89
98
 
90
- const languages = (nav.languages || []) as Array<{
91
- language: string;
92
- tabs: Array<{ groups: Array<{ pages: string[] }> }>;
93
- }>;
94
-
95
- if (languages.length === 0) {
96
- // Flat tabs structure (not yet migrated to languages)
97
- const tabs = (nav.tabs || []) as Array<{
98
- groups: Array<{ pages: string[] }>;
99
- }>;
100
- for (const tab of tabs) {
101
- for (const group of tab.groups) {
102
- for (const page of group.pages) {
103
- total++;
104
- const filePath = join(DOCS_DIR, `${page}.mdx`);
105
- if (!existsSync(filePath)) {
106
- console.error(` MISSING: ${page} -> ${filePath}`);
107
- missing++;
108
- valid = false;
109
- }
110
- }
111
- }
112
- }
113
- } else {
114
- for (const langEntry of languages) {
115
- for (const tab of langEntry.tabs) {
116
- for (const group of tab.groups) {
117
- for (const page of group.pages) {
118
- total++;
119
- const filePath = join(DOCS_DIR, `${page}.mdx`);
120
- if (!existsSync(filePath)) {
121
- console.error(` MISSING [${langEntry.language}]: ${page} -> ${filePath}`);
122
- missing++;
123
- valid = false;
124
- }
125
- }
126
- }
127
- }
99
+ for (const reference of getNavigationPageReferences(nav)) {
100
+ total++;
101
+ const filePath = join(DOCS_DIR, `${reference.page}.mdx`);
102
+ if (!existsSync(filePath)) {
103
+ const context = reference.language ? ` [${reference.language}]` : "";
104
+ console.error(` MISSING${context}: ${reference.page} -> ${filePath}`);
105
+ missing++;
106
+ valid = false;
128
107
  }
129
108
  }
130
109
 
@@ -169,7 +148,9 @@ async function main() {
169
148
  `${isDryRun ? "[DRY RUN] " : ""}Translating into: ${langCodes.join(", ")}`,
170
149
  );
171
150
  if (!modelOverride) {
172
- console.log(`Models: Tier 1 -> ${getModelForTier(1)}, Tier 2/3 -> ${getModelForTier(2)}`);
151
+ console.log(
152
+ `Models: Tier 1 -> ${getModelForTier(1)}, Tier 2/3 -> ${getModelForTier(2)}`,
153
+ );
173
154
  } else {
174
155
  console.log(`Model override: ${modelOverride}`);
175
156
  }
@@ -186,10 +167,17 @@ async function main() {
186
167
  // configured in translator.ts) to absorb per-request transient
187
168
  // `Connection error.` from LB-induced replica flapping.
188
169
  // Override via TRANSLATE_MAX_CONCURRENT (integer >= 1; otherwise default).
189
- const parsedConcurrent = Number.parseInt(process.env.TRANSLATE_MAX_CONCURRENT ?? "", 10);
170
+ const parsedConcurrent = Number.parseInt(
171
+ process.env.TRANSLATE_MAX_CONCURRENT ?? "",
172
+ 10,
173
+ );
190
174
  const MAX_CONCURRENT =
191
- Number.isInteger(parsedConcurrent) && parsedConcurrent > 0 ? parsedConcurrent : 4;
192
- async function runWithConcurrency<T>(tasks: (() => Promise<T>)[]): Promise<T[]> {
175
+ Number.isInteger(parsedConcurrent) && parsedConcurrent > 0
176
+ ? parsedConcurrent
177
+ : 4;
178
+ async function runWithConcurrency<T>(
179
+ tasks: (() => Promise<T>)[],
180
+ ): Promise<T[]> {
193
181
  const results: T[] = [];
194
182
  let i = 0;
195
183
  async function next(): Promise<void> {
@@ -198,7 +186,11 @@ async function main() {
198
186
  results[idx] = await tasks[idx]();
199
187
  }
200
188
  }
201
- await Promise.all(Array.from({ length: Math.min(MAX_CONCURRENT, tasks.length) }, () => next()));
189
+ await Promise.all(
190
+ Array.from({ length: Math.min(MAX_CONCURRENT, tasks.length) }, () =>
191
+ next(),
192
+ ),
193
+ );
202
194
  return results;
203
195
  }
204
196
 
@@ -227,7 +219,11 @@ async function main() {
227
219
  for (const page of filteredPages) {
228
220
  const relPath = relative(DOCS_DIR, page);
229
221
  const task = { page, relPath, lang };
230
- if (!isForce && !isDryRun && isCached(cache, relPath, lang, pageContents.get(page)!)) {
222
+ if (
223
+ !isForce &&
224
+ !isDryRun &&
225
+ isCached(cache, relPath, lang, pageContents.get(page)!)
226
+ ) {
231
227
  cachedTasks.push(task);
232
228
  } else {
233
229
  uncachedTasks.push(task);
@@ -235,7 +231,9 @@ async function main() {
235
231
  }
236
232
  }
237
233
 
238
- console.log(`\n${filteredPages.length} MDX pages x ${langCodes.length} languages = ${filteredPages.length * langCodes.length} total`);
234
+ console.log(
235
+ `\n${filteredPages.length} MDX pages x ${langCodes.length} languages = ${filteredPages.length * langCodes.length} total`,
236
+ );
239
237
  console.log(` Cached (unchanged): ${cachedTasks.length}`);
240
238
  console.log(` Need translation: ${uncachedTasks.length}`);
241
239
 
@@ -268,7 +266,14 @@ async function main() {
268
266
  console.log(` ${relPath} [${lang}] -> ${status}`);
269
267
  results.push(result);
270
268
  if (!result.cached && !isDryRun) {
271
- setCacheEntry(cache, relPath, lang, pageContents.get(page)!, result.inputTokens, result.outputTokens);
269
+ setCacheEntry(
270
+ cache,
271
+ relPath,
272
+ lang,
273
+ pageContents.get(page)!,
274
+ result.inputTokens,
275
+ result.outputTokens,
276
+ );
272
277
  }
273
278
  } catch (err) {
274
279
  const msg = err instanceof Error ? err.message : String(err);
@@ -285,10 +290,17 @@ async function main() {
285
290
  console.log(`\nTranslating README...`);
286
291
 
287
292
  // Read README once
288
- const readmeSource = readFileSync(join(DOCS_DIR, "..", "README.md"), "utf-8");
293
+ const readmeSource = readFileSync(
294
+ join(DOCS_DIR, "..", "README.md"),
295
+ "utf-8",
296
+ );
289
297
  const uncachedLangs: string[] = [];
290
298
  for (const lang of langCodes) {
291
- if (!isForce && !isDryRun && isCached(cache, "README.md", lang, readmeSource)) {
299
+ if (
300
+ !isForce &&
301
+ !isDryRun &&
302
+ isCached(cache, "README.md", lang, readmeSource)
303
+ ) {
292
304
  console.log(` README.${lang}.md -> cached`);
293
305
  results.push({
294
306
  lang,
@@ -317,10 +329,19 @@ async function main() {
317
329
  const status = isDryRun
318
330
  ? "would translate"
319
331
  : `translated (${result.inputTokens}+${result.outputTokens} tokens)`;
320
- console.log(` README.${lang}.md -> ${langConfig.nativeName}: ${status}`);
332
+ console.log(
333
+ ` README.${lang}.md -> ${langConfig.nativeName}: ${status}`,
334
+ );
321
335
  results.push(result);
322
336
  if (!result.cached && !isDryRun) {
323
- setCacheEntry(cache, "README.md", lang, readmeSource, result.inputTokens, result.outputTokens);
337
+ setCacheEntry(
338
+ cache,
339
+ "README.md",
340
+ lang,
341
+ readmeSource,
342
+ result.inputTokens,
343
+ result.outputTokens,
344
+ );
324
345
  }
325
346
  } catch (err) {
326
347
  const msg = err instanceof Error ? err.message : String(err);
@@ -2,22 +2,60 @@ import type { LanguageConfig } from "./types";
2
2
 
3
3
  export const LANGUAGES: LanguageConfig[] = [
4
4
  // Tier 1 — largest developer populations
5
- { code: "zh", name: "Chinese (Simplified)", nativeName: "\u7b80\u4f53\u4e2d\u6587", tier: 1 },
5
+ {
6
+ code: "zh",
7
+ name: "Chinese (Simplified)",
8
+ nativeName: "\u7b80\u4f53\u4e2d\u6587",
9
+ tier: 1,
10
+ },
6
11
  { code: "ja", name: "Japanese", nativeName: "\u65e5\u672c\u8a9e", tier: 1 },
7
12
  { code: "ko", name: "Korean", nativeName: "\ud55c\uad6d\uc5b4", tier: 1 },
8
13
  { code: "es", name: "Spanish", nativeName: "Espa\u00f1ol", tier: 1 },
9
- { code: "pt-br", name: "Portuguese (Brazil)", nativeName: "Portugu\u00eas", tier: 1 },
14
+ {
15
+ code: "pt-br",
16
+ mintlifyCode: "pt-BR",
17
+ name: "Portuguese (Brazil)",
18
+ nativeName: "Portugu\u00eas",
19
+ tier: 1,
20
+ },
10
21
  { code: "de", name: "German", nativeName: "Deutsch", tier: 1 },
11
22
  { code: "fr", name: "French", nativeName: "Fran\u00e7ais", tier: 1 },
12
23
  // Tier 2 — strong tech communities
13
- { code: "ru", name: "Russian", nativeName: "\u0420\u0443\u0441\u0441\u043a\u0438\u0439", tier: 2 },
14
- { code: "hi", name: "Hindi", nativeName: "\u0939\u093f\u0928\u094d\u0926\u0940", tier: 2 },
24
+ {
25
+ code: "ru",
26
+ name: "Russian",
27
+ nativeName: "\u0420\u0443\u0441\u0441\u043a\u0438\u0439",
28
+ tier: 2,
29
+ },
30
+ {
31
+ code: "hi",
32
+ name: "Hindi",
33
+ nativeName: "\u0939\u093f\u0928\u094d\u0926\u0940",
34
+ tier: 2,
35
+ },
15
36
  { code: "tr", name: "Turkish", nativeName: "T\u00fcrk\u00e7e", tier: 2 },
16
- { code: "vi", name: "Vietnamese", nativeName: "Ti\u1ebfng Vi\u1ec7t", tier: 2 },
37
+ {
38
+ code: "vi",
39
+ name: "Vietnamese",
40
+ nativeName: "Ti\u1ebfng Vi\u1ec7t",
41
+ tier: 2,
42
+ },
17
43
  { code: "it", name: "Italian", nativeName: "Italiano", tier: 2 },
18
44
  // Tier 3 — RTL languages
19
- { code: "ar", name: "Arabic", nativeName: "\u0627\u0644\u0639\u0631\u0628\u064a\u0629", tier: 3, rtl: true },
20
- { code: "he", name: "Hebrew", nativeName: "\u05e2\u05d1\u05e8\u05d9\u05ea", tier: 3, rtl: true },
45
+ {
46
+ code: "ar",
47
+ name: "Arabic",
48
+ nativeName: "\u0627\u0644\u0639\u0631\u0628\u064a\u0629",
49
+ tier: 3,
50
+ rtl: true,
51
+ },
52
+ {
53
+ code: "he",
54
+ name: "Hebrew",
55
+ nativeName: "\u05e2\u05d1\u05e8\u05d9\u05ea",
56
+ tier: 3,
57
+ rtl: true,
58
+ },
21
59
  ];
22
60
 
23
61
  export function getLanguagesByTier(maxTier: number): LanguageConfig[] {
@@ -184,17 +222,21 @@ export const NAV_TRANSLATIONS: Record<
184
222
  ru: {
185
223
  docs: "\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f",
186
224
  examples: "\u041f\u0440\u0438\u043c\u0435\u0440\u044b",
187
- gettingStarted: "\u041d\u0430\u0447\u0430\u043b\u043e \u0440\u0430\u0431\u043e\u0442\u044b",
188
- coreConcepts: "\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438",
225
+ gettingStarted:
226
+ "\u041d\u0430\u0447\u0430\u043b\u043e \u0440\u0430\u0431\u043e\u0442\u044b",
227
+ coreConcepts:
228
+ "\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438",
189
229
  cli: "CLI",
190
230
  tools: "\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b",
191
- advanced: "\u041f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0439",
231
+ advanced:
232
+ "\u041f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0439",
192
233
  },
193
234
  hi: {
194
235
  docs: "\u0926\u0938\u094d\u0924\u093e\u0935\u0947\u091c\u093c",
195
236
  examples: "\u0909\u0926\u093e\u0939\u0930\u0923",
196
237
  gettingStarted: "\u0936\u0941\u0930\u0942 \u0915\u0930\u0947\u0902",
197
- coreConcepts: "\u092e\u0942\u0932 \u0905\u0935\u0927\u093e\u0930\u0923\u093e\u090f\u0901",
238
+ coreConcepts:
239
+ "\u092e\u0942\u0932 \u0905\u0935\u0927\u093e\u0930\u0923\u093e\u090f\u0901",
198
240
  cli: "CLI",
199
241
  tools: "\u0909\u092a\u0915\u0930\u0923",
200
242
  advanced: "\u0909\u0928\u094d\u0928\u0924",
@@ -230,7 +272,8 @@ export const NAV_TRANSLATIONS: Record<
230
272
  docs: "\u0627\u0644\u0645\u0633\u062a\u0646\u062f\u0627\u062a",
231
273
  examples: "\u0623\u0645\u062b\u0644\u0629",
232
274
  gettingStarted: "\u0627\u0644\u0628\u062f\u0627\u064a\u0629",
233
- coreConcepts: "\u0627\u0644\u0645\u0641\u0627\u0647\u064a\u0645 \u0627\u0644\u0623\u0633\u0627\u0633\u064a\u0629",
275
+ coreConcepts:
276
+ "\u0627\u0644\u0645\u0641\u0627\u0647\u064a\u0645 \u0627\u0644\u0623\u0633\u0627\u0633\u064a\u0629",
234
277
  cli: "CLI",
235
278
  tools: "\u0627\u0644\u0623\u062f\u0648\u0627\u062a",
236
279
  advanced: "\u0645\u062a\u0642\u062f\u0645",
@@ -238,7 +281,8 @@ export const NAV_TRANSLATIONS: Record<
238
281
  he: {
239
282
  docs: "\u05ea\u05d9\u05e2\u05d5\u05d3",
240
283
  examples: "\u05d3\u05d5\u05d2\u05de\u05d0\u05d5\u05ea",
241
- gettingStarted: "\u05ea\u05d7\u05d9\u05dc\u05ea \u05e2\u05d1\u05d5\u05d3\u05d4",
284
+ gettingStarted:
285
+ "\u05ea\u05d7\u05d9\u05dc\u05ea \u05e2\u05d1\u05d5\u05d3\u05d4",
242
286
  coreConcepts: "\u05de\u05d5\u05e9\u05d2\u05d9 \u05d9\u05e1\u05d5\u05d3",
243
287
  cli: "CLI",
244
288
  tools: "\u05db\u05dc\u05d9\u05dd",
@@ -1,14 +1,15 @@
1
- import { readFileSync, writeFileSync, mkdirSync, readdirSync, statSync } from "node:fs";
1
+ import {
2
+ readFileSync,
3
+ writeFileSync,
4
+ mkdirSync,
5
+ readdirSync,
6
+ statSync,
7
+ } from "node:fs";
2
8
  import { dirname, join, relative } from "node:path";
3
9
  import { fileURLToPath } from "node:url";
4
10
  import { getLanguageByCode } from "./config";
5
11
  import { translateContent } from "./translator";
6
- import {
7
- readCache,
8
- writeCache,
9
- isCached,
10
- setCacheEntry,
11
- } from "./cache";
12
+ import { readCache, writeCache, isCached, setCacheEntry } from "./cache";
12
13
  import type { TranslationResult, TranslationCache } from "./types";
13
14
 
14
15
  const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -98,28 +99,23 @@ export function stripStrayTrailingFence(content: string): string {
98
99
  * e.g. href="/built-in-policies" -> href="/es/built-in-policies"
99
100
  * [Getting started](/getting-started) -> [Getting started](/es/getting-started)
100
101
  */
101
- export function rewriteInternalLinks(
102
- content: string,
103
- lang: string,
104
- ): string {
102
+ export function rewriteInternalLinks(content: string, lang: string): string {
103
+ const shouldPreservePath = (path: string): boolean =>
104
+ path.startsWith("/http") ||
105
+ path === "/" ||
106
+ /\.(?:png|jpe?g|gif|svg|webp|ico)(?:#.*)?$/i.test(path);
107
+
105
108
  // Rewrite MDX component href attributes pointing to internal paths
106
- let result = content.replace(
107
- /href="(\/[^"]*?)"/g,
108
- (_match, path: string) => {
109
- // Skip external URLs and anchors
110
- if (path.startsWith("/http") || path === "/") return `href="${path}"`;
111
- return `href="/${lang}${path}"`;
112
- },
113
- );
109
+ let result = content.replace(/href="(\/[^"]*?)"/g, (_match, path: string) => {
110
+ if (shouldPreservePath(path)) return `href="${path}"`;
111
+ return `href="/${lang}${path}"`;
112
+ });
114
113
 
115
114
  // Rewrite Markdown links with internal paths
116
- result = result.replace(
117
- /\]\((\/[^)]*?)\)/g,
118
- (_match, path: string) => {
119
- if (path.startsWith("/http") || path === "/") return `](${path})`;
120
- return `](/${lang}${path})`;
121
- },
122
- );
115
+ result = result.replace(/\]\((\/[^)]*?)\)/g, (_match, path: string) => {
116
+ if (shouldPreservePath(path)) return `](${path})`;
117
+ return `](/${lang}${path})`;
118
+ });
123
119
 
124
120
  return result;
125
121
  }
@@ -130,7 +126,12 @@ export function rewriteInternalLinks(
130
126
  export async function translateMdxPage(
131
127
  sourcePath: string,
132
128
  lang: string,
133
- options: { force?: boolean; dryRun?: boolean; model?: string; cache?: TranslationCache } = {},
129
+ options: {
130
+ force?: boolean;
131
+ dryRun?: boolean;
132
+ model?: string;
133
+ cache?: TranslationCache;
134
+ } = {},
134
135
  ): Promise<TranslationResult> {
135
136
  const relPath = relative(DOCS_DIR, sourcePath);
136
137
  const outputPath = join(DOCS_DIR, lang, relPath);
@@ -186,7 +187,14 @@ export async function translateMdxPage(
186
187
  // Update cache — skip if caller manages the cache (batch write)
187
188
  if (!options.cache) {
188
189
  const cache = readCache();
189
- setCacheEntry(cache, relPath, lang, sourceContent, inputTokens, outputTokens);
190
+ setCacheEntry(
191
+ cache,
192
+ relPath,
193
+ lang,
194
+ sourceContent,
195
+ inputTokens,
196
+ outputTokens,
197
+ );
190
198
  writeCache(cache);
191
199
  }
192
200
 
@@ -213,7 +221,7 @@ export function getEnglishMdxPages(): string[] {
213
221
  if (statSync(full).isDirectory()) {
214
222
  // Skip language directories at the top level
215
223
  if (!prefix && isLanguageDir(entry)) continue;
216
- // Skip non-doc directories like logo, i18n
224
+ // Skip non-page asset and localization directories.
217
225
  if (!prefix && (entry === "logo" || entry === "i18n")) continue;
218
226
  walk(full, rel);
219
227
  } else if (entry.endsWith(".mdx")) {
@@ -228,8 +236,20 @@ export function getEnglishMdxPages(): string[] {
228
236
 
229
237
  function isLanguageDir(name: string): boolean {
230
238
  const langCodes = [
231
- "zh", "ja", "ko", "es", "pt-br", "de", "fr",
232
- "ru", "hi", "tr", "vi", "it", "ar", "he",
239
+ "zh",
240
+ "ja",
241
+ "ko",
242
+ "es",
243
+ "pt-br",
244
+ "de",
245
+ "fr",
246
+ "ru",
247
+ "hi",
248
+ "tr",
249
+ "vi",
250
+ "it",
251
+ "ar",
252
+ "he",
233
253
  ];
234
254
  return langCodes.includes(name);
235
255
  }
@@ -1,7 +1,7 @@
1
1
  import { readFileSync, writeFileSync } from "node:fs";
2
2
  import { dirname, join } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
- import { NAV_TRANSLATIONS, LANGUAGES } from "./config";
4
+ import { getLanguageByCode, NAV_TRANSLATIONS, LANGUAGES } from "./config";
5
5
 
6
6
  const __dirname = dirname(fileURLToPath(import.meta.url));
7
7
  const DOCS_JSON_PATH = join(__dirname, "..", "..", "docs", "docs.json");
@@ -21,6 +21,57 @@ interface LanguageNav {
21
21
  tabs: NavTab[];
22
22
  }
23
23
 
24
+ export interface NavigationPageReference {
25
+ page: string;
26
+ language?: string;
27
+ }
28
+
29
+ /** Collect page references from flat, localized, or multi-product navigation. */
30
+ export function getNavigationPageReferences(
31
+ navigation: unknown,
32
+ ): NavigationPageReference[] {
33
+ const references: NavigationPageReference[] = [];
34
+ const childKeys = [
35
+ "products",
36
+ "languages",
37
+ "tabs",
38
+ "groups",
39
+ "anchors",
40
+ "dropdowns",
41
+ "versions",
42
+ "menu",
43
+ ];
44
+
45
+ function walk(value: unknown, inheritedLanguage?: string): void {
46
+ if (Array.isArray(value)) {
47
+ for (const item of value) walk(item, inheritedLanguage);
48
+ return;
49
+ }
50
+ if (!value || typeof value !== "object") return;
51
+
52
+ const entry = value as Record<string, unknown>;
53
+ const language =
54
+ typeof entry.language === "string" ? entry.language : inheritedLanguage;
55
+
56
+ if (Array.isArray(entry.pages)) {
57
+ for (const page of entry.pages) {
58
+ if (typeof page === "string") {
59
+ references.push({ page, language });
60
+ } else {
61
+ walk(page, language);
62
+ }
63
+ }
64
+ }
65
+
66
+ for (const key of childKeys) {
67
+ if (key !== "pages" && entry[key]) walk(entry[key], language);
68
+ }
69
+ }
70
+
71
+ walk(navigation);
72
+ return references;
73
+ }
74
+
24
75
  /**
25
76
  * Build a navigation entry for a specific language by transforming the
26
77
  * English navigation structure.
@@ -54,7 +105,10 @@ export function buildLanguageNav(
54
105
  })),
55
106
  }));
56
107
 
57
- return { language: lang, tabs };
108
+ return {
109
+ language: getLanguageByCode(lang)?.mintlifyCode ?? lang,
110
+ tabs,
111
+ };
58
112
  }
59
113
 
60
114
  /**
@@ -78,6 +132,28 @@ export function generateLanguagesArray(
78
132
  return [english, ...others];
79
133
  }
80
134
 
135
+ /** Localize every product that has English tabs or an English language entry. */
136
+ export function localizeProductsNavigation(
137
+ products: unknown[],
138
+ langCodes: string[],
139
+ ): Record<string, unknown>[] {
140
+ return products.map((value) => {
141
+ const product = value as Record<string, unknown>;
142
+ const existingLanguages = product.languages as LanguageNav[] | undefined;
143
+ const englishTabs = existingLanguages
144
+ ? existingLanguages.find((entry) => entry.language === "en")?.tabs
145
+ : (product.tabs as NavTab[] | undefined);
146
+
147
+ if (!englishTabs) return product;
148
+
149
+ const { tabs: _tabs, ...rest } = product;
150
+ return {
151
+ ...rest,
152
+ languages: generateLanguagesArray(englishTabs, langCodes),
153
+ };
154
+ });
155
+ }
156
+
81
157
  /**
82
158
  * Update docs.json to use the languages array structure.
83
159
  */
@@ -85,18 +161,23 @@ export function updateDocsJson(langCodes: string[]): void {
85
161
  const config = readDocsConfig();
86
162
  const nav = config.navigation as Record<string, unknown>;
87
163
 
88
- // Extract existing English tabs
89
- const englishTabs = nav.tabs as NavTab[];
90
- if (!englishTabs) {
91
- throw new Error("docs.json navigation.tabs not found is this already using the languages format?");
164
+ if (Array.isArray(nav.products)) {
165
+ nav.products = localizeProductsNavigation(nav.products, langCodes);
166
+ config.navigation = nav;
167
+ writeFileSync(DOCS_JSON_PATH, JSON.stringify(config, null, 2) + "\n");
168
+ return;
92
169
  }
93
170
 
94
- // Build languages array
95
- const languages = generateLanguagesArray(englishTabs, langCodes);
171
+ const existingLanguages = nav.languages as LanguageNav[] | undefined;
172
+ const englishTabs = existingLanguages
173
+ ? existingLanguages.find((entry) => entry.language === "en")?.tabs
174
+ : (nav.tabs as NavTab[] | undefined);
175
+ if (!englishTabs) {
176
+ throw new Error("No English navigation tabs found in docs.json");
177
+ }
96
178
 
97
- // Replace tabs with languages, preserve global
98
179
  const newNav: Record<string, unknown> = {
99
- languages,
180
+ languages: generateLanguagesArray(englishTabs, langCodes),
100
181
  };
101
182
  if (nav.global) {
102
183
  newNav.global = nav.global;
@@ -1,5 +1,8 @@
1
1
  export interface LanguageConfig {
2
+ /** Internal code used for folders, cache keys, and translation routing. */
2
3
  code: string;
4
+ /** Mintlify locale when its canonical casing differs from `code`. */
5
+ mintlifyCode?: string;
3
6
  name: string;
4
7
  nativeName: string;
5
8
  tier: 1 | 2 | 3;