failproofai 1.0.0-beta.2 → 1.0.0-beta.21

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 (381) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +2 -1
  3. package/.next/standalone/.next/build-manifest.json +6 -6
  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/routes-manifest.json +6 -0
  7. package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +3 -3
  8. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  9. package/.next/standalone/.next/server/app/_global-error/page.js +3 -1
  10. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  11. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  12. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  13. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  14. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  15. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  16. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
  17. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  18. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  19. package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +3 -3
  20. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  21. package/.next/standalone/.next/server/app/_not-found/page.js +3 -1
  22. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  23. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  24. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  25. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  26. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  27. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  28. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
  29. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  30. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  31. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  32. package/.next/standalone/.next/server/app/api/audit/invite/route.js +3 -2
  33. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/api/audit/run/route.js +4 -3
  35. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/api/audit/status/route.js +1 -1
  37. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  38. package/.next/standalone/.next/server/app/api/auth/login-request/route.js +3 -1
  39. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +3 -2
  41. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  42. package/.next/standalone/.next/server/app/api/auth/logout/route.js +3 -2
  43. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/api/auth/reminder/route.js +3 -2
  45. package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -1
  46. package/.next/standalone/.next/server/app/api/auth/status/route.js +3 -2
  47. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js +1 -1
  49. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  50. package/.next/standalone/.next/server/app/audit/page/build-manifest.json +3 -3
  51. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  52. package/.next/standalone/.next/server/app/audit/page.js +5 -3
  53. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  54. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  55. package/.next/standalone/.next/server/app/index.html +1 -1
  56. package/.next/standalone/.next/server/app/index.rsc +15 -15
  57. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  58. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  59. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  60. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
  61. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  62. package/.next/standalone/.next/server/app/page/build-manifest.json +3 -3
  63. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  64. package/.next/standalone/.next/server/app/page.js +3 -1
  65. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  66. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  67. package/.next/standalone/.next/server/app/policies/page/build-manifest.json +3 -3
  68. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +30 -18
  69. package/.next/standalone/.next/server/app/policies/page.js +5 -3
  70. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  71. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  72. package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +3 -3
  73. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  74. package/.next/standalone/.next/server/app/project/[name]/page.js +4 -2
  75. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  76. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  77. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +3 -3
  78. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  79. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  80. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +6 -4
  81. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  82. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  83. package/.next/standalone/.next/server/app/projects/page/build-manifest.json +3 -3
  84. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  85. package/.next/standalone/.next/server/app/projects/page.js +4 -2
  86. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  87. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  88. package/.next/standalone/.next/server/app/settings/page/app-paths-manifest.json +3 -0
  89. package/.next/standalone/.next/server/app/settings/page/build-manifest.json +18 -0
  90. package/.next/standalone/.next/server/app/settings/page/next-font-manifest.json +6 -0
  91. package/.next/standalone/.next/server/app/settings/page/react-loadable-manifest.json +1 -0
  92. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +53 -0
  93. package/.next/standalone/.next/server/app/settings/page.js +18 -0
  94. package/.next/standalone/.next/server/app/settings/page.js.map +5 -0
  95. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -0
  96. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +3 -0
  97. package/.next/standalone/.next/server/app-paths-manifest.json +2 -1
  98. package/.next/standalone/.next/server/chunks/[externals]__0h9_83k._.js +3 -0
  99. package/.next/standalone/.next/server/chunks/{[externals]__1nl3dvw._.js → [externals]__0r-zamh._.js} +2 -2
  100. package/.next/standalone/.next/server/chunks/[externals]__1ifpkx-._.js +3 -0
  101. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0l4vuqm._.js → [root-of-the-server]__00ni9za._.js} +2 -2
  102. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06hexd0._.js +3 -0
  103. package/.next/standalone/.next/server/chunks/[root-of-the-server]__08y94xv._.js +3 -0
  104. package/.next/standalone/.next/server/chunks/[root-of-the-server]__094p1f1._.js +3 -0
  105. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_0xu5z._.js +1 -1
  106. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ed01_d._.js +3 -0
  107. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0-dh5jy._.js → [root-of-the-server]__0effm9m._.js} +2 -2
  108. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0g0vcwt._.js +3 -0
  109. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__18d-9oi._.js → [root-of-the-server]__0ix8gm7._.js} +2 -2
  110. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0h3lfmp._.js → [root-of-the-server]__0ji11a-._.js} +2 -2
  111. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__10oa-v9._.js → [root-of-the-server]__0ojwjxl._.js} +2 -2
  112. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__16le-kd._.js → [root-of-the-server]__0pbp9fe._.js} +2 -2
  113. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q-v9z2._.js +1 -1
  114. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0vb5fl2._.js +3 -0
  115. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0sb_5m8._.js → [root-of-the-server]__131ebum._.js} +4 -4
  116. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ibjy5x._.js +3 -0
  117. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tvn4wf._.js +1 -1
  118. package/.next/standalone/.next/server/chunks/[root-of-the-server]__20d06rh._.js +3 -0
  119. package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +3 -0
  120. package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +3 -0
  121. package/.next/standalone/.next/server/chunks/lib_telemetry_ts_0dctyyw._.js +3 -0
  122. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +5 -5
  123. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_01r25oi._.js +2 -1
  124. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_09z9-p7._.js +2 -1
  125. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  126. package/.next/standalone/.next/server/chunks/ssr/[externals]__1aq139v._.js +3 -0
  127. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0-wfhrp._.js +3 -0
  128. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__06bp_fg._.js +5 -0
  129. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__074qmkp._.js +3 -0
  130. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1apb7k_._.js → [root-of-the-server]__0_1tiya._.js} +2 -2
  131. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__170799-._.js → [root-of-the-server]__0spkm68._.js} +11 -11
  132. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0t281d4._.js +3 -0
  133. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17itmx-._.js +5 -0
  134. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__01od0m6._.js → [root-of-the-server]__1n2vcv4._.js} +2 -2
  135. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1qapotl._.js +1 -1
  136. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1rv-sc9._.js +3 -0
  137. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1tlvv9a._.js +3 -0
  138. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1u-wx42._.js +4 -0
  139. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1v185mo._.js +3 -0
  140. package/.next/standalone/.next/server/chunks/ssr/_0-yi74u._.js +3 -0
  141. package/.next/standalone/.next/server/chunks/ssr/_0rjgfln._.js +3 -0
  142. package/.next/standalone/.next/server/chunks/ssr/_0vo2qyt._.js +3 -0
  143. package/.next/standalone/.next/server/chunks/ssr/_0xej-0e._.js +3 -0
  144. package/.next/standalone/.next/server/chunks/ssr/_10399ge._.js +3 -0
  145. package/.next/standalone/.next/server/chunks/ssr/_11_p9y8._.js +1 -1
  146. package/.next/standalone/.next/server/chunks/ssr/_149k9oy._.js +3 -0
  147. package/.next/standalone/.next/server/chunks/ssr/_1_hwp06._.js +3 -0
  148. package/.next/standalone/.next/server/chunks/ssr/_1ctse6u._.js +3 -0
  149. package/.next/standalone/.next/server/chunks/ssr/_1e19atl._.js +1 -1
  150. package/.next/standalone/.next/server/chunks/ssr/_1mnhi_r._.js +3 -0
  151. package/.next/standalone/.next/server/chunks/ssr/_1ror7k9._.js +3 -0
  152. package/.next/standalone/.next/server/chunks/ssr/_1sdgprl._.js +5 -0
  153. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +2 -2
  154. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  155. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
  156. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0dwo94s.js +4 -0
  157. package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_11bnuzn._.js +2 -1
  158. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +3 -0
  159. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +4 -0
  160. package/.next/standalone/.next/server/middleware-build-manifest.js +6 -6
  161. package/.next/standalone/.next/server/middleware.js +2 -2
  162. package/.next/standalone/.next/server/pages/404.html +1 -1
  163. package/.next/standalone/.next/server/pages/500.html +1 -1
  164. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  165. package/.next/standalone/.next/server/server-reference-manifest.json +74 -20
  166. package/.next/standalone/.next/static/chunks/{03fmihek9n986.js → 06zgzyh3wv1ig.js} +1 -1
  167. package/.next/standalone/.next/static/chunks/0km-jn9o5xyqs.css +2 -0
  168. package/.next/standalone/.next/static/chunks/{1hdhteui932bq.js → 0qmo2t50kpb30.js} +1 -1
  169. package/.next/standalone/.next/static/chunks/{2sbelanzvxvv0.js → 113g8wtal6_c4.js} +22 -22
  170. package/.next/standalone/.next/static/chunks/16p68cybetr31.js +1 -0
  171. package/.next/standalone/.next/static/chunks/18wqn0_3mzylf.js +1 -0
  172. package/.next/standalone/.next/static/chunks/1v1gqvpjk62jm.js +1 -0
  173. package/.next/standalone/.next/static/chunks/{0fi645si-uiiq.js → 1xq1m8h14tnlj.js} +1 -1
  174. package/.next/standalone/.next/static/chunks/{3hp8ulqknybil.js → 1y3vwogqb88dx.js} +1 -1
  175. package/.next/standalone/.next/static/chunks/{3vs4ay36tjds_.js → 1zmh-b0ulrqu7.js} +1 -1
  176. package/.next/standalone/.next/static/chunks/23kev26by1e4f.js +1 -0
  177. package/.next/standalone/.next/static/chunks/299lhw60e8gr6.js +1 -0
  178. package/.next/standalone/.next/static/chunks/{18rvdw5v72364.js → 2adbpdaxp5ygq.js} +1 -1
  179. package/.next/standalone/.next/static/chunks/{2j94uwkb4s3qr.js → 2kbqcw-6swmav.js} +1 -1
  180. package/.next/standalone/.next/static/chunks/2n9n5m0963pdg.js +6 -0
  181. package/.next/standalone/.next/static/chunks/2uvhw57mf9lg_.css +2 -0
  182. package/.next/standalone/.next/static/chunks/{31feojxhjyjpl.js → 30nrrpwymht5m.js} +1 -1
  183. package/.next/standalone/.next/static/chunks/31coz11ia5vc4.js +1 -0
  184. package/.next/standalone/.next/static/chunks/{turbopack-1lsv92x7klwrn.js → turbopack-3diub4ctvn1n0.js} +1 -1
  185. package/.next/standalone/SECURITY.md +8 -2
  186. package/.next/standalone/app/actions/get-active-pauses.ts +16 -0
  187. package/.next/standalone/app/actions/get-hooks-config.ts +2 -2
  188. package/.next/standalone/app/actions/get-scheduled-audit.ts +70 -0
  189. package/.next/standalone/app/actions/update-scheduled-audit.ts +44 -0
  190. package/.next/standalone/app/api/audit/run/route.ts +28 -0
  191. package/.next/standalone/app/api/audit/status/route.ts +13 -1
  192. package/.next/standalone/app/api/auth/status/route.ts +1 -1
  193. package/.next/standalone/app/audit/_components/audit-dashboard.tsx +1 -3
  194. package/.next/standalone/app/audit/_components/audit-progress-strip.tsx +1 -1
  195. package/.next/standalone/app/audit/_components/auth-dialog.css +159 -0
  196. package/.next/standalone/app/audit/_components/auth-dialog.tsx +3 -0
  197. package/.next/standalone/app/audit/_components/come-back-better-section.tsx +1 -1
  198. package/.next/standalone/app/audit/_components/empty-state.tsx +0 -1
  199. package/.next/standalone/app/audit/_components/how-to-improve-section.tsx +1 -1
  200. package/.next/standalone/app/audit/_components/quirks-section.tsx +0 -1
  201. package/.next/standalone/app/audit/_components/report-footer.tsx +0 -2
  202. package/.next/standalone/app/audit/_components/run-progress.tsx +1 -1
  203. package/.next/standalone/app/audit/_components/strengths-section.tsx +0 -1
  204. package/.next/standalone/app/audit/audit-styles.css +6 -149
  205. package/.next/standalone/app/components/pause-notices.tsx +111 -0
  206. package/.next/standalone/app/components/raw-log-viewer.tsx +1 -1
  207. package/.next/standalone/app/components/toast.tsx +1 -1
  208. package/.next/standalone/app/policies/hooks-client.tsx +84 -8
  209. package/.next/standalone/app/settings/page.tsx +31 -0
  210. package/.next/standalone/app/settings/settings-client.tsx +487 -0
  211. package/.next/standalone/components/navbar.tsx +2 -0
  212. package/.next/standalone/lib/auth/api-server-client.ts +2 -3
  213. package/.next/standalone/lib/auth/auth-store.ts +4 -5
  214. package/.next/standalone/lib/codex-sessions.ts +2 -1
  215. package/.next/standalone/lib/dashboard-host.ts +101 -0
  216. package/.next/standalone/lib/install-check.ts +22 -7
  217. package/.next/standalone/lib/pi-sessions.ts +99 -14
  218. package/.next/standalone/lib/telemetry-enabled.ts +54 -0
  219. package/.next/standalone/lib/telemetry-id.ts +52 -1
  220. package/.next/standalone/lib/telemetry.ts +8 -4
  221. package/.next/standalone/node_modules/react/cjs/react.development.js +1 -1
  222. package/.next/standalone/node_modules/react/cjs/react.production.js +1 -1
  223. package/.next/standalone/node_modules/react/package.json +3 -3
  224. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.browser.production.js +1 -1
  225. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.node.production.js +1 -1
  226. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.browser.production.js +3 -3
  227. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.edge.production.js +3 -3
  228. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.node.production.js +3 -3
  229. package/.next/standalone/node_modules/react-dom/cjs/react-dom.production.js +1 -1
  230. package/.next/standalone/node_modules/react-dom/package.json +4 -4
  231. package/.next/standalone/package.json +23 -12
  232. package/.next/standalone/proxy.ts +111 -1
  233. package/.next/standalone/server.js +1 -1
  234. package/bin/failproofai-worker.mjs +1 -1
  235. package/bin/failproofai.mjs +1041 -81
  236. package/bin/failproofaid-shim.mjs +4 -4
  237. package/dist/cli.mjs +18513 -10474
  238. package/dist/worker.mjs +1223 -299
  239. package/lib/auth/api-server-client.ts +2 -3
  240. package/lib/auth/auth-store.ts +4 -5
  241. package/lib/codex-sessions.ts +2 -1
  242. package/lib/dashboard-host.ts +101 -0
  243. package/lib/install-check.ts +22 -7
  244. package/lib/pi-sessions.ts +99 -14
  245. package/lib/telemetry-enabled.ts +54 -0
  246. package/lib/telemetry-id.ts +52 -1
  247. package/lib/telemetry.ts +8 -4
  248. package/package.json +23 -12
  249. package/scripts/build-daemon-packages.mjs +247 -0
  250. package/scripts/daemon-platforms.mjs +42 -0
  251. package/scripts/dev-hook.mjs +46 -5
  252. package/scripts/install-telemetry.mjs +8 -1
  253. package/scripts/launch.ts +25 -3
  254. package/scripts/parse-script-args.ts +27 -1
  255. package/scripts/prune-standalone.mjs +26 -0
  256. package/scripts/publish-aliases.mjs +62 -41
  257. package/scripts/repro-npm-install.sh +155 -0
  258. package/scripts/translate-docs/cache.ts +1 -1
  259. package/scripts/translate-docs/cli.ts +2 -2
  260. package/scripts/translate-docs/mintlify-nav.ts +1 -1
  261. package/scripts/translate-docs/readme-translator.ts +163 -4
  262. package/scripts/validate-mdx.ts +153 -13
  263. package/src/audit/audit-lock.ts +285 -0
  264. package/src/audit/audit-schedule.ts +111 -0
  265. package/src/audit/cache.ts +18 -5
  266. package/src/audit/cli-adapters/goose.ts +2 -1
  267. package/src/audit/cli-adapters/hermes.ts +28 -10
  268. package/src/audit/cli.ts +191 -35
  269. package/src/audit/dashboard-cache.ts +2 -3
  270. package/src/audit/report.ts +0 -1
  271. package/src/hooks/backfill-cli.ts +247 -0
  272. package/src/hooks/builtin-policies.ts +391 -3
  273. package/src/hooks/cloud-connection.ts +354 -0
  274. package/src/hooks/cloud-enrollment-cli.ts +439 -0
  275. package/src/hooks/cloud-enrollment.ts +284 -0
  276. package/src/hooks/cloud-introspect.ts +147 -0
  277. package/src/hooks/cloud-managed-policies.ts +206 -0
  278. package/src/hooks/collector-config.ts +218 -0
  279. package/src/hooks/configure-wizard.ts +1211 -233
  280. package/src/hooks/custom-hooks-loader.ts +243 -37
  281. package/src/hooks/daemon-client.ts +136 -33
  282. package/src/hooks/daemon-download.ts +264 -31
  283. package/src/hooks/daemon-service.ts +1124 -76
  284. package/src/hooks/first-run-gate.ts +50 -0
  285. package/src/hooks/flush-cli.ts +180 -0
  286. package/src/hooks/fp-config.ts +835 -0
  287. package/src/hooks/fp-home.ts +714 -0
  288. package/src/hooks/fp-reset.ts +1363 -0
  289. package/src/hooks/handler.ts +185 -6
  290. package/src/hooks/harness-cli.ts +386 -0
  291. package/src/hooks/hook-activity-store.ts +171 -24
  292. package/src/hooks/hook-logger.ts +2 -2
  293. package/src/hooks/hook-telemetry.ts +5 -1
  294. package/src/hooks/hooks-config.ts +4 -3
  295. package/src/hooks/integrations.ts +0 -1
  296. package/src/hooks/loader-utils.ts +172 -9
  297. package/src/hooks/manager.ts +41 -5
  298. package/src/hooks/migrations.ts +450 -0
  299. package/src/hooks/onboarding-attempt.ts +195 -0
  300. package/src/hooks/onboarding-lock.ts +118 -0
  301. package/src/hooks/policy-types.ts +28 -0
  302. package/src/hooks/session-pause-cli.ts +159 -0
  303. package/src/hooks/session-pause.ts +267 -0
  304. package/src/hooks/setup-state.ts +256 -0
  305. package/src/hooks/tui.ts +209 -9
  306. package/src/hooks/uninstall-cli.ts +418 -0
  307. package/src/hooks/worker-server.ts +134 -15
  308. package/.next/standalone/.next/server/chunks/[externals]__14odj07._.js +0 -3
  309. package/.next/standalone/.next/server/chunks/[externals]__1s61mel._.js +0 -3
  310. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0id_xf7._.js +0 -3
  311. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0longh-._.js +0 -3
  312. package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +0 -3
  313. package/.next/standalone/.next/server/chunks/[root-of-the-server]__19120tr._.js +0 -3
  314. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1fwl2mz._.js +0 -3
  315. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1myjm-d._.js +0 -3
  316. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1rhmvod._.js +0 -3
  317. package/.next/standalone/.next/server/chunks/ssr/[externals]__1_g_b3t._.js +0 -3
  318. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0114ewg._.js +0 -4
  319. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02r5bgf._.js +0 -4
  320. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e8sjqm._.js +0 -4
  321. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0lkzqax._.js +0 -4
  322. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0nb0syg._.js +0 -3
  323. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qucxyj._.js +0 -4
  324. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0u02miy._.js +0 -4
  325. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0uno39i._.js +0 -3
  326. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__14dd6h8._.js +0 -3
  327. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ath6v_._.js +0 -4
  328. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1psjybo._.js +0 -3
  329. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1zqz4v8._.js +0 -4
  330. package/.next/standalone/.next/server/chunks/ssr/_1m_p7pi._.js +0 -3
  331. package/.next/standalone/.next/server/chunks/ssr/node_modules_html-to-image_es_index_0oy_-36.js +0 -3
  332. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1ezd2jf._.js +0 -5
  333. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1tnuifj._.js +0 -5
  334. package/.next/standalone/.next/static/chunks/0h7auy7hzjyhw.js +0 -1
  335. package/.next/standalone/.next/static/chunks/0zbxssxh53n-3.js +0 -1
  336. package/.next/standalone/.next/static/chunks/2mazwb1qmur1p.js +0 -1
  337. package/.next/standalone/.next/static/chunks/2pujpnfx4pws6.css +0 -2
  338. package/.next/standalone/.next/static/chunks/33u59vf_8xpd-.js +0 -1
  339. package/.next/standalone/.next/static/chunks/3i27c3hcriawq.css +0 -1
  340. package/.next/standalone/.next/static/chunks/3s7myk_co0gbh.js +0 -1
  341. package/.next/standalone/.next/static/chunks/40k1_v4os4cw6.js +0 -6
  342. package/.next/standalone/Cargo.lock +0 -428
  343. package/.next/standalone/Cargo.toml +0 -9
  344. package/.next/standalone/crates/PROTOCOL.md +0 -122
  345. package/.next/standalone/crates/failproofaid/Cargo.toml +0 -18
  346. package/.next/standalone/crates/failproofaid/src/lock.rs +0 -81
  347. package/.next/standalone/crates/failproofaid/src/main.rs +0 -83
  348. package/.next/standalone/crates/failproofaid/src/paths.rs +0 -172
  349. package/.next/standalone/crates/failproofaid/src/server.rs +0 -502
  350. package/.next/standalone/crates/failproofaid/src/worker.rs +0 -400
  351. package/.next/standalone/crates/failproofaid/tests/daemon_e2e.rs +0 -241
  352. package/.next/standalone/crates/fpai-ipc/Cargo.toml +0 -16
  353. package/.next/standalone/crates/fpai-ipc/src/envelope.rs +0 -175
  354. package/.next/standalone/crates/fpai-ipc/src/framing.rs +0 -177
  355. package/.next/standalone/crates/fpai-ipc/src/lib.rs +0 -10
  356. package/.next/standalone/crates/fpai-ipc/src/peer.rs +0 -80
  357. package/.next/standalone/docker-hook-sync/Dockerfile +0 -79
  358. package/.next/standalone/docker-hook-sync/entrypoint.sh +0 -109
  359. package/.next/standalone/integration-suite/Dockerfile +0 -47
  360. package/.next/standalone/integration-suite/README.md +0 -129
  361. package/.next/standalone/integration-suite/canary-policies.mjs +0 -45
  362. package/.next/standalone/integration-suite/capture-tokens.sh +0 -48
  363. package/.next/standalone/integration-suite/ci-entrypoint.sh +0 -179
  364. package/.next/standalone/integration-suite/inject-tokens.sh +0 -44
  365. package/.next/standalone/integration-suite/install-clis.sh +0 -136
  366. package/.next/standalone/integration-suite/probe-cli.sh +0 -248
  367. package/.next/standalone/integration-suite/report.js +0 -120
  368. package/.next/standalone/integration-suite/run.sh +0 -159
  369. package/.next/standalone/openclaw-plugin/index.js +0 -223
  370. package/.next/standalone/openclaw-plugin/openclaw.plugin.json +0 -6
  371. package/.next/standalone/openclaw-plugin/package.json +0 -12
  372. package/.next/standalone/osv-scanner.toml +0 -17
  373. package/.next/standalone/pi-extension/index.ts +0 -524
  374. package/.next/standalone/pi-extension/package.json +0 -12
  375. package/.next/standalone/postcss.config.mjs +0 -8
  376. package/.next/standalone/readme-arch-hq.gif +0 -0
  377. package/.next/standalone/rust-toolchain.toml +0 -4
  378. package/src/auth/cli.ts +0 -371
  379. /package/.next/standalone/.next/static/{NWAjs0tHFyzk97gRGG09r → VjEdIL6W5uBsvEzknXqV9}/_buildManifest.js +0 -0
  380. /package/.next/standalone/.next/static/{NWAjs0tHFyzk97gRGG09r → VjEdIL6W5uBsvEzknXqV9}/_clientMiddlewareManifest.js +0 -0
  381. /package/.next/standalone/.next/static/{NWAjs0tHFyzk97gRGG09r → VjEdIL6W5uBsvEzknXqV9}/_ssgManifest.js +0 -0
@@ -8,7 +8,7 @@
8
8
  import { execSync } from "node:child_process";
9
9
  import { existsSync } from "node:fs";
10
10
  import { resolve, basename } from "node:path";
11
- import { homedir, platform, arch, release, hostname } from "node:os";
11
+ import { platform, arch, release, hostname } from "node:os";
12
12
  import {
13
13
  HOOK_SCOPES,
14
14
  type HookScope,
@@ -24,6 +24,8 @@ import { trackHookEvent } from "./hook-telemetry";
24
24
  import { getInstanceId, hashToId } from "../../lib/telemetry-id";
25
25
  import { CliError } from "../cli-error";
26
26
  import { hookLogWarn } from "./hook-logger";
27
+ import { customPoliciesDir, globalPolicyConfigFile } from "./fp-home";
28
+ import { readActiveCloudManagedPolicies } from "./cloud-managed-policies";
27
29
 
28
30
  const VALID_POLICY_NAMES = new Set(BUILTIN_POLICIES.map((p) => p.name));
29
31
 
@@ -645,7 +647,7 @@ export async function listHooks(cwd?: string): Promise<void> {
645
647
  } else {
646
648
  console.log("\n Run `failproofai policies --install` to get started.");
647
649
  }
648
- console.log(" Config: ~/.failproofai/policies-config.json\n");
650
+ console.log(` Config: ${globalPolicyConfigFile()}\n`);
649
651
  } else if (installedScopes.length === 1) {
650
652
  // State B: Single scope — table with header row
651
653
  const scope = installedScopes[0];
@@ -657,7 +659,7 @@ export async function listHooks(cwd?: string): Promise<void> {
657
659
  for (const policy of regularPolicies) printSimpleRow(policy);
658
660
  printBetaSection(printSimpleRow);
659
661
 
660
- console.log("\n Config: ~/.failproofai/policies-config.json\n");
662
+ console.log(`\n Config: ${globalPolicyConfigFile()}\n`);
661
663
  } else {
662
664
  // State C: Multiple scopes — column table
663
665
  const COL = 9;
@@ -701,7 +703,7 @@ export async function listHooks(cwd?: string): Promise<void> {
701
703
  for (const policy of betaPolicies) printMultiScopeRow(policy);
702
704
  }
703
705
 
704
- console.log("\n Config: ~/.failproofai/policies-config.json");
706
+ console.log(`\n Config: ${globalPolicyConfigFile()}`);
705
707
 
706
708
  // Multi-scope warning
707
709
  const scopeNames = installedScopes.join(", ");
@@ -765,7 +767,7 @@ export async function listHooks(cwd?: string): Promise<void> {
765
767
  // hook path was loading them.
766
768
  const base = findProjectConfigDir(cwd ?? process.cwd());
767
769
  const projectDir = resolve(base, ".failproofai", "policies");
768
- const userDir = resolve(homedir(), ".failproofai", "policies");
770
+ const userDir = customPoliciesDir();
769
771
  const sameDir = userDir === projectDir;
770
772
  const conventionDirs: { label: string; dir: string }[] = [
771
773
  { label: sameDir ? "Project + User" : "Project", dir: projectDir },
@@ -838,6 +840,40 @@ export async function listHooks(cwd?: string): Promise<void> {
838
840
  console.log();
839
841
  }
840
842
 
843
+ // Cloud-managed policies. These enforce on this machine exactly like the two
844
+ // sections above, but nothing here listed them — so `failproofai policies`
845
+ // answered "what is enforcing?" with a subset, and the policies an operator
846
+ // pushed to a fleet were the ones invisible to the person running the
847
+ // command on it.
848
+ //
849
+ // Read-only on purpose: these are owned by the deployment, not by local
850
+ // config. `--uninstall <name>` cannot switch one off, and printing them
851
+ // beside toggleable rows without saying so would imply it can.
852
+ try {
853
+ const cloud = readActiveCloudManagedPolicies();
854
+ if (cloud.length > 0) {
855
+ const gen = cloud[0].deployment;
856
+ console.log(
857
+ `\n \u2500\u2500 Cloud-managed \u2014 deployment ${gen} \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`,
858
+ );
859
+ const colWidth = Math.max(nameColWidth, ...cloud.map((c) => c.id.length + 2));
860
+ for (const artifact of cloud) {
861
+ // `observe` is evaluated and then has its verdict discarded, so a row
862
+ // that read "ON" would claim enforcement this policy deliberately is
863
+ // not doing.
864
+ const status =
865
+ artifact.effect === "observe" ? "\x1B[33m\u25D0 OBS\x1B[0m" : "\x1B[32m\u2713 ON\x1B[0m";
866
+ console.log(` ${status} ${artifact.id.padEnd(colWidth)}v${artifact.version}`);
867
+ }
868
+ console.log("\n Managed from the dashboard \u2014 not switchable with `failproofai policies`.");
869
+ console.log();
870
+ }
871
+ } catch {
872
+ // A machine with no deployment, or an unreadable manifest, simply has no
873
+ // section. The hook path reports its own failures; a listing must not be
874
+ // the thing that turns a bad manifest into a broken command.
875
+ }
876
+
841
877
  // Mirror what was just listed into the USER config. Safe here because
842
878
  // `failproofai policies` is a one-shot command — never do this on the hook
843
879
  // path (see the HooksConfig.conventionPolicies doc comment).
@@ -0,0 +1,450 @@
1
+ /**
2
+ * How a home written by an older layout reaches this one, step by step.
3
+ *
4
+ * ## The problem this replaces
5
+ *
6
+ * `resetHome(from)` took the layout it found and then largely ignored it: the
7
+ * carry functions each asked "is layout 1's file here? is layout 2's?" and
8
+ * handled whichever they found. That works for two old layouts and does not
9
+ * scale — every carry has to know every historical path, so the knowledge grows
10
+ * with the SQUARE of the layout count, in a set of hand-written functions with
11
+ * nothing forcing them to stay complete. It is also the shape that produced every
12
+ * silent-data-loss bug in `fp-reset.ts`'s history.
13
+ *
14
+ * A registry of steps replaces it. `planMigration()` composes a chain from what
15
+ * is on disk to what this build speaks, and each step only has to know its own
16
+ * ends.
17
+ *
18
+ * ## Keyed on the LAYOUT, never on the npm version
19
+ *
20
+ * The customer case is "on 1.0.0 for four months, then jumps to 1.3.0". The steps
21
+ * are LAYOUT steps, not version steps, because npm versions change on every
22
+ * release — dozens between two layouts — and a customer who skips thirty of them
23
+ * with no layout change should run ZERO migrations, not thirty no-ops. The npm
24
+ * version is recorded in the ledger for diagnostics and decides nothing.
25
+ *
26
+ * ## `to` is not always `from + 1`, and that is deliberate
27
+ *
28
+ * The obvious contract is single-hop steps. Today's two steps both land on layout
29
+ * 3 — one from 1, one from 2 — because `resetHome` was written before this
30
+ * registry existed and handles either source directly. Forcing them into single
31
+ * hops would mean inventing a 1 → 2 step that produces an intermediate layout-2
32
+ * home NO CODE IN THIS REPO WRITES ANY MORE, purely to satisfy the shape, and
33
+ * then a 2 → 3 step that consumes it. That is more moving parts and one more
34
+ * thing to get wrong, for a home state no user will ever hold.
35
+ *
36
+ * So the contract is `to > from`, and composition follows the `to` link rather
37
+ * than counting. A chain from 1 today is one step; when layout 4 lands it becomes
38
+ * `1 → 3` then `3 → 4`, and only the second has to be written.
39
+ */
40
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
41
+ import { basename, dirname, resolve } from "node:path";
42
+ import { version as cliVersion } from "../../package.json";
43
+ import {
44
+ LAYOUT_VERSION,
45
+ configFile,
46
+ credentialsFile,
47
+ failproofaiHome,
48
+ globalPolicyConfigFile,
49
+ legacy,
50
+ migrationBackupDir,
51
+ migrationLedgerFile,
52
+ migrationsDir,
53
+ versionFile,
54
+ } from "./fp-home";
55
+ import { resetHome, type ResetOutcome } from "./fp-reset";
56
+
57
+ export interface Migration {
58
+ /** The layout this step reads. */
59
+ from: number;
60
+ /** The layout the home speaks once it has run. Always greater than `from`. */
61
+ to: number;
62
+ /** One line, printed by `--dry-run`. Present tense, names what moves. */
63
+ describe: string;
64
+ run(): ResetOutcome;
65
+ }
66
+
67
+ /**
68
+ * Every step, in order.
69
+ *
70
+ * Both current entries delegate to `resetHome`, which is where the actual carry
71
+ * logic lives and stays — this module owns the ORDER and the record, not the
72
+ * moves. A layout-4 step would be written as its own function here and would not
73
+ * touch `resetHome` at all, which is the point: the next migration is additive.
74
+ */
75
+ export const MIGRATIONS: readonly Migration[] = [
76
+ {
77
+ from: 1,
78
+ to: 3,
79
+ describe:
80
+ "layout 1 → 3: carry the decision log out of cache/, keep the policy config in place, drop the layout-1 credential files",
81
+ run: () => resetHome(1),
82
+ },
83
+ {
84
+ from: 2,
85
+ to: 3,
86
+ describe:
87
+ "layout 2 → 3: carry config.toml and credentials.toml into JSON, move custom-policies/ back up into policies/, nest the policy config at the root",
88
+ run: () => resetHome(2),
89
+ },
90
+ ];
91
+
92
+ /**
93
+ * The steps that take `from` to {@link LAYOUT_VERSION}.
94
+ *
95
+ * Returns an empty array when the home is already current. THROWS when no step
96
+ * covers a layout, rather than returning a short chain — a partial plan silently
97
+ * leaves a home half-migrated, which is the one outcome `fp-reset.ts`'s header
98
+ * says is worse than refusing. `migrationCoverageGap()` below is the same check
99
+ * run over every layout at once, so CI catches it before a user does.
100
+ */
101
+ export function planMigration(from: number, registry: readonly Migration[] = MIGRATIONS): Migration[] {
102
+ if (from >= LAYOUT_VERSION) return [];
103
+ const chain: Migration[] = [];
104
+ let at = from;
105
+ while (at < LAYOUT_VERSION) {
106
+ const step = registry.find((m) => m.from === at);
107
+ if (!step) {
108
+ throw new Error(
109
+ `no migration from layout ${at} to ${LAYOUT_VERSION} — this build cannot upgrade that home`,
110
+ );
111
+ }
112
+ chain.push(step);
113
+ at = step.to;
114
+ }
115
+ return chain;
116
+ }
117
+
118
+ /**
119
+ * Layouts with no way forward, and steps that cannot be reached.
120
+ *
121
+ * The CI guard. Bumping `LAYOUT_VERSION` without writing a step leaves every
122
+ * older home unable to upgrade — and the symptom shows up on a user's machine
123
+ * rather than in a test, because nothing in the normal path plans a chain for a
124
+ * layout the developer does not happen to have on disk.
125
+ */
126
+ export function migrationCoverageGap(registry: readonly Migration[] = MIGRATIONS): string[] {
127
+ const problems: string[] = [];
128
+ for (let layout = 1; layout < LAYOUT_VERSION; layout += 1) {
129
+ try {
130
+ planMigration(layout, registry);
131
+ } catch {
132
+ problems.push(`layout ${layout} has no path to ${LAYOUT_VERSION}`);
133
+ }
134
+ }
135
+ for (const m of registry) {
136
+ if (m.to <= m.from) problems.push(`step ${m.from} → ${m.to} does not move forward`);
137
+ if (m.to > LAYOUT_VERSION) problems.push(`step ${m.from} → ${m.to} overshoots ${LAYOUT_VERSION}`);
138
+ }
139
+ const froms = registry.map((m) => m.from);
140
+ if (froms.length !== new Set(froms).size) problems.push("two steps read the same layout");
141
+ return problems;
142
+ }
143
+
144
+ // ── The ledger ───────────────────────────────────────────────────────────────
145
+
146
+ export interface LedgerEntry {
147
+ from: number;
148
+ to: number;
149
+ /** The CLI that ran it. Diagnostics only — the chain is keyed on layout. */
150
+ cli: string;
151
+ /** ISO-8601, so a support request can be lined up against a deploy. */
152
+ at: string;
153
+ durationMs: number;
154
+ ok: boolean;
155
+ /** Counts, so "did my history survive" is answerable from the file alone. */
156
+ removed?: number;
157
+ migrated?: number;
158
+ activity?: number;
159
+ }
160
+
161
+ export function readLedger(): LedgerEntry[] {
162
+ try {
163
+ const parsed = JSON.parse(readFileSync(migrationLedgerFile(), "utf8")) as unknown;
164
+ return Array.isArray(parsed) ? (parsed as LedgerEntry[]) : [];
165
+ } catch {
166
+ // Absent on every machine that has never migrated, which is most of them.
167
+ return [];
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Append one entry.
173
+ *
174
+ * Read-modify-write rather than an append-only line format, because the file is
175
+ * read as JSON by support and by `failproofai migrate --dry-run`, and a torn
176
+ * final line would make the whole thing unparseable. Two migrations never race:
177
+ * a migration only runs from a CLI command, and the onboarding lock already
178
+ * serialises those.
179
+ */
180
+ function appendLedger(entry: LedgerEntry): void {
181
+ try {
182
+ mkdirSync(migrationsDir(), { recursive: true });
183
+ const all = [...readLedger(), entry];
184
+ writeFileSync(migrationLedgerFile(), `${JSON.stringify(all, null, 2)}\n`, "utf8");
185
+ } catch {
186
+ // A ledger we cannot write must never fail the migration it is recording.
187
+ // The `VERSION` stamp is what makes the migration durable; this is the audit
188
+ // trail, and losing a line of it costs a support conversation, not a home.
189
+ }
190
+ }
191
+
192
+ // ── The backup ───────────────────────────────────────────────────────────────
193
+
194
+ /**
195
+ * The files worth copying before a step runs.
196
+ *
197
+ * Small, and each irreplaceable: nothing regenerates a cloud token, a policy
198
+ * selection, or the settings that decide whether the machine fails closed. The
199
+ * two retired TOMLs are included because a step is about to delete them, and they
200
+ * are the only remaining copy of a layout-2 machine's enrolment.
201
+ *
202
+ * Deliberately NOT the whole home. `HOME_CLASSES` already stopped the migration
203
+ * deleting anything irreplaceable by design, so a full copy would insure against
204
+ * a threat that no longer exists — while costing a duplicate of `bin/` and
205
+ * `hook-activity/`, and needing a rename window that has to dodge a live daemon.
206
+ * What is left to insure against is a BUG in a step, and these files are where
207
+ * such a bug would hurt.
208
+ */
209
+ /**
210
+ * One file to back up: where it lives, and what to call it in the backup.
211
+ *
212
+ * `as` exists because the backup directory is FLAT and two of these paths share a
213
+ * basename. It is only set where that happens, so every other entry keeps the
214
+ * name it has always been saved under — which matters, because `backup-layout<n>/`
215
+ * directories written by beta.17 and beta.18 are already on real machines and
216
+ * `restoreBackup()` has to keep finding them. Restructuring the backup into
217
+ * mirrored subdirectories would have been the tidier scheme and would have renamed
218
+ * data an older build already wrote: the same mistake as the four rename bugs
219
+ * above it in this changelog.
220
+ */
221
+ interface BackedUpFile {
222
+ at: () => string;
223
+ as?: string;
224
+ }
225
+
226
+ const BACKED_UP: BackedUpFile[] = [
227
+ { at: configFile },
228
+ { at: credentialsFile },
229
+ { at: globalPolicyConfigFile },
230
+ { at: versionFile },
231
+ ];
232
+
233
+ const BACKED_UP_LEGACY: BackedUpFile[] = [
234
+ { at: legacy.configToml },
235
+ { at: legacy.credentialsToml },
236
+ { at: legacy.policyConfig },
237
+ // Layout 2's policy selection, at the NESTED path. `legacy.policyConfig` above
238
+ // is the layout-1 ROOT path, which layout 3 reuses and which the migration
239
+ // therefore leaves alone — so on the layout-2 leg it is usually absent, and
240
+ // listing it was the whole of this backup's claim to protect a policy
241
+ // selection. The file layout 2 actually holds it in is under
242
+ // `legacy.localPoliciesDir()`, which IS deleted. So the one leg where the
243
+ // selection is destroyed was the one leg with no copy of it, while
244
+ // `describePlan` reported a backup either way.
245
+ //
246
+ // Saved under a distinct name because the basename collides with the entry
247
+ // above: flat, they would overwrite each other on backup, and on restore the
248
+ // single surviving file would be copied back to BOTH paths — writing layout 2's
249
+ // nested selection over layout 3's live config.
250
+ { at: legacy.localPolicyConfig, as: "local-policies-policies-config.json" },
251
+ // Layout 1's credentials, which the migration DELETES and which nothing
252
+ // regenerates. They were missing here while the carry that reads them was
253
+ // added, so on the layout-1 leg — the one a user upgrading from the published
254
+ // `latest` actually takes — the cloud token was removed with no copy kept. That
255
+ // is precisely the file this backup exists for, and its absence made the backup
256
+ // most incomplete exactly where it mattered most.
257
+ { at: legacy.cloudCredentials },
258
+ { at: legacy.ingestCredentials },
259
+ ];
260
+
261
+ /** The name a file is saved under inside `backup-layout<n>/`. */
262
+ function backupNameOf(f: BackedUpFile): string {
263
+ return f.as ?? basename(f.at());
264
+ }
265
+
266
+ /**
267
+ * The files that exist right now and would be backed up, each exactly once.
268
+ *
269
+ * ONE function, because there were two: `backupBeforeMigrating` deduped by path
270
+ * and `describePlan` built the same list again without deduping, so
271
+ * `migrate --dry-run` printed `policies-config.json` TWICE while the backup
272
+ * correctly wrote it once. Seen on a real machine, in the one command whose
273
+ * entire job is to state accurately what is about to happen.
274
+ *
275
+ * The duplicate is not a typo waiting to be spotted, it is structural:
276
+ * `legacy.policyConfig()` and `globalPolicyConfigFile()` are the SAME path,
277
+ * because layout 3 put the policy config back exactly where layout 1 kept it. Any
278
+ * caller that walks both lists sees it twice. So the walk lives here once and
279
+ * nobody walks those arrays directly — which is the same "state it once, derive
280
+ * the rest" move `resettablePaths()` makes over `HOME_CLASSES`.
281
+ */
282
+ function filesToBackUp(): { path: string; as: string }[] {
283
+ const seen = new Map<string, string>();
284
+ for (const f of [...BACKED_UP, ...BACKED_UP_LEGACY]) {
285
+ const path = f.at();
286
+ if (existsSync(path)) seen.set(path, backupNameOf(f));
287
+ }
288
+ return [...seen].map(([path, as]) => ({ path, as }));
289
+ }
290
+
291
+ /** Copy the irreplaceable files aside. Returns the basenames it saved. */
292
+ export function backupBeforeMigrating(from: number): string[] {
293
+ const dir = migrationBackupDir(from);
294
+ const saved: string[] = [];
295
+ try {
296
+ // A previous attempt's backup is replaced, not merged: a half-old, half-new
297
+ // set is not a restorable snapshot of anything.
298
+ rmSync(dir, { recursive: true, force: true });
299
+ mkdirSync(dir, { recursive: true });
300
+ } catch {
301
+ return [];
302
+ }
303
+ for (const { path: source, as } of filesToBackUp()) {
304
+ try {
305
+ copyFileSync(source, resolve(dir, as));
306
+ saved.push(as);
307
+ } catch {
308
+ // One unreadable file must not stop the rest being saved, and must not
309
+ // stop the migration — the backup is insurance, not a precondition.
310
+ }
311
+ }
312
+ return saved.sort((a, b) => a.localeCompare(b));
313
+ }
314
+
315
+ // ── Running ──────────────────────────────────────────────────────────────────
316
+
317
+ export interface MigrationRun {
318
+ /** The layout found on disk. */
319
+ from: number;
320
+ steps: { from: number; to: number; ok: boolean }[];
321
+ /** Basenames copied into `migrations/backup-layout<n>/`. */
322
+ backedUp: string[];
323
+ /** Merged outcome of every step that ran. */
324
+ outcome: ResetOutcome;
325
+ /** Set when a step threw. The home is left where that step got to. */
326
+ failed?: { from: number; to: number; error: string };
327
+ }
328
+
329
+ /**
330
+ * Run the chain from `from` to {@link LAYOUT_VERSION}, recording each step.
331
+ *
332
+ * The backup is taken ONCE, before the first step, against the layout actually
333
+ * found — the point is to be able to get back to where the machine started, not
334
+ * to snapshot each intermediate state.
335
+ *
336
+ * A step that throws STOPS the chain. It does not roll back: `resetHome` stamps
337
+ * `VERSION` at the end of a successful run, so a step that failed part-way leaves
338
+ * a home still marked with the old layout, which is the state the next command
339
+ * will correctly try to migrate again. Continuing past a failure would be the
340
+ * genuinely dangerous option — it would run a step against a home whose
341
+ * preconditions the previous step never established.
342
+ */
343
+ export function runMigrations(
344
+ from: number,
345
+ /**
346
+ * The chain to run. Defaults to the real plan; a caller passes one only to
347
+ * exercise a path the real registry cannot currently produce — a step that
348
+ * THROWS, which is the branch that decides whether a machine can be left
349
+ * half-migrated and is therefore the one most worth a test.
350
+ */
351
+ chain: readonly Migration[] = planMigration(from),
352
+ ): MigrationRun {
353
+ const backedUp = backupBeforeMigrating(from);
354
+ const steps: MigrationRun["steps"] = [];
355
+ const outcome: ResetOutcome = {
356
+ removed: [],
357
+ migrated: [],
358
+ activity: [],
359
+ policyConfig: [],
360
+ spooled: [],
361
+ from,
362
+ };
363
+ let failed: MigrationRun["failed"];
364
+
365
+ for (const step of chain) {
366
+ const startedAt = Date.now();
367
+ try {
368
+ const result = step.run();
369
+ outcome.removed.push(...result.removed);
370
+ outcome.migrated.push(...result.migrated);
371
+ outcome.activity.push(...result.activity);
372
+ outcome.policyConfig.push(...result.policyConfig);
373
+ outcome.spooled.push(...result.spooled);
374
+ steps.push({ from: step.from, to: step.to, ok: true });
375
+ appendLedger({
376
+ from: step.from,
377
+ to: step.to,
378
+ cli: cliVersion,
379
+ at: new Date(startedAt).toISOString(),
380
+ durationMs: Date.now() - startedAt,
381
+ ok: true,
382
+ removed: result.removed.length,
383
+ migrated: result.migrated.length,
384
+ activity: result.activity.length,
385
+ });
386
+ } catch (err) {
387
+ steps.push({ from: step.from, to: step.to, ok: false });
388
+ failed = {
389
+ from: step.from,
390
+ to: step.to,
391
+ error: err instanceof Error ? err.message : String(err),
392
+ };
393
+ appendLedger({
394
+ from: step.from,
395
+ to: step.to,
396
+ cli: cliVersion,
397
+ at: new Date(startedAt).toISOString(),
398
+ durationMs: Date.now() - startedAt,
399
+ ok: false,
400
+ });
401
+ break;
402
+ }
403
+ }
404
+
405
+ return { from, steps, backedUp, outcome, failed };
406
+ }
407
+
408
+ /** What `--dry-run` prints: the chain, and what was saved last time. */
409
+ export function describePlan(from: number): string[] {
410
+ if (from >= LAYOUT_VERSION) {
411
+ return [`${failproofaiHome()} is already at layout ${LAYOUT_VERSION}. Nothing to migrate.`];
412
+ }
413
+ let chain: Migration[];
414
+ try {
415
+ chain = planMigration(from);
416
+ } catch (err) {
417
+ return [err instanceof Error ? err.message : String(err)];
418
+ }
419
+ return [
420
+ `Layout ${from} on disk; this build speaks ${LAYOUT_VERSION}.`,
421
+ `${chain.length} step(s) would run:`,
422
+ ...chain.map((m) => ` ${m.from} → ${m.to} ${m.describe}`),
423
+ ``,
424
+ `These would be copied to ${migrationBackupDir(from)} first:`,
425
+ ...filesToBackUp().map((f) => ` ${f.as}`),
426
+ ``,
427
+ `Settings, cloud enrolment, policy selection, your own policy files, decision`,
428
+ `history and undelivered events are carried, not removed — see \`HOME_CLASSES\`.`,
429
+ ];
430
+ }
431
+
432
+ /** Restore a backup taken before the layout-`n` migration. */
433
+ export function restoreBackup(layout: number): string[] {
434
+ const dir = migrationBackupDir(layout);
435
+ if (!existsSync(dir)) return [];
436
+ const restored: string[] = [];
437
+ for (const f of [...BACKED_UP, ...BACKED_UP_LEGACY]) {
438
+ const target = f.at();
439
+ const source = resolve(dir, backupNameOf(f));
440
+ if (!existsSync(source)) continue;
441
+ try {
442
+ mkdirSync(dirname(target), { recursive: true });
443
+ copyFileSync(source, target);
444
+ restored.push(backupNameOf(f));
445
+ } catch {
446
+ // Report what did land rather than claiming a restore that did not.
447
+ }
448
+ }
449
+ return restored.sort((a, b) => a.localeCompare(b));
450
+ }