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
@@ -0,0 +1,714 @@
1
+ /**
2
+ * Every path inside `~/.failproofai`, in one place.
3
+ *
4
+ * Before this module the layout was ~40 hardcoded `resolve(homedir(),
5
+ * ".failproofai", …)` calls in TypeScript and ~10 more in Rust, and the two
6
+ * sides had drifted into three different ideas of where things lived
7
+ * (`cache/hook-activity` vs `hook-activity`, `spool` at the root vs under
8
+ * state). Moving anything meant finding every one of them, and missing one
9
+ * meant the daemon wrote where the dashboard did not read — silently, because
10
+ * an absent directory is indistinguishable from an idle one.
11
+ *
12
+ * So: nothing outside this file may join a path onto the failproofai home.
13
+ * The Rust side mirrors it in `crates/failproofaid/src/paths.rs`. The test that
14
+ * asserts the two agree lives THERE, not here —
15
+ * `paths::tests::every_mirrored_path_agrees_with_fp_home_ts` imports this module
16
+ * in a child process and compares every mirrored path against its own.
17
+ *
18
+ * This line used to cite `__tests__/hooks/fp-home.test.ts`, which contains no
19
+ * reference to `crates/` and never checked anything cross-language. While both
20
+ * files claimed the guard existed, three paths were wrong at once: the daemon's
21
+ * `run/` ignored `FAILPROOFAI_HOME` (so a healthy daemon on a fail-closed
22
+ * machine denied every tool call), its cloud policy directory still said
23
+ * `cloud-managed`, and its credential still said `cloud.json`.
24
+ *
25
+ * ## Layout 3
26
+ *
27
+ * Three things changed from layout 2, all of them about a directory saying what
28
+ * it holds:
29
+ *
30
+ * - **Everything is JSON.** `config.toml` and `credentials.toml` are now
31
+ * `.json`. Two serialisation formats in one home meant two parsers, two
32
+ * escaping rules, and a `toml` dependency in both the CLI and the daemon to
33
+ * read files that were only ever flat key/value.
34
+ * - **`policies/` holds policies, and only policies.** It also held
35
+ * `local-policies/` — our config, not a policy at all, and the one file a
36
+ * user must not hand-edit sitting among the ones they should. That moved to
37
+ * the root. What stays is every policy on the machine: the user's own `*.mjs`
38
+ * directly in it, the fleet's under `cloud-policies/`. Nesting them is safe
39
+ * because the convention loader does not recurse (see `cloudPoliciesDir`),
40
+ * and it means one directory answers "what governs this machine".
41
+ * - **No per-deployment directories.** `cloud-policies/generations/<n>/` held a
42
+ * full copy of every artifact per deployment — a tree to create, prune and
43
+ * keep consistent with the manifest, on top of the `artifacts/` copy. They
44
+ * are content-addressed and therefore immutable, so the copies bought nothing
45
+ * the digests did not already give. `cloud-policies/` is flat now: one
46
+ * `artifacts/` directory, and `active.json` naming what is live — see
47
+ * `cloud_policies.rs` for why activation is still atomic without them.
48
+ *
49
+ * ```
50
+ * ~/.failproofai/
51
+ * VERSION layout / cli / daemon versions
52
+ * config.json 0644 non-secret: mode, daemon, collector prefs
53
+ * credentials.json 0600 every token
54
+ * policies-config.json the builtin enable/disable set + params
55
+ * bin/ downloaded daemon binaries, one per version
56
+ * policies/ every policy: the user's *.mjs sit directly here
57
+ * cloud-policies/ the fleet's — flat: active.json, desired-state.json, artifacts/
58
+ * cursors/<source>/ per-source collector watermarks
59
+ * audit/ audit report + per-session cache
60
+ * hook-activity/ decision log the dashboard reads
61
+ * custom-agents/ SDK spool (events/ + failed/)
62
+ * run/ sockets + flock — MUST stay shallow, see below
63
+ * state/ daemon scratch: spool, failed, health, pauses, shims
64
+ * ```
65
+ *
66
+ * **`run/` is deliberately NOT under `state/`.** A Unix socket path must fit
67
+ * in `sockaddr_un.sun_path` (~108 bytes) and we have hit that ceiling twice
68
+ * already during development. Every directory level spends part of a budget
69
+ * that a long `$HOME` has already eaten into, so the socket stays as close to
70
+ * the root as it can.
71
+ *
72
+ * ## Project scope is NOT here
73
+ *
74
+ * `<project>/.failproofai/` keeps its old shape — `policies-config.json` and
75
+ * `policies/*.mjs` at the top. Those files are committed to users' git repos,
76
+ * so reorganising them would rewrite history in every repo that adopted
77
+ * failproofai. `hooks-config.ts` still owns those paths.
78
+ */
79
+ import { homedir } from "node:os";
80
+ import { resolve } from "node:path";
81
+
82
+ /**
83
+ * The on-disk layout this build speaks.
84
+ *
85
+ * Bumped whenever a path in this file moves. Recorded in `VERSION`, and what
86
+ * `detectLayout()` compares against — a home written by a different layout is
87
+ * refused rather than half-read, because reading a moved directory silently
88
+ * yields "no data" instead of an error.
89
+ *
90
+ * 1 — the original flat/`cache`-based layout, through 1.0.0-beta.5.
91
+ * 2 — this file.
92
+ */
93
+ export const LAYOUT_VERSION = 3;
94
+
95
+ /**
96
+ * `~/.failproofai`, or `FAILPROOFAI_HOME`.
97
+ *
98
+ * The override is load-bearing for tests and containers: everything below is
99
+ * derived from it, so pointing it elsewhere relocates the entire layout
100
+ * atomically rather than per-path.
101
+ */
102
+ export function failproofaiHome(home?: string): string {
103
+ if (home) return resolve(home, ".failproofai");
104
+ return process.env.FAILPROOFAI_HOME || resolve(homedir(), ".failproofai");
105
+ }
106
+
107
+ const at = (...parts: string[]): string => resolve(failproofaiHome(), ...parts);
108
+
109
+ /**
110
+ * Same, against an explicitly supplied HOME (not the failproofai home).
111
+ *
112
+ * `setup-state` and `onboarding-lock` take a `home` parameter purely so their
113
+ * tests can point at a temp directory, and a helper that silently ignored it
114
+ * would send those tests at the developer's real home — which is precisely the
115
+ * bug this overload exists to make impossible.
116
+ */
117
+ const atHome = (home: string | undefined, ...parts: string[]): string =>
118
+ home ? resolve(failproofaiHome(home), ...parts) : at(...parts);
119
+
120
+ // ── Top level ────────────────────────────────────────────────────────────────
121
+
122
+ /** Layout / CLI / daemon versions. Also the layout marker. */
123
+ export const versionFile = (home?: string) => atHome(home, "VERSION");
124
+
125
+ /** Non-secret configuration. World-readable by design; never holds a token. */
126
+ export const configFile = (home?: string) => atHome(home, "config.json");
127
+
128
+ /**
129
+ * Every credential, owner-only.
130
+ *
131
+ * Split from `config.toml` because that file is written with a bare
132
+ * `writeFileSync` and inherits the umask (0664 on a normal machine). A token
133
+ * there would be readable by every local user on the box — which is exactly
134
+ * why `ingest.json` and `cloud.json` were separate files before this.
135
+ */
136
+ export const credentialsFile = (home?: string) => atHome(home, "credentials.json");
137
+
138
+ // ── Daemon binaries ──────────────────────────────────────────────────────────
139
+
140
+ export const binDir = (home?: string) => atHome(home, "bin");
141
+
142
+ /**
143
+ * One file per version, never overwritten in place: an in-place write hits
144
+ * `ETXTBSY` against the running daemon on Linux, and would silently repoint a
145
+ * live service unit at a binary built from different source.
146
+ */
147
+ export const daemonBinary = (version: string, home?: string) =>
148
+ resolve(binDir(home), `failproofaid-${version}`);
149
+
150
+ // ── Policies ─────────────────────────────────────────────────────────────────
151
+
152
+ /**
153
+ * Where the user drops convention policies (`*.mjs`), loaded with no flag.
154
+ *
155
+ * Layout 3 made this the WHOLE meaning of the directory. It used to hold two
156
+ * subdirectories the user did not put there — `local-policies/` (our config)
157
+ * and `cloud-policies/` (the fleet's) — so "mine" and "not mine" shared a
158
+ * folder and nothing said which was which.
159
+ */
160
+ export const policiesDir = (home?: string) => atHome(home, "policies");
161
+
162
+ /** Convention policies ARE the policies directory now; kept as an alias. */
163
+ export const customPoliciesDir = policiesDir;
164
+
165
+ /**
166
+ * The builtin enable/disable set and per-policy params, GLOBAL scope only.
167
+ *
168
+ * At the root in layout 3. It is configuration, not a policy, and burying it
169
+ * two levels inside a directory users are told to drop files into put the one
170
+ * file they must not hand-edit among the ones they should.
171
+ */
172
+ export const globalPolicyConfigFile = (home?: string) =>
173
+ atHome(home, "policies-config.json");
174
+
175
+ /**
176
+ * Cloud-managed deployments: `active.json`, `desired-state.json`, and
177
+ * content-addressed `artifacts/`.
178
+ *
179
+ * A CHILD of `policies/`, so everything that is a policy lives under one
180
+ * directory and the home root stays readable — every policy on the machine is
181
+ * under `policies/`, whoever put it there.
182
+ *
183
+ * Safe to nest because the convention loader does not recurse:
184
+ * `discoverPolicyFiles()` and `findSkippedPolicyFiles()` both filter
185
+ * `isFile()`, so this directory is invisible to it. That is the property that
186
+ * makes the nesting safe rather than a coincidence — if either ever walks
187
+ * subdirectories, every cloud artifact becomes a convention policy loaded
188
+ * WITHOUT its digest being checked, which is the one path this whole module
189
+ * exists to prevent. `fp-home.test.ts` pins it.
190
+ *
191
+ * What is flat is the INSIDE of this directory: `artifacts/` holds every
192
+ * content-addressed policy for every deployment, and `active.json` names which
193
+ * of them is live. There is no `deployments/<n>/` tree — a per-deployment
194
+ * directory is one more moving part that has to be created, pruned and kept
195
+ * consistent with the manifest, and it bought nothing the digests did not
196
+ * already give.
197
+ */
198
+ export const cloudPoliciesDir = (home?: string) => resolve(policiesDir(home), "cloud-policies");
199
+
200
+ // ── Collector ────────────────────────────────────────────────────────────────
201
+
202
+ /** Per-source watermarks. One directory per source — never shared: the cursor
203
+ * store rewrites its whole map atomically, so two sources sharing a file
204
+ * clobber each other and the loser re-reads from zero after every restart. */
205
+ export const cursorsDir = (source?: string, home?: string) =>
206
+ source ? resolve(atHome(home, "cursors"), source) : atHome(home, "cursors");
207
+
208
+ /** The SDK spool root. Mirrors `~/.agenteye/`, which stays supported. */
209
+ export const customAgentsDir = (home?: string) => atHome(home, "custom-agents");
210
+ export const customAgentsEventsDir = (home?: string) => resolve(customAgentsDir(home), "events");
211
+ export const customAgentsFailedDir = (home?: string) => resolve(customAgentsDir(home), "failed");
212
+
213
+ // ── Audit ────────────────────────────────────────────────────────────────────
214
+
215
+ export const auditDir = (home?: string) => atHome(home, "audit");
216
+ export const auditDashboardFile = (home?: string) => resolve(auditDir(home), "dashboard.json");
217
+ export const auditCacheDir = (home?: string) => resolve(auditDir(home), "cache");
218
+
219
+ // ── Hook activity ────────────────────────────────────────────────────────────
220
+
221
+ /** The decision log: page-sized JSONL the dashboard's activity tab reads. */
222
+ export const hookActivityDir = (home?: string) => atHome(home, "hook-activity");
223
+
224
+ // ── Runtime ──────────────────────────────────────────────────────────────────
225
+
226
+ /** Sockets and the singleton flock. Shallow on purpose — see the header note. */
227
+ export const runDir = (home?: string) => atHome(home, "run");
228
+ export const daemonSocket = () =>
229
+ process.env.FAILPROOFAI_DAEMON_SOCKET || resolve(runDir(), "failproofaid.sock");
230
+ export const workerSocket = (home?: string) => resolve(runDir(home), "worker.sock");
231
+ export const daemonLock = (home?: string) => resolve(runDir(home), "failproofaid.lock");
232
+
233
+ /**
234
+ * Single-flight lock for the audit.
235
+ *
236
+ * Three separate processes can start one — a scheduled run, `failproofai
237
+ * audit`, and the dashboard's re-run — and all three write the same
238
+ * sha1-keyed cache files, so the lock has to be visible across processes.
239
+ * It sits in `run/` with the other runtime files rather than under `audit/`,
240
+ * which holds results a human might keep and a reset is expected to clear.
241
+ *
242
+ * NOT mirrored in `crates/failproofaid/src/paths.rs` yet: nothing in Rust
243
+ * takes this lock until the daemon grows its audit lane, and a `pub fn` no
244
+ * caller uses is a dead_code failure under `-D warnings`.
245
+ */
246
+ export const auditLockFile = (home?: string) => resolve(runDir(home), "audit.lock");
247
+
248
+ // ── Daemon scratch state ─────────────────────────────────────────────────────
249
+
250
+ /** Everything the daemon writes that a human would never open by hand. */
251
+ export const stateDir = (home?: string) => atHome(home, "state");
252
+ /**
253
+ * Where the policy loader writes its ESM shim.
254
+ *
255
+ * Under the user's own home rather than beside the installed package: that
256
+ * directory belongs to whoever installed failproofai, and on a system-wide
257
+ * install it is root-owned, which made every non-root hook fail to load
258
+ * cloud-managed and custom policies — silently, and open.
259
+ */
260
+ export const shimsDir = (home?: string) => resolve(stateDir(home), "shims");
261
+ export const spoolDir = (home?: string) => resolve(stateDir(home), "spool");
262
+ export const failedDir = (home?: string) => resolve(stateDir(home), "failed");
263
+ export const collectorHealthFile = (home?: string) => resolve(stateDir(home), "collector-health.json");
264
+ /** Per-session enforcement pauses, keyed by a hash of the session id. */
265
+ export const sessionPauseDir = () => resolve(stateDir(), "sessions");
266
+ /**
267
+ * When the scheduled audit last ran, and when the next one is due.
268
+ *
269
+ * The DAEMON is the sole writer (`crates/failproofaid/src/audit_lane.rs`, which
270
+ * mirrors this path in `paths.rs`) — it owns the schedule, and a second writer
271
+ * racing it could hand a machine two full scans back to back. Everything on this
272
+ * side reads it: the interval itself lives in `config.json`'s `audit` object,
273
+ * which a human edits, while this file is derived state a human never opens,
274
+ * which is why it sits under `state/` rather than beside the audit results.
275
+ */
276
+ export const auditScheduleFile = (home?: string) => resolve(stateDir(home), "audit-schedule.json");
277
+ /**
278
+ * The anonymous instance id this machine reports telemetry under.
279
+ *
280
+ * The mirror image of `auditScheduleFile()` above: here the CLI is the sole
281
+ * writer (`getInstanceId()` in `lib/telemetry-id.ts`, which persists whatever it
282
+ * resolved) and **failproofaid** only reads, through `telemetry_id_path()` in
283
+ * `crates/failproofaid/src/paths.rs`. The daemon cannot re-derive the value —
284
+ * `getInstanceId`'s middle tier hashes Node-formatted strings (`os.arch()` is
285
+ * `x64` where Rust says `x86_64`), and a near-miss there does not fail, it
286
+ * silently files one machine under two PostHog persons — so this file is how the
287
+ * two agree. Derived state a human never opens, hence `state/` rather than
288
+ * beside `config.json`.
289
+ */
290
+ export const telemetryIdFile = (home?: string) => resolve(stateDir(home), "telemetry-id");
291
+ export const launcherMarker = (home?: string) => resolve(stateDir(home), "launcher-configured");
292
+ /**
293
+ * The last first-run setup attempt that ABORTED, and why.
294
+ *
295
+ * Deliberately NOT one of `isConfigured()`'s signals: a failed attempt must
296
+ * never make a machine read as set up. It exists only so the next command can
297
+ * tell "never tried" from "tried and could not finish" — the wizard writes
298
+ * nothing on an abort, so without this the two are identical and setup
299
+ * relaunches on every single command forever.
300
+ *
301
+ * Under `state/` with the other derived markers a human never opens.
302
+ */
303
+ export const onboardingAttemptFile = (home?: string) =>
304
+ resolve(stateDir(home), "onboarding-attempt.json");
305
+ /**
306
+ * The version that last reported an install, so an upgrade is reported once.
307
+ *
308
+ * Under `state/` in layout 2 like every other piece of derived state, and that
309
+ * placement fixes a real bug rather than being tidiness: at the root it was
310
+ * `~/.failproofai/last-version`, which `detectLayout()` lists as a LAYOUT-1
311
+ * MARKER — while the code that writes it still runs under layout 2, and runs
312
+ * BEFORE the layout check. So on a genuinely fresh machine the CLI created the
313
+ * file, then immediately read it back as evidence of an old layout, classified
314
+ * a brand-new home as stale, and opened every new user's first command with
315
+ * "failproofai reorganised … Removed 1 item(s) from the old layout."
316
+ */
317
+ export const lastVersionFile = (home?: string) => resolve(stateDir(home), "last-version");
318
+ export const onboardingLockFile = (home?: string) => resolve(stateDir(home), "onboarding.lock");
319
+ export const codexSessionPathsFile = (home?: string) => resolve(stateDir(home), "codex-session-paths.json");
320
+
321
+ export const logsDir = (home?: string) => atHome(home, "logs");
322
+
323
+ // ── Migration state ──────────────────────────────────────────────────────────
324
+
325
+ /**
326
+ * Where a migration records what it did, and what it saved first.
327
+ *
328
+ * The migration CODE ships in the npm package, never here. A home written by
329
+ * 1.0.0 contains only 1.0.0's migrations, and the steps that get that machine
330
+ * forward are precisely the ones its old install never had — so the installed
331
+ * CLI, always the newest thing on the machine, is the only correct source. What
332
+ * belongs in the home is the STATE: which steps have run, and the files they
333
+ * saved before running. Exactly the split a database makes, where migrations are
334
+ * code in the repo and the applied set is a table.
335
+ */
336
+ export const migrationsDir = (home?: string) => atHome(home, "migrations");
337
+
338
+ /** One line per step that has run: `{from, to, cli, at, durationMs, ok}`. */
339
+ export const migrationLedgerFile = (home?: string) =>
340
+ resolve(migrationsDir(home), "applied.json");
341
+
342
+ /**
343
+ * Copies of the irreplaceable files, taken before the layout-`n` migration ran.
344
+ *
345
+ * NOT a copy of the whole home, and the reason is that `HOME_CLASSES` already
346
+ * made one unnecessary: a migration deletes only `derived` and `refetchable`
347
+ * paths, so there is no longer anything irreplaceable for it to lose by design.
348
+ * What remains worth insuring against is a BUG in a step — and for that, the few
349
+ * kilobytes of `config.json`, `credentials.json`, `policies-config.json`, the
350
+ * marker, and the retired layout's own config are a real undo, where a full-home
351
+ * copy would cost a duplicate of `bin/` and `hook-activity/` and need a
352
+ * two-rename window that also has to dodge a live daemon holding `run/`.
353
+ */
354
+ export const migrationBackupDir = (layout: number, home?: string) =>
355
+ resolve(migrationsDir(home), `backup-layout${layout}`);
356
+
357
+ // ── What each path HOLDS ─────────────────────────────────────────────────────
358
+
359
+ /**
360
+ * What kind of data a path in the home holds, which is what decides whether an
361
+ * upgrade may throw it away.
362
+ *
363
+ * The rule, stated once: **derived and re-fetchable may be dropped; anything a
364
+ * person typed, anything not yet delivered, and anything that identifies the
365
+ * machine is carried.**
366
+ */
367
+ export type DataClass =
368
+ /** A person set this and nothing regenerates it. Never deleted. */
369
+ | "user-typed"
370
+ /** Recorded here and not yet shipped anywhere. Never deleted. */
371
+ | "undelivered"
372
+ /** Stable ids and watermarks. Never deleted — a new one is a new machine. */
373
+ | "identity"
374
+ /** Rebuilt on demand. May be dropped. */
375
+ | "derived"
376
+ /** The server is the source of truth. May be dropped and re-fetched. */
377
+ | "refetchable"
378
+ /** Sockets, locks, binaries: live process state. Never touched by a reset. */
379
+ | "ephemeral";
380
+
381
+ /**
382
+ * Every path in the home, and what it holds.
383
+ *
384
+ * `resettablePaths()` is DERIVED from this rather than hand-listed beside it,
385
+ * and that is the whole point. Before this table one path was declared in four
386
+ * places — as a function above, again in `legacy` once it moved, again in the
387
+ * delete list, and again in `CARRIED_POLICY_CONFIG_KEYS` if it held carried
388
+ * keys — with nothing making the four agree. **Every silent-data-loss bug this
389
+ * module has had is one of those lists falling out of sync with a path that
390
+ * moved:** layout 1's `policies/` (hand-written source, deleted), layout 2's
391
+ * nested policy config (enabled policies, emptied), `cache/hook-activity` (the
392
+ * whole decision log, deleted with its parent), the layout-2 `credentials.toml`
393
+ * (a live token left behind), and `collector.sources.extra_paths` — which was
394
+ * on the delete list by way of `config.json` and would have taken every extra
395
+ * path a user typed at the next layout bump.
396
+ *
397
+ * Two consequences worth naming:
398
+ *
399
+ * - **Forgetting is now safe.** A path absent from this table is not deleted,
400
+ * because the delete list is a filter over what is here rather than a
401
+ * catch-all. The failure mode of an oversight becomes a stale file — loud
402
+ * and recoverable — instead of a deleted cloud token.
403
+ * - **`state/` is not classified as a whole**, because it is mixed: its
404
+ * `spool/` and `telemetry-id` are things we must never drop, and everything
405
+ * else under it is scratch. Listing the parent is exactly how a reset came
406
+ * to delete undelivered events and the machine's own telemetry identity.
407
+ *
408
+ * `home-classification.test.ts` asserts every exported path function in this
409
+ * module is either classified here or covered by a classified parent, so the
410
+ * next path added to the home cannot skip the one question that matters.
411
+ */
412
+ export const HOME_CLASSES: readonly { path: (home?: string) => string; class: DataClass }[] = [
413
+ // ── Never deleted: a person typed it ──
414
+ // The cloud enrolment. Deleting it drops the machine out of cloud-managed
415
+ // policy silently — it keeps enforcing whatever it last had, reports healthy,
416
+ // and never reconciles again. Nothing re-derives a token.
417
+ { path: credentialsFile, class: "user-typed" },
418
+ // Holds `daemon.configured` (the flag that makes the machine fail closed),
419
+ // the collector preferences, `[audit] auto`, the telemetry opt-out, and
420
+ // `collector.sources.*.extra_paths` — the entire output of `harness add-path`.
421
+ { path: configFile, class: "user-typed" },
422
+ // The builtin enable/disable set and per-policy params. `resetHome` used to
423
+ // clear this and carry eight named keys back over; it is simply kept now.
424
+ { path: globalPolicyConfigFile, class: "user-typed" },
425
+ // The user's own convention policies, the `lib/` they import and the data
426
+ // files they read. `at("policies")` was on the delete list once: hand-written
427
+ // source destroyed, while `isConfigured()` still read true so the wizard never
428
+ // re-asked and hooks kept firing against an empty policy set.
429
+ { path: policiesDir, class: "user-typed" },
430
+
431
+ // ── Never deleted: recorded and not yet shipped ──
432
+ // Batches read out of transcripts and queued for upload. The reason losing
433
+ // these is PERMANENT and not merely slow is `cursorsDir` below: the watermark
434
+ // has already advanced past them, so nothing will ever read that range again.
435
+ { path: spoolDir, class: "undelivered" },
436
+ { path: failedDir, class: "undelivered" },
437
+ // The SDK spool (`events/` + `failed/`), same argument.
438
+ { path: customAgentsDir, class: "undelivered" },
439
+ // The decision log the dashboard's activity tab reads. Neither derived nor
440
+ // re-fetchable: it is the record of what this machine did, and nothing
441
+ // regenerates it. Deleting its layout-1 parent threw away every decision a
442
+ // machine had recorded, which is why `migrateHookActivity()` exists.
443
+ { path: hookActivityDir, class: "undelivered" },
444
+ // Requests the CLI wrote for the daemon to drain on its next tick. The file's
445
+ // existence IS the pending state, so deleting one silently cancels something
446
+ // a person asked for. Rust-only paths (`crates/failproofaid/src/paths.rs`),
447
+ // hence spelled here rather than exported — nothing on this side reads them.
448
+ { path: (home) => resolve(stateDir(home), "flush-request.json"), class: "undelivered" },
449
+ { path: (home) => resolve(stateDir(home), "backfill-request.json"), class: "undelivered" },
450
+
451
+ // ── Never deleted: it names the machine ──
452
+ // Per-source watermarks. Kept out of the reset so pages carried by
453
+ // `migrateHookActivity()` are not re-shipped in full — it MOVES them, which
454
+ // preserves the inode a cursor is keyed on. A cursor whose file is gone is
455
+ // inert (`retain_existing` drops it), so keeping them costs nothing.
456
+ { path: cursorsDir, class: "identity" },
457
+ // The anonymous instance id both the CLI and the daemon report under. Tiers 1
458
+ // and 2 of `getInstanceId()` re-derive the same value, so most machines would
459
+ // survive losing it — but a machine that fell through to the daemon's own
460
+ // fallback would come back as a brand-new PostHog person, and no analysis
461
+ // spans that split.
462
+ { path: telemetryIdFile, class: "identity" },
463
+ { path: (home) => resolve(stateDir(home), "daemon-telemetry-id"), class: "identity" },
464
+ // The layout marker itself. Not user data, and `resetHome` rewrites it
465
+ // immediately — but listing it made a no-op reset report "removed 1 item" for
466
+ // a file it had just recreated.
467
+ { path: versionFile, class: "identity" },
468
+ // The record of what this machine has been migrated through, and the copies a
469
+ // step took before running. A migration deleting its own audit trail would
470
+ // leave "what has this home been through?" answerable only by guessing, and
471
+ // deleting the backup is deleting the undo for the step that just ran.
472
+ { path: migrationsDir, class: "identity" },
473
+
474
+ // ── May be dropped: rebuilt on demand ──
475
+ { path: auditDir, class: "derived" },
476
+ { path: collectorHealthFile, class: "derived" },
477
+ { path: auditScheduleFile, class: "derived" },
478
+ { path: codexSessionPathsFile, class: "derived" },
479
+ { path: shimsDir, class: "derived" },
480
+ { path: sessionPauseDir, class: "derived" },
481
+ { path: logsDir, class: "derived" },
482
+ { path: lastVersionFile, class: "derived" },
483
+ { path: launcherMarker, class: "derived" },
484
+ { path: onboardingLockFile, class: "derived" },
485
+ { path: onboardingAttemptFile, class: "derived" },
486
+
487
+ // ── May be dropped: the server has it ──
488
+ // Re-fetched and digest-verified on the next daemon poll. This is the whole
489
+ // reason the delete list is per-entry rather than `rm -rf policies/`: one
490
+ // directory holds both the files a person wrote and the ones the fleet sent,
491
+ // and only the second kind may be thrown away.
492
+ { path: cloudPoliciesDir, class: "refetchable" },
493
+
494
+ // ── Never touched ──
495
+ // A downloaded daemon binary is large, version-pinned and re-verified on use,
496
+ // so deleting it only forces a needless re-download.
497
+ { path: binDir, class: "ephemeral" },
498
+ // Sockets and the singleton flock belong to a process that may be alive right
499
+ // now; removing them breaks it rather than resetting configuration.
500
+ { path: runDir, class: "ephemeral" },
501
+ ];
502
+
503
+ // ── Layout 1 (legacy) ────────────────────────────────────────────────────────
504
+
505
+ /**
506
+ * Where layout 1 kept things.
507
+ *
508
+ * Retained ONLY so `detectLayout()` can recognise an old home and so the reset
509
+ * can delete it. Nothing reads data from these paths: the decision was
510
+ * wipe-and-re-setup rather than migrate, because a half-migrated home that
511
+ * silently reads "no data" is worse than one that says so.
512
+ */
513
+ export const legacy = {
514
+ /**
515
+ * Layout 1's policy config — at the home root.
516
+ *
517
+ * Layout 3 puts the CURRENT config back at this exact path, so this is not a
518
+ * discriminating landmark on its own. `detectLayout()` checks for a layout-2+
519
+ * marker before consulting it; see the comment there.
520
+ */
521
+ policyConfig: () => at("policies-config.json"),
522
+ /**
523
+ * Layout 2's `config.toml`. A landmark in its own right now: layout 1 had no
524
+ * such file, so its presence proves a home is newer than layout 1 even when
525
+ * `VERSION` is missing.
526
+ */
527
+ configToml: () => at("config.toml"),
528
+ /** Layout 2's credentials, replaced by `credentials.json`. */
529
+ credentialsToml: () => at("credentials.toml"),
530
+ /** Layout 2 nested the policy config two levels down. */
531
+ localPoliciesDir: () => at("policies", "local-policies"),
532
+ /**
533
+ * Layout 2's policy config, at its nested path.
534
+ *
535
+ * The file `readCarriedPolicyConfig()` reads and `localPoliciesDir()` above
536
+ * deletes — so on the layout-2 leg this, not `policyConfig()`, is the policy
537
+ * selection the migration destroys. Named separately because its BASENAME is
538
+ * identical to the layout-1 root copy's, and the backup directory is flat.
539
+ */
540
+ localPolicyConfig: () => at("policies", "local-policies", "policies-config.json"),
541
+ /** Layout 2 kept convention policies in a subdirectory. */
542
+ customPoliciesDir: () => at("policies", "custom-policies"),
543
+ // NO `cloudPoliciesDir` HERE. Layout 2 put cloud deployments at
544
+ // `policies/cloud-policies`, which is where layout 3 puts them too — so there
545
+ // is no old location to migrate from or prune, and an entry here would be a
546
+ // "legacy" path identical to the live one. That is not a harmless duplicate:
547
+ // it is exactly the shape that made `legacy.policyConfig()` unusable as a
548
+ // landmark, and anything treating this list as "safe to delete, it's old"
549
+ // would be deleting the current deployment. What DID change inside it is the
550
+ // shape — `deployments/<n>/` trees flattened into one `artifacts/` dir —
551
+ // which `cloud_policies.rs` prunes after the flip, not this list.
552
+ policyConfigLocal: () => at("policies-config.local.json"),
553
+ cloudCredentials: () => at("cloud.json"),
554
+ ingestCredentials: () => at("ingest.json"),
555
+ launcherMarker: () => at(".launcher-configured"),
556
+ lastVersion: () => at("last-version"),
557
+ auditDashboard: () => at("audit-dashboard.json"),
558
+ cacheDir: () => at("cache"),
559
+ hookActivityDir: () => at("cache", "hook-activity"),
560
+ auditCacheDir: () => at("cache", "audit"),
561
+ codexSessionPaths: () => at("cache", "codex-session-paths.json"),
562
+ spoolDir: () => at("spool"),
563
+ failedDir: () => at("failed"),
564
+ collectorHealth: () => at("collector-health.json"),
565
+ sessionPauseDir: () => at("state", "sessions"),
566
+ cloudManagedPolicies: () => at("policies", "cloud-managed"),
567
+ onboardingLock: () => at(".onboarding.lock"),
568
+ } as const;
569
+
570
+ /**
571
+ * Every path a reset must remove, in the order it should remove them.
572
+ *
573
+ * Enumerated rather than "delete the home directory" so a reset never takes
574
+ * out something a future layout adds and this list has not been taught about
575
+ * — and so the function is auditable at a glance, which matters for anything
576
+ * that deletes user data.
577
+ *
578
+ * TWO HALVES, and they are not maintained the same way. The paths of layouts
579
+ * that no longer exist are listed by hand below, because a retired path has no
580
+ * definition left to hang a class off — it exists only in this file. The paths
581
+ * of the CURRENT layout are DERIVED from `HOME_CLASSES`, so a path that moves
582
+ * or is added cannot silently fall off (or onto) the list. See `HOME_CLASSES`
583
+ * for what each class means and which incidents the split is answering.
584
+ */
585
+ export function resettablePaths(): string[] {
586
+ return [
587
+ ...retiredLayoutPaths(),
588
+ // The current layout, by what each path HOLDS. `user-typed`, `undelivered`
589
+ // and `identity` are absent from this list by construction rather than by
590
+ // anyone remembering to leave them out.
591
+ ...HOME_CLASSES.filter((e) => e.class === "derived" || e.class === "refetchable").map((e) =>
592
+ e.path(),
593
+ ),
594
+ ];
595
+ }
596
+
597
+ /**
598
+ * The paths of layouts this build no longer writes.
599
+ *
600
+ * Hand-listed, and they have to be: a retired path has no definition to carry a
601
+ * class, and `legacy` is the only place it still exists. Each entry is here
602
+ * because an upgrade would otherwise leave it behind — see the notes inline,
603
+ * every one of which records something that actually happened.
604
+ *
605
+ * Phase-splitting these per migration step is what the migration registry does
606
+ * with them next; until then they are one list because `resetHome` is one step.
607
+ */
608
+ function retiredLayoutPaths(): string[] {
609
+ return [
610
+ // Layout 1
611
+ //
612
+ // NOT `legacy.policyConfig()`. It is `at("policies-config.json")` — the
613
+ // EXACT path layout 3 puts the live config back at, which `legacy`'s own
614
+ // note records and `detectLayout()` has a whole ordering rule about. Listing
615
+ // it here while `HOME_CLASSES` calls the same path `user-typed` would have
616
+ // the two halves of this function contradict each other, and the delete
617
+ // would win.
618
+ //
619
+ // Leaving it in place is also strictly better than what it replaced. The old
620
+ // sequence was delete-then-carry-eight-named-keys, so every key outside
621
+ // `CARRIED_POLICY_CONFIG_KEYS` was dropped on a layout-1 upgrade; now the
622
+ // file is simply not touched and keeps everything. `readCarriedPolicyConfig`
623
+ // is narrowed to layout 2's NESTED copy accordingly — that path really is
624
+ // deleted (`legacy.localPoliciesDir()`, below) and really does need carrying.
625
+ //
626
+ // The project-scope `policies-config.local.json` is a different file at a
627
+ // different path (`{cwd}/.failproofai/`, see `hooks-config.ts`); the global
628
+ // one below is a layout-1 artefact nothing reads.
629
+ legacy.policyConfigLocal(),
630
+ legacy.cloudCredentials(),
631
+ legacy.ingestCredentials(),
632
+ legacy.launcherMarker(),
633
+ legacy.lastVersion(),
634
+ legacy.auditDashboard(),
635
+ // `legacy.cacheDir()` — the whole of `cache/` — stood here, and it CONTAINS
636
+ // `cache/hook-activity`: layout 1's decision log. Deleting the parent threw
637
+ // away every decision the machine had ever recorded, which is the data the
638
+ // dashboard's activity tab exists to show. Its children are now named
639
+ // individually so the log can be carried across by
640
+ // `migrateHookActivity()`, and everything else in `cache/` still goes —
641
+ // both remaining entries are re-derived on demand.
642
+ legacy.auditCacheDir(),
643
+ legacy.codexSessionPaths(),
644
+ legacy.spoolDir(),
645
+ legacy.failedDir(),
646
+ legacy.collectorHealth(),
647
+ legacy.onboardingLock(),
648
+ legacy.cloudManagedPolicies(),
649
+ // Layout 2's files, by their layout-2 names. Without these a layout-2 home
650
+ // upgrading to 3 keeps `config.toml` and `credentials.toml` sitting next to
651
+ // the new `.json` pair — two configs, one of them stale, and the reset that
652
+ // was supposed to clear the old layout leaving its most important files
653
+ // behind. `credentials.toml` is the worse half: a live token in a file
654
+ // nothing reads any more and nothing will clean up.
655
+ legacy.configToml(),
656
+ legacy.credentialsToml(),
657
+ legacy.localPoliciesDir(),
658
+ // NOT `legacy.customPoliciesDir()`. `migrateConventionPolicies()` empties it
659
+ // and removes it itself, and whatever it could NOT move is the user's own
660
+ // hand-written source — which this list would delete moments after that
661
+ // function deliberately decided to preserve it. That is not hypothetical:
662
+ // a `lib/` of helpers colliding with a stale `policies/lib/` was destroyed
663
+ // outright, and the policy that did move was left importing a file that no
664
+ // longer existed.
665
+ //
666
+ // Everything that used to follow here — `globalPolicyConfigFile()`,
667
+ // `cloudPoliciesDir()`, `at("state")`, `configFile()`, `credentialsFile()`,
668
+ // `auditDir()`, `customAgentsDir()`, `logsDir()` — was the CURRENT layout,
669
+ // hand-listed. It is derived from `HOME_CLASSES` now, and five of those
670
+ // entries stopped being deleted as a result, each for a reason recorded on
671
+ // its row: the cloud token, the whole of `config.json` (including the
672
+ // `extra_paths` a user typed), the undelivered spool, the SDK spool, and the
673
+ // machine's telemetry identity.
674
+ //
675
+ // `at("state")` is the sharpest of them. It is MIXED — `spool/` and
676
+ // `telemetry-id` sit under it beside a dozen scratch files — so listing the
677
+ // parent is precisely how a reset came to delete events that were recorded,
678
+ // queued, and then unreachable forever, because `cursors/` deliberately
679
+ // survives and the watermark had already moved past them. Its scratch
680
+ // children are classified individually now and the parent is not listed at
681
+ // all, so anything under it this table has not been taught about survives
682
+ // rather than being swept up.
683
+ //
684
+ // Two notes worth keeping from the old list, because they explain absences
685
+ // that still hold:
686
+ //
687
+ // `policies/` is `user-typed`, not absent by oversight. On layout 1 that
688
+ // directory IS the documented home for hand-written personal policies —
689
+ // `docs/configuration.mdx` names `~/.failproofai/policies/` as the user
690
+ // scope, and `manager.ts` read it. It stood on this list once: source files
691
+ // a person wrote, nothing regenerating them, nothing backing them up, and a
692
+ // reset message that named only "policy config, activity history and audit
693
+ // cache". Worse, the machine then reported itself configured —
694
+ // `isConfigured()` is a union that still sees the agent CLIs' untouched
695
+ // settings files — so the wizard was skipped and hooks kept firing against
696
+ // an empty policy set. Its `cloud-policies/` CHILD is `refetchable` and does
697
+ // still go, which is the whole reason this is a per-entry list and not
698
+ // `rm -rf policies/`.
699
+ //
700
+ // `cursors/` is `identity` for a reason load-bearing to the activity
701
+ // migration rather than a separate opinion. Cursors are keyed on
702
+ // `(device, inode)`; `migrateHookActivity()` MOVES pages, which preserves
703
+ // the inode, so a surviving cursor still points at the file it belongs to
704
+ // and resumes at the right offset. Delete the cursors and every carried page
705
+ // reads as new and re-ships in full — the outcome the move exists to avoid.
706
+ // A cursor whose file is gone is inert (`retain_existing` drops it), so
707
+ // keeping them costs nothing when there is nothing to resume.
708
+ //
709
+ // And `hook-activity/` is `undelivered`, never listed: it is the DESTINATION
710
+ // `migrateHookActivity()` moves layout 1's log into, so listing it deleted
711
+ // the migration moments after it happened — the reset runs every path in
712
+ // this list after the migrations.
713
+ ];
714
+ }