failproofai 1.0.0-beta.4 → 1.0.0-beta.6

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 (369) 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 +3 -3
  4. package/.next/standalone/.next/prerender-manifest.json +3 -3
  5. package/.next/standalone/.next/required-server-files.json +1 -1
  6. package/.next/standalone/.next/routes-manifest.json +6 -0
  7. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error/page.js +3 -1
  9. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  10. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  11. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  12. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  13. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  14. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  15. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
  16. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  17. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  18. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  19. package/.next/standalone/.next/server/app/_not-found/page.js +3 -1
  20. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  21. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  22. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  23. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  24. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  25. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  26. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
  27. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  28. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  29. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  30. package/.next/standalone/.next/server/app/api/audit/invite/route.js +3 -2
  31. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/api/audit/run/route.js +4 -3
  33. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/api/audit/status/route.js +1 -1
  35. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/api/auth/login-request/route.js +2 -1
  37. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  38. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +3 -2
  39. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/api/auth/logout/route.js +3 -2
  41. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  42. package/.next/standalone/.next/server/app/api/auth/reminder/route.js +3 -2
  43. package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/api/auth/status/route.js +3 -2
  45. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  46. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js +1 -1
  47. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  49. package/.next/standalone/.next/server/app/audit/page.js +5 -3
  50. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  51. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  52. package/.next/standalone/.next/server/app/index.html +1 -1
  53. package/.next/standalone/.next/server/app/index.rsc +15 -15
  54. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  55. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  56. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  57. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
  58. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  59. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  60. package/.next/standalone/.next/server/app/page.js +3 -1
  61. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  62. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  63. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +10 -10
  64. package/.next/standalone/.next/server/app/policies/page.js +4 -2
  65. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  66. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  67. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  68. package/.next/standalone/.next/server/app/project/[name]/page.js +4 -2
  69. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  70. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  71. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  72. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  73. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +6 -4
  74. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  75. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  76. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  77. package/.next/standalone/.next/server/app/projects/page.js +4 -2
  78. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  79. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  80. package/.next/standalone/.next/server/app/settings/page/app-paths-manifest.json +3 -0
  81. package/.next/standalone/.next/server/app/settings/page/build-manifest.json +18 -0
  82. package/.next/standalone/.next/server/app/settings/page/next-font-manifest.json +6 -0
  83. package/.next/standalone/.next/server/app/settings/page/react-loadable-manifest.json +1 -0
  84. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +53 -0
  85. package/.next/standalone/.next/server/app/settings/page.js +18 -0
  86. package/.next/standalone/.next/server/app/settings/page.js.map +5 -0
  87. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -0
  88. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +3 -0
  89. package/.next/standalone/.next/server/app-paths-manifest.json +2 -1
  90. package/.next/standalone/.next/server/chunks/{[externals]__1nl3dvw._.js → [externals]__0r-zamh._.js} +2 -2
  91. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06hexd0._.js +3 -0
  92. package/.next/standalone/.next/server/chunks/[root-of-the-server]__094p1f1._.js +3 -0
  93. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_0xu5z._.js +1 -1
  94. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ed01_d._.js +3 -0
  95. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0g0vcwt._.js +3 -0
  96. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0h3lfmp._.js → [root-of-the-server]__0ky_n0r._.js} +2 -2
  97. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__18d-9oi._.js → [root-of-the-server]__0lk_935._.js} +2 -2
  98. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1p7s8-d._.js → [root-of-the-server]__0pbp9fe._.js} +2 -2
  99. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q-v9z2._.js +1 -1
  100. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__10oa-v9._.js → [root-of-the-server]__0v2fpxe._.js} +2 -2
  101. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0sb_5m8._.js → [root-of-the-server]__131ebum._.js} +3 -3
  102. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0-dh5jy._.js → [root-of-the-server]__1_ps0jw._.js} +2 -2
  103. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0l4vuqm._.js → [root-of-the-server]__1a7i2q4._.js} +1 -1
  104. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ibjy5x._.js +3 -0
  105. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1iny24d._.js +3 -0
  106. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tvn4wf._.js +1 -1
  107. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tyedjt._.js +3 -0
  108. package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +5 -0
  109. package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +5 -0
  110. package/.next/standalone/.next/server/chunks/lib_telemetry_ts_0dctyyw._.js +5 -0
  111. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +5 -5
  112. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  113. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__06bp_fg._.js +5 -0
  114. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__074qmkp._.js +3 -0
  115. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0spkm68._.js +10 -10
  116. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1_a_gwn._.js +3 -0
  117. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1a2hcb_._.js +3 -0
  118. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1e7-pa7._.js +3 -0
  119. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0rtdfof._.js → [root-of-the-server]__1rdruw4._.js} +1 -1
  120. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1rv-sc9._.js +3 -0
  121. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1tyf0tc._.js +5 -0
  122. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1u-wx42._.js +4 -0
  123. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1v185mo._.js +3 -0
  124. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0rag5dg._.js → [root-of-the-server]__1yw368c._.js} +2 -2
  125. package/.next/standalone/.next/server/chunks/ssr/_0-yi74u._.js +3 -0
  126. package/.next/standalone/.next/server/chunks/ssr/_04mekdy._.js +3 -0
  127. package/.next/standalone/.next/server/chunks/ssr/_0igtyj5._.js +3 -0
  128. package/.next/standalone/.next/server/chunks/ssr/_0r-dsre._.js +3 -0
  129. package/.next/standalone/.next/server/chunks/ssr/_0rjgfln._.js +3 -0
  130. package/.next/standalone/.next/server/chunks/ssr/_0se484m._.js +3 -0
  131. package/.next/standalone/.next/server/chunks/ssr/_0uz7o9y._.js +3 -0
  132. package/.next/standalone/.next/server/chunks/ssr/_11_p9y8._.js +1 -1
  133. package/.next/standalone/.next/server/chunks/ssr/_1fahg9e._.js +3 -0
  134. package/.next/standalone/.next/server/chunks/ssr/_1gmzkwj._.js +5 -0
  135. package/.next/standalone/.next/server/chunks/ssr/_1w8sola._.js +3 -0
  136. package/.next/standalone/.next/server/chunks/ssr/_1w_6p9g._.js +3 -0
  137. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +2 -2
  138. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  139. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
  140. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0dwo94s.js +4 -0
  141. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +3 -0
  142. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +5 -0
  143. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  144. package/.next/standalone/.next/server/middleware.js +2 -2
  145. package/.next/standalone/.next/server/pages/404.html +1 -1
  146. package/.next/standalone/.next/server/pages/500.html +1 -1
  147. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  148. package/.next/standalone/.next/server/server-reference-manifest.json +54 -12
  149. package/.next/standalone/.next/static/chunks/{2c90h1g6x8z8y.js → 0_2n13i94rnw5.js} +1 -1
  150. package/.next/standalone/.next/static/chunks/1bm0q12hgs22l.css +2 -0
  151. package/.next/standalone/.next/static/chunks/1v1gqvpjk62jm.js +1 -0
  152. package/.next/standalone/.next/static/chunks/23557z4e6dtsr.js +1 -0
  153. package/.next/standalone/.next/static/chunks/28zkwzu50puki.js +1 -0
  154. package/.next/standalone/.next/static/chunks/2uvhw57mf9lg_.css +2 -0
  155. package/.next/standalone/.next/static/chunks/3081gykdubv8b.js +1 -0
  156. package/.next/standalone/.next/static/chunks/{06jakt_xhoolk.js → 34fa65k0cldkj.js} +1 -1
  157. package/.next/standalone/.next/static/chunks/35v07j9gc1pvr.js +6 -0
  158. package/.next/standalone/.next/static/chunks/{2zb3m1tzq6h98.js → 3f_939wi3kfnx.js} +22 -22
  159. package/.next/standalone/.next/static/chunks/{31cqiv_cpgj9m.js → 3p1vpm2_-tfwm.js} +1 -1
  160. package/.next/standalone/.next/static/chunks/{0ue9ak_xexiqh.js → 3rbpw_waieafm.js} +1 -1
  161. package/.next/standalone/.next/static/chunks/40ffnfpkeyvb0.js +1 -0
  162. package/.next/standalone/app/actions/get-hooks-config.ts +2 -1
  163. package/.next/standalone/app/actions/get-scheduled-audit.ts +70 -0
  164. package/.next/standalone/app/actions/update-scheduled-audit.ts +44 -0
  165. package/.next/standalone/app/api/audit/run/route.ts +28 -0
  166. package/.next/standalone/app/api/audit/status/route.ts +13 -1
  167. package/.next/standalone/app/api/auth/status/route.ts +1 -1
  168. package/.next/standalone/app/audit/_components/auth-dialog.css +159 -0
  169. package/.next/standalone/app/audit/_components/auth-dialog.tsx +3 -0
  170. package/.next/standalone/app/audit/audit-styles.css +6 -149
  171. package/.next/standalone/app/settings/page.tsx +31 -0
  172. package/.next/standalone/app/settings/settings-client.tsx +488 -0
  173. package/.next/standalone/components/navbar.tsx +2 -0
  174. package/.next/standalone/lib/auth/api-server-client.ts +2 -3
  175. package/.next/standalone/lib/auth/auth-store.ts +4 -4
  176. package/.next/standalone/lib/codex-sessions.ts +2 -1
  177. package/.next/standalone/lib/dashboard-host.ts +101 -0
  178. package/.next/standalone/lib/install-check.ts +22 -7
  179. package/.next/standalone/lib/pi-sessions.ts +99 -14
  180. package/.next/standalone/lib/telemetry-enabled.ts +54 -0
  181. package/.next/standalone/lib/telemetry-id.ts +52 -1
  182. package/.next/standalone/lib/telemetry.ts +8 -4
  183. package/.next/standalone/node_modules/react/cjs/react.development.js +1 -1
  184. package/.next/standalone/node_modules/react/cjs/react.production.js +1 -1
  185. package/.next/standalone/node_modules/react/package.json +3 -3
  186. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.browser.production.js +1 -1
  187. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server-legacy.node.production.js +1 -1
  188. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.browser.production.js +3 -3
  189. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.edge.production.js +3 -3
  190. package/.next/standalone/node_modules/react-dom/cjs/react-dom-server.node.production.js +3 -3
  191. package/.next/standalone/node_modules/react-dom/cjs/react-dom.production.js +1 -1
  192. package/.next/standalone/node_modules/react-dom/package.json +4 -4
  193. package/.next/standalone/package.json +7 -6
  194. package/.next/standalone/proxy.ts +89 -1
  195. package/.next/standalone/server.js +1 -1
  196. package/bin/failproofai.mjs +197 -80
  197. package/dist/cli.mjs +17699 -15345
  198. package/dist/worker.mjs +1620 -257
  199. package/lib/auth/api-server-client.ts +2 -3
  200. package/lib/auth/auth-store.ts +4 -4
  201. package/lib/codex-sessions.ts +2 -1
  202. package/lib/dashboard-host.ts +101 -0
  203. package/lib/install-check.ts +22 -7
  204. package/lib/pi-sessions.ts +99 -14
  205. package/lib/telemetry-enabled.ts +54 -0
  206. package/lib/telemetry-id.ts +52 -1
  207. package/lib/telemetry.ts +8 -4
  208. package/package.json +7 -6
  209. package/scripts/install-telemetry.mjs +8 -1
  210. package/scripts/launch.ts +25 -3
  211. package/scripts/parse-script-args.ts +17 -1
  212. package/scripts/prune-standalone.mjs +20 -0
  213. package/scripts/translate-docs/readme-translator.ts +163 -4
  214. package/scripts/validate-mdx.ts +153 -13
  215. package/src/audit/audit-lock.ts +285 -0
  216. package/src/audit/audit-schedule.ts +111 -0
  217. package/src/audit/cache.ts +18 -4
  218. package/src/audit/cli-adapters/goose.ts +2 -1
  219. package/src/audit/cli-adapters/hermes.ts +28 -10
  220. package/src/audit/cli.ts +191 -35
  221. package/src/audit/dashboard-cache.ts +2 -1
  222. package/src/hooks/builtin-policies.ts +100 -3
  223. package/src/hooks/cloud-connection.ts +163 -14
  224. package/src/hooks/cloud-enrollment-cli.ts +119 -21
  225. package/src/hooks/cloud-enrollment.ts +87 -17
  226. package/src/hooks/cloud-introspect.ts +147 -0
  227. package/src/hooks/cloud-managed-policies.ts +33 -2
  228. package/src/hooks/collector-config.ts +32 -40
  229. package/src/hooks/configure-wizard.ts +696 -318
  230. package/src/hooks/custom-hooks-loader.ts +125 -11
  231. package/src/hooks/daemon-client.ts +83 -17
  232. package/src/hooks/daemon-download.ts +54 -2
  233. package/src/hooks/daemon-service.ts +595 -27
  234. package/src/hooks/first-run-gate.ts +39 -0
  235. package/src/hooks/fp-config.ts +497 -0
  236. package/src/hooks/fp-home.ts +342 -0
  237. package/src/hooks/fp-reset.ts +332 -0
  238. package/src/hooks/handler.ts +42 -1
  239. package/src/hooks/hook-activity-store.ts +35 -20
  240. package/src/hooks/hook-logger.ts +2 -1
  241. package/src/hooks/hook-telemetry.ts +5 -1
  242. package/src/hooks/hooks-config.ts +4 -3
  243. package/src/hooks/loader-utils.ts +166 -5
  244. package/src/hooks/manager.ts +5 -4
  245. package/src/hooks/onboarding-lock.ts +119 -0
  246. package/src/hooks/policy-types.ts +0 -7
  247. package/src/hooks/session-pause-cli.ts +15 -13
  248. package/src/hooks/session-pause.ts +36 -4
  249. package/src/hooks/setup-state.ts +256 -0
  250. package/src/hooks/tui.ts +4 -4
  251. package/src/hooks/worker-server.ts +53 -1
  252. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0f8nu8d._.js +0 -3
  253. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0szqzl8._.js +0 -3
  254. package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +0 -3
  255. package/.next/standalone/.next/server/chunks/[root-of-the-server]__19120tr._.js +0 -3
  256. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1fwl2mz._.js +0 -3
  257. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1myjm-d._.js +0 -3
  258. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1rhmvod._.js +0 -3
  259. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02r5bgf._.js +0 -4
  260. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0cmdyn_._.js +0 -3
  261. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e8sjqm._.js +0 -4
  262. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0lkzqax._.js +0 -4
  263. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ls0gsr._.js +0 -4
  264. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n_uvv0._.js +0 -3
  265. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qucxyj._.js +0 -4
  266. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0sdrz-j._.js +0 -3
  267. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0u02miy._.js +0 -4
  268. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__14dd6h8._.js +0 -3
  269. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1j4u3yd._.js +0 -4
  270. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1zqz4v8._.js +0 -4
  271. package/.next/standalone/.next/server/chunks/ssr/_1m_p7pi._.js +0 -3
  272. package/.next/standalone/.next/server/chunks/ssr/node_modules_html-to-image_es_index_1q9xxca.js +0 -3
  273. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1ezd2jf._.js +0 -5
  274. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1tnuifj._.js +0 -5
  275. package/.next/standalone/.next/static/chunks/0h7auy7hzjyhw.js +0 -1
  276. package/.next/standalone/.next/static/chunks/0oe2-hp0_2tzs.js +0 -6
  277. package/.next/standalone/.next/static/chunks/1fw3pxobk_otl.js +0 -1
  278. package/.next/standalone/.next/static/chunks/3h5_3u46gu9jx.js +0 -1
  279. package/.next/standalone/.next/static/chunks/3i27c3hcriawq.css +0 -1
  280. package/.next/standalone/.next/static/chunks/3zdwnnthucs_1.css +0 -2
  281. package/.next/standalone/.next/static/chunks/43a1ywqsg9bq9.js +0 -1
  282. package/.next/standalone/Cargo.lock +0 -2222
  283. package/.next/standalone/Cargo.toml +0 -9
  284. package/.next/standalone/crates/CLOUD_POLICIES.md +0 -136
  285. package/.next/standalone/crates/PROTOCOL.md +0 -122
  286. package/.next/standalone/crates/failproofaid/Cargo.toml +0 -25
  287. package/.next/standalone/crates/failproofaid/src/cloud_client.rs +0 -484
  288. package/.next/standalone/crates/failproofaid/src/cloud_policies.rs +0 -921
  289. package/.next/standalone/crates/failproofaid/src/lock.rs +0 -81
  290. package/.next/standalone/crates/failproofaid/src/main.rs +0 -532
  291. package/.next/standalone/crates/failproofaid/src/paths.rs +0 -201
  292. package/.next/standalone/crates/failproofaid/src/server.rs +0 -502
  293. package/.next/standalone/crates/failproofaid/src/worker.rs +0 -400
  294. package/.next/standalone/crates/failproofaid/tests/daemon_e2e.rs +0 -241
  295. package/.next/standalone/crates/fpai-collect/Cargo.toml +0 -43
  296. package/.next/standalone/crates/fpai-collect/src/config.rs +0 -412
  297. package/.next/standalone/crates/fpai-collect/src/cursor.rs +0 -520
  298. package/.next/standalone/crates/fpai-collect/src/delivery.rs +0 -472
  299. package/.next/standalone/crates/fpai-collect/src/filetail.rs +0 -484
  300. package/.next/standalone/crates/fpai-collect/src/health.rs +0 -369
  301. package/.next/standalone/crates/fpai-collect/src/lib.rs +0 -34
  302. package/.next/standalone/crates/fpai-collect/src/redact.rs +0 -516
  303. package/.next/standalone/crates/fpai-collect/src/sources/claude/mod.rs +0 -279
  304. package/.next/standalone/crates/fpai-collect/src/sources/claude/transform.rs +0 -619
  305. package/.next/standalone/crates/fpai-collect/src/sources/codex/mod.rs +0 -156
  306. package/.next/standalone/crates/fpai-collect/src/sources/codex/transform.rs +0 -715
  307. package/.next/standalone/crates/fpai-collect/src/sources/copilot/mod.rs +0 -158
  308. package/.next/standalone/crates/fpai-collect/src/sources/copilot/transform.rs +0 -512
  309. package/.next/standalone/crates/fpai-collect/src/sources/goose/mod.rs +0 -511
  310. package/.next/standalone/crates/fpai-collect/src/sources/goose/transform.rs +0 -586
  311. package/.next/standalone/crates/fpai-collect/src/sources/hermes/mod.rs +0 -318
  312. package/.next/standalone/crates/fpai-collect/src/sources/hermes/transform.rs +0 -579
  313. package/.next/standalone/crates/fpai-collect/src/sources/hooks/mod.rs +0 -310
  314. package/.next/standalone/crates/fpai-collect/src/sources/hooks/transform.rs +0 -448
  315. package/.next/standalone/crates/fpai-collect/src/sources/mod.rs +0 -23
  316. package/.next/standalone/crates/fpai-collect/src/sources/openclaw/mod.rs +0 -176
  317. package/.next/standalone/crates/fpai-collect/src/sources/openclaw/transform.rs +0 -500
  318. package/.next/standalone/crates/fpai-collect/src/sources/opencode/mod.rs +0 -315
  319. package/.next/standalone/crates/fpai-collect/src/sources/opencode/transform.rs +0 -493
  320. package/.next/standalone/crates/fpai-collect/src/sources/pi/mod.rs +0 -201
  321. package/.next/standalone/crates/fpai-collect/src/sources/pi/transform.rs +0 -533
  322. package/.next/standalone/crates/fpai-collect/src/spool.rs +0 -458
  323. package/.next/standalone/crates/fpai-collect/src/sqlitepoll.rs +0 -387
  324. package/.next/standalone/crates/fpai-collect/src/supervisor.rs +0 -423
  325. package/.next/standalone/crates/fpai-collect/src/uploader.rs +0 -600
  326. package/.next/standalone/crates/fpai-collect/tests/claude_source.rs +0 -738
  327. package/.next/standalone/crates/fpai-collect/tests/claude_subagents.rs +0 -393
  328. package/.next/standalone/crates/fpai-collect/tests/codex_source.rs +0 -975
  329. package/.next/standalone/crates/fpai-collect/tests/config.rs +0 -286
  330. package/.next/standalone/crates/fpai-collect/tests/copilot_source.rs +0 -1019
  331. package/.next/standalone/crates/fpai-collect/tests/delivery.rs +0 -281
  332. package/.next/standalone/crates/fpai-collect/tests/goose_source.rs +0 -1008
  333. package/.next/standalone/crates/fpai-collect/tests/hermes_source.rs +0 -1129
  334. package/.next/standalone/crates/fpai-collect/tests/hooks_source.rs +0 -621
  335. package/.next/standalone/crates/fpai-collect/tests/openclaw_source.rs +0 -854
  336. package/.next/standalone/crates/fpai-collect/tests/opencode_source.rs +0 -1478
  337. package/.next/standalone/crates/fpai-collect/tests/pi_source.rs +0 -1191
  338. package/.next/standalone/crates/fpai-collect/tests/supervisor.rs +0 -290
  339. package/.next/standalone/crates/fpai-collect/tests/uploader.rs +0 -506
  340. package/.next/standalone/crates/fpai-ipc/Cargo.toml +0 -16
  341. package/.next/standalone/crates/fpai-ipc/src/envelope.rs +0 -175
  342. package/.next/standalone/crates/fpai-ipc/src/framing.rs +0 -177
  343. package/.next/standalone/crates/fpai-ipc/src/lib.rs +0 -10
  344. package/.next/standalone/crates/fpai-ipc/src/peer.rs +0 -80
  345. package/.next/standalone/docker-hook-sync/Dockerfile +0 -79
  346. package/.next/standalone/docker-hook-sync/entrypoint.sh +0 -109
  347. package/.next/standalone/integration-suite/Dockerfile +0 -47
  348. package/.next/standalone/integration-suite/README.md +0 -129
  349. package/.next/standalone/integration-suite/canary-policies.mjs +0 -45
  350. package/.next/standalone/integration-suite/capture-tokens.sh +0 -48
  351. package/.next/standalone/integration-suite/ci-entrypoint.sh +0 -179
  352. package/.next/standalone/integration-suite/inject-tokens.sh +0 -44
  353. package/.next/standalone/integration-suite/install-clis.sh +0 -136
  354. package/.next/standalone/integration-suite/probe-cli.sh +0 -248
  355. package/.next/standalone/integration-suite/report.js +0 -120
  356. package/.next/standalone/integration-suite/run.sh +0 -159
  357. package/.next/standalone/openclaw-plugin/index.js +0 -223
  358. package/.next/standalone/openclaw-plugin/openclaw.plugin.json +0 -6
  359. package/.next/standalone/openclaw-plugin/package.json +0 -12
  360. package/.next/standalone/osv-scanner.toml +0 -17
  361. package/.next/standalone/pi-extension/index.ts +0 -524
  362. package/.next/standalone/pi-extension/package.json +0 -12
  363. package/.next/standalone/postcss.config.mjs +0 -8
  364. package/.next/standalone/readme-arch-hq.gif +0 -0
  365. package/.next/standalone/rust-toolchain.toml +0 -4
  366. package/src/auth/cli.ts +0 -371
  367. /package/.next/standalone/.next/static/{StV6Lay7Q1cU4ysYCFJmH → Ptn8aBQl_cnNgOd0ebyv0}/_buildManifest.js +0 -0
  368. /package/.next/standalone/.next/static/{StV6Lay7Q1cU4ysYCFJmH → Ptn8aBQl_cnNgOd0ebyv0}/_clientMiddlewareManifest.js +0 -0
  369. /package/.next/standalone/.next/static/{StV6Lay7Q1cU4ysYCFJmH → Ptn8aBQl_cnNgOd0ebyv0}/_ssgManifest.js +0 -0
@@ -0,0 +1,342 @@
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 2
26
+ *
27
+ * ```
28
+ * ~/.failproofai/
29
+ * VERSION layout / cli / daemon versions
30
+ * config.toml 0644 non-secret: mode, daemon, collector prefs
31
+ * credentials.toml 0600 every token
32
+ * bin/ downloaded daemon binaries, one per version
33
+ * policies/
34
+ * local-policies/ the builtin enable/disable set
35
+ * cloud-policies/ content-addressed artifacts + active generation
36
+ * custom-policies/ user convention policies (*.mjs)
37
+ * cursors/<source>/ per-source collector watermarks
38
+ * audit/ audit report + per-session cache
39
+ * hook-activity/ decision log the dashboard reads
40
+ * custom-agents/ SDK spool (events/ + failed/)
41
+ * run/ sockets + flock — MUST stay shallow, see below
42
+ * state/ daemon scratch: spool, failed, health, pauses, shims
43
+ * ```
44
+ *
45
+ * **`run/` is deliberately NOT under `state/`.** A Unix socket path must fit
46
+ * in `sockaddr_un.sun_path` (~108 bytes) and we have hit that ceiling twice
47
+ * already during development. Every directory level spends part of a budget
48
+ * that a long `$HOME` has already eaten into, so the socket stays as close to
49
+ * the root as it can.
50
+ *
51
+ * ## Project scope is NOT here
52
+ *
53
+ * `<project>/.failproofai/` keeps its old shape — `policies-config.json` and
54
+ * `policies/*.mjs` at the top. Those files are committed to users' git repos,
55
+ * so reorganising them would rewrite history in every repo that adopted
56
+ * failproofai. `hooks-config.ts` still owns those paths.
57
+ */
58
+ import { homedir } from "node:os";
59
+ import { resolve } from "node:path";
60
+
61
+ /**
62
+ * The on-disk layout this build speaks.
63
+ *
64
+ * Bumped whenever a path in this file moves. Recorded in `VERSION`, and what
65
+ * `detectLayout()` compares against — a home written by a different layout is
66
+ * refused rather than half-read, because reading a moved directory silently
67
+ * yields "no data" instead of an error.
68
+ *
69
+ * 1 — the original flat/`cache`-based layout, through 1.0.0-beta.5.
70
+ * 2 — this file.
71
+ */
72
+ export const LAYOUT_VERSION = 2;
73
+
74
+ /**
75
+ * `~/.failproofai`, or `FAILPROOFAI_HOME`.
76
+ *
77
+ * The override is load-bearing for tests and containers: everything below is
78
+ * derived from it, so pointing it elsewhere relocates the entire layout
79
+ * atomically rather than per-path.
80
+ */
81
+ export function failproofaiHome(home?: string): string {
82
+ if (home) return resolve(home, ".failproofai");
83
+ return process.env.FAILPROOFAI_HOME || resolve(homedir(), ".failproofai");
84
+ }
85
+
86
+ const at = (...parts: string[]): string => resolve(failproofaiHome(), ...parts);
87
+
88
+ /**
89
+ * Same, against an explicitly supplied HOME (not the failproofai home).
90
+ *
91
+ * `setup-state` and `onboarding-lock` take a `home` parameter purely so their
92
+ * tests can point at a temp directory, and a helper that silently ignored it
93
+ * would send those tests at the developer's real home — which is precisely the
94
+ * bug this overload exists to make impossible.
95
+ */
96
+ const atHome = (home: string | undefined, ...parts: string[]): string =>
97
+ home ? resolve(failproofaiHome(home), ...parts) : at(...parts);
98
+
99
+ // ── Top level ────────────────────────────────────────────────────────────────
100
+
101
+ /** Layout / CLI / daemon versions. Also the layout marker. */
102
+ export const versionFile = (home?: string) => atHome(home, "VERSION");
103
+
104
+ /** Non-secret configuration. World-readable by design; never holds a token. */
105
+ export const configFile = (home?: string) => atHome(home, "config.toml");
106
+
107
+ /**
108
+ * Every credential, owner-only.
109
+ *
110
+ * Split from `config.toml` because that file is written with a bare
111
+ * `writeFileSync` and inherits the umask (0664 on a normal machine). A token
112
+ * there would be readable by every local user on the box — which is exactly
113
+ * why `ingest.json` and `cloud.json` were separate files before this.
114
+ */
115
+ export const credentialsFile = (home?: string) => atHome(home, "credentials.toml");
116
+
117
+ // ── Daemon binaries ──────────────────────────────────────────────────────────
118
+
119
+ export const binDir = (home?: string) => atHome(home, "bin");
120
+
121
+ /**
122
+ * One file per version, never overwritten in place: an in-place write hits
123
+ * `ETXTBSY` against the running daemon on Linux, and would silently repoint a
124
+ * live service unit at a binary built from different source.
125
+ */
126
+ export const daemonBinary = (version: string, home?: string) =>
127
+ resolve(binDir(home), `failproofaid-${version}`);
128
+
129
+ // ── Policies ─────────────────────────────────────────────────────────────────
130
+
131
+ export const policiesDir = (home?: string) => atHome(home, "policies");
132
+
133
+ /** The builtin enable/disable set and per-policy params, GLOBAL scope only. */
134
+ export const localPoliciesDir = (home?: string) => atHome(home, "policies", "local-policies");
135
+ export const globalPolicyConfigFile = (home?: string) =>
136
+ resolve(localPoliciesDir(home), "policies-config.json");
137
+
138
+ /** Cloud-managed generations: `active.json` plus content-addressed artifacts. */
139
+ export const cloudPoliciesDir = (home?: string) => resolve(policiesDir(home), "cloud-policies");
140
+
141
+ /** User convention policies (`*.mjs`) that load without any flag. */
142
+ export const customPoliciesDir = (home?: string) => resolve(policiesDir(home), "custom-policies");
143
+
144
+ // ── Collector ────────────────────────────────────────────────────────────────
145
+
146
+ /** Per-source watermarks. One directory per source — never shared: the cursor
147
+ * store rewrites its whole map atomically, so two sources sharing a file
148
+ * clobber each other and the loser re-reads from zero after every restart. */
149
+ export const cursorsDir = (source?: string, home?: string) =>
150
+ source ? resolve(atHome(home, "cursors"), source) : atHome(home, "cursors");
151
+
152
+ /** The SDK spool root. Mirrors `~/.agenteye/`, which stays supported. */
153
+ export const customAgentsDir = (home?: string) => atHome(home, "custom-agents");
154
+ export const customAgentsEventsDir = (home?: string) => resolve(customAgentsDir(home), "events");
155
+ export const customAgentsFailedDir = (home?: string) => resolve(customAgentsDir(home), "failed");
156
+
157
+ // ── Audit ────────────────────────────────────────────────────────────────────
158
+
159
+ export const auditDir = (home?: string) => atHome(home, "audit");
160
+ export const auditDashboardFile = (home?: string) => resolve(auditDir(home), "dashboard.json");
161
+ export const auditCacheDir = (home?: string) => resolve(auditDir(home), "cache");
162
+
163
+ // ── Hook activity ────────────────────────────────────────────────────────────
164
+
165
+ /** The decision log: page-sized JSONL the dashboard's activity tab reads. */
166
+ export const hookActivityDir = (home?: string) => atHome(home, "hook-activity");
167
+
168
+ // ── Runtime ──────────────────────────────────────────────────────────────────
169
+
170
+ /** Sockets and the singleton flock. Shallow on purpose — see the header note. */
171
+ export const runDir = (home?: string) => atHome(home, "run");
172
+ export const daemonSocket = () =>
173
+ process.env.FAILPROOFAI_DAEMON_SOCKET || resolve(runDir(), "failproofaid.sock");
174
+ export const workerSocket = (home?: string) => resolve(runDir(home), "worker.sock");
175
+ export const daemonLock = (home?: string) => resolve(runDir(home), "failproofaid.lock");
176
+
177
+ /**
178
+ * Single-flight lock for the audit.
179
+ *
180
+ * Three separate processes can start one — a scheduled run, `failproofai
181
+ * audit`, and the dashboard's re-run — and all three write the same
182
+ * sha1-keyed cache files, so the lock has to be visible across processes.
183
+ * It sits in `run/` with the other runtime files rather than under `audit/`,
184
+ * which holds results a human might keep and a reset is expected to clear.
185
+ *
186
+ * NOT mirrored in `crates/failproofaid/src/paths.rs` yet: nothing in Rust
187
+ * takes this lock until the daemon grows its audit lane, and a `pub fn` no
188
+ * caller uses is a dead_code failure under `-D warnings`.
189
+ */
190
+ export const auditLockFile = (home?: string) => resolve(runDir(home), "audit.lock");
191
+
192
+ // ── Daemon scratch state ─────────────────────────────────────────────────────
193
+
194
+ /** Everything the daemon writes that a human would never open by hand. */
195
+ export const stateDir = (home?: string) => atHome(home, "state");
196
+ /**
197
+ * Where the policy loader writes its ESM shim.
198
+ *
199
+ * Under the user's own home rather than beside the installed package: that
200
+ * directory belongs to whoever installed failproofai, and on a system-wide
201
+ * install it is root-owned, which made every non-root hook fail to load
202
+ * cloud-managed and custom policies — silently, and open.
203
+ */
204
+ export const shimsDir = (home?: string) => resolve(stateDir(home), "shims");
205
+ export const spoolDir = (home?: string) => resolve(stateDir(home), "spool");
206
+ export const failedDir = (home?: string) => resolve(stateDir(home), "failed");
207
+ export const collectorHealthFile = (home?: string) => resolve(stateDir(home), "collector-health.json");
208
+ /** Per-session enforcement pauses, keyed by a hash of the session id. */
209
+ export const sessionPauseDir = () => resolve(stateDir(), "sessions");
210
+ /**
211
+ * When the scheduled audit last ran, and when the next one is due.
212
+ *
213
+ * The DAEMON is the sole writer (`crates/failproofaid/src/audit_lane.rs`, which
214
+ * mirrors this path in `paths.rs`) — it owns the schedule, and a second writer
215
+ * racing it could hand a machine two full scans back to back. Everything on this
216
+ * side reads it: the interval itself lives in `config.toml`'s `[audit]` table,
217
+ * which a human edits, while this file is derived state a human never opens,
218
+ * which is why it sits under `state/` rather than beside the audit results.
219
+ */
220
+ export const auditScheduleFile = (home?: string) => resolve(stateDir(home), "audit-schedule.json");
221
+ /**
222
+ * The anonymous instance id this machine reports telemetry under.
223
+ *
224
+ * The mirror image of `auditScheduleFile()` above: here the CLI is the sole
225
+ * writer (`getInstanceId()` in `lib/telemetry-id.ts`, which persists whatever it
226
+ * resolved) and **failproofaid** only reads, through `telemetry_id_path()` in
227
+ * `crates/failproofaid/src/paths.rs`. The daemon cannot re-derive the value —
228
+ * `getInstanceId`'s middle tier hashes Node-formatted strings (`os.arch()` is
229
+ * `x64` where Rust says `x86_64`), and a near-miss there does not fail, it
230
+ * silently files one machine under two PostHog persons — so this file is how the
231
+ * two agree. Derived state a human never opens, hence `state/` rather than
232
+ * beside `config.toml`.
233
+ */
234
+ export const telemetryIdFile = (home?: string) => resolve(stateDir(home), "telemetry-id");
235
+ export const launcherMarker = (home?: string) => resolve(stateDir(home), "launcher-configured");
236
+ /**
237
+ * The version that last reported an install, so an upgrade is reported once.
238
+ *
239
+ * Under `state/` in layout 2 like every other piece of derived state, and that
240
+ * placement fixes a real bug rather than being tidiness: at the root it was
241
+ * `~/.failproofai/last-version`, which `detectLayout()` lists as a LAYOUT-1
242
+ * MARKER — while the code that writes it still runs under layout 2, and runs
243
+ * BEFORE the layout check. So on a genuinely fresh machine the CLI created the
244
+ * file, then immediately read it back as evidence of an old layout, classified
245
+ * a brand-new home as stale, and opened every new user's first command with
246
+ * "failproofai reorganised … Removed 1 item(s) from the old layout."
247
+ */
248
+ export const lastVersionFile = (home?: string) => resolve(stateDir(home), "last-version");
249
+ export const onboardingLockFile = (home?: string) => resolve(stateDir(home), "onboarding.lock");
250
+ export const codexSessionPathsFile = (home?: string) => resolve(stateDir(home), "codex-session-paths.json");
251
+
252
+ export const logsDir = (home?: string) => atHome(home, "logs");
253
+
254
+ // ── Layout 1 (legacy) ────────────────────────────────────────────────────────
255
+
256
+ /**
257
+ * Where layout 1 kept things.
258
+ *
259
+ * Retained ONLY so `detectLayout()` can recognise an old home and so the reset
260
+ * can delete it. Nothing reads data from these paths: the decision was
261
+ * wipe-and-re-setup rather than migrate, because a half-migrated home that
262
+ * silently reads "no data" is worse than one that says so.
263
+ */
264
+ export const legacy = {
265
+ policyConfig: () => at("policies-config.json"),
266
+ policyConfigLocal: () => at("policies-config.local.json"),
267
+ cloudCredentials: () => at("cloud.json"),
268
+ ingestCredentials: () => at("ingest.json"),
269
+ launcherMarker: () => at(".launcher-configured"),
270
+ lastVersion: () => at("last-version"),
271
+ auditDashboard: () => at("audit-dashboard.json"),
272
+ cacheDir: () => at("cache"),
273
+ hookActivityDir: () => at("cache", "hook-activity"),
274
+ auditCacheDir: () => at("cache", "audit"),
275
+ codexSessionPaths: () => at("cache", "codex-session-paths.json"),
276
+ spoolDir: () => at("spool"),
277
+ failedDir: () => at("failed"),
278
+ collectorHealth: () => at("collector-health.json"),
279
+ sessionPauseDir: () => at("state", "sessions"),
280
+ cloudManagedPolicies: () => at("policies", "cloud-managed"),
281
+ onboardingLock: () => at(".onboarding.lock"),
282
+ } as const;
283
+
284
+ /**
285
+ * Every path a reset must remove, in the order it should remove them.
286
+ *
287
+ * Enumerated rather than "delete the home directory" so a reset never takes
288
+ * out something a future layout adds and this list has not been taught about
289
+ * — and so the function is auditable at a glance, which matters for anything
290
+ * that deletes user data.
291
+ */
292
+ export function resettablePaths(): string[] {
293
+ return [
294
+ // Layout 1
295
+ legacy.policyConfig(),
296
+ legacy.policyConfigLocal(),
297
+ legacy.cloudCredentials(),
298
+ legacy.ingestCredentials(),
299
+ legacy.launcherMarker(),
300
+ legacy.lastVersion(),
301
+ legacy.auditDashboard(),
302
+ legacy.cacheDir(),
303
+ legacy.spoolDir(),
304
+ legacy.failedDir(),
305
+ legacy.collectorHealth(),
306
+ legacy.onboardingLock(),
307
+ legacy.cloudManagedPolicies(),
308
+ // The MACHINE-OWNED children of `policies/`, never the parent.
309
+ //
310
+ // `at("policies")` stood here, and on layout 1 that directory IS the
311
+ // documented home for hand-written personal policies — `docs/
312
+ // configuration.mdx` names `~/.failproofai/policies/` as the user scope,
313
+ // and `manager.ts` read it. Those are source files a person wrote; nothing
314
+ // regenerates them, nothing backed them up, and the reset message named
315
+ // only "policy config, activity history and audit cache". Worse, the
316
+ // machine then reported itself configured — `isConfigured()` is a union
317
+ // that still sees the agent CLIs' untouched settings files — so the wizard
318
+ // was skipped and hooks kept firing against an empty policy set.
319
+ //
320
+ // `custom-policies/` is deliberately absent from this list for the same
321
+ // reason. Both directories below are re-derived: `local-policies/` by
322
+ // setup, `cloud-policies/` by the next daemon poll.
323
+ localPoliciesDir(),
324
+ cloudPoliciesDir(),
325
+ at("cursors"),
326
+ at("state"),
327
+ // Layout 2.
328
+ // NOT versionFile() — it is the layout marker, not user data, and the
329
+ // reset rewrites it immediately afterwards. Listing it made a no-op reset
330
+ // report "removed 1 item" for a file it had just recreated.
331
+ configFile(),
332
+ credentialsFile(),
333
+ auditDir(),
334
+ hookActivityDir(),
335
+ customAgentsDir(),
336
+ logsDir(),
337
+ // NOT bin/ — a downloaded daemon binary is large, version-pinned and
338
+ // re-verified on use, so deleting it only forces a needless re-download.
339
+ // NOT run/ — sockets belong to a running daemon; removing them out from
340
+ // under it breaks a live process rather than resetting configuration.
341
+ ];
342
+ }
@@ -0,0 +1,332 @@
1
+ /**
2
+ * What happens when this CLI meets a home directory written by a different
3
+ * layout.
4
+ *
5
+ * The decision was wipe-and-re-setup rather than migrate. A migration has to
6
+ * be right on every path or it half-moves a home, and a half-moved home fails
7
+ * in the worst available way: the daemon writes where the dashboard does not
8
+ * read, and an absent directory is indistinguishable from an idle one. A reset
9
+ * is one destructive operation that is either done or not done.
10
+ *
11
+ * ## Where the deletion happens, and where it deliberately does not
12
+ *
13
+ * Only a real CLI command resets. A HOOK never deletes anything, because a
14
+ * hook runs unattended, once per tool call, with an agent waiting on stdout —
15
+ * removing a user's audit history and cursors from inside one would be a
16
+ * destructive act nobody asked for and nobody saw.
17
+ *
18
+ * But a hook must not stay silent either. On a stale layout the merged config
19
+ * resolves to nothing, so every builtin policy quietly stops firing: the
20
+ * machine looks protected and is not. That is the single worst outcome here,
21
+ * so the hook path says so on stderr, every time, until setup is re-run.
22
+ *
23
+ * ## Why the hook does not simply deny
24
+ *
25
+ * Failing closed is this product's instinct, and it is the wrong instinct
26
+ * here. A stale layout is the result of an upgrade the user did not ask to be
27
+ * interrupted by, and this branch has already demonstrated — on this very
28
+ * machine — that a blanket deny takes `UserPromptSubmit` with it and locks the
29
+ * user out of their agent entirely, with no way back except hand-editing JSON.
30
+ * A loud warning that survives until setup runs is the proportionate answer.
31
+ */
32
+ import { existsSync, mkdirSync, readdirSync, renameSync, rmSync } from "node:fs";
33
+ import { resolve } from "node:path";
34
+ import {
35
+ LAYOUT_VERSION,
36
+ customPoliciesDir,
37
+ failproofaiHome,
38
+ policiesDir,
39
+ resettablePaths,
40
+ } from "./fp-home";
41
+ import { detectLayout, readConfig, updateConfig, writeVersionFile, type LayoutState } from "./fp-config";
42
+ import {
43
+ daemonServiceStatus,
44
+ daemonVersionSkew,
45
+ isDaemonSupportedPlatform,
46
+ probeDaemonEndToEnd,
47
+ } from "./daemon-service";
48
+
49
+ export interface ResetOutcome {
50
+ /** Paths that existed and were removed. */
51
+ removed: string[];
52
+ /** Basenames of user-authored policy files moved into `custom-policies/`. */
53
+ migrated: string[];
54
+ /** The layout that was found before the reset. */
55
+ from: number;
56
+ }
57
+
58
+ /** Script files a person could have written by hand. `.d.ts` is a type stub. */
59
+ const USER_SOURCE_RE = /\.(js|mjs|ts)$/;
60
+
61
+ /**
62
+ * Move hand-written policies from layout 1's `policies/` into layout 2's
63
+ * `policies/custom-policies/`, where the loader actually reads them.
64
+ *
65
+ * Layout 1 documented `~/.failproofai/policies/` as the user scope for personal
66
+ * convention policies, and layout 2 moved the directory the loader opens down a
67
+ * level (`customPoliciesDir()`). Left alone, those files survive the reset —
68
+ * that part is handled by keeping the parent out of `resettablePaths()` — but
69
+ * nothing would ever load them again, which is the same silent enforcement gap
70
+ * by a slower route.
71
+ *
72
+ * Every loadable extension moves, not just the `*policies.{js,mjs,ts}` names
73
+ * the convention loads: a file that misses the naming convention is still
74
+ * source somebody wrote, and `findSkippedPolicyFiles` exists precisely to tell
75
+ * them so. Leaving it behind to be reported against an empty directory helps
76
+ * nobody.
77
+ *
78
+ * A destination that already exists is never overwritten — the source is left
79
+ * in place instead. The parent directory is no longer deleted, so "left in
80
+ * place" means "still there to look at", which is the right outcome for the
81
+ * only case that reaches it (a half-finished earlier migration).
82
+ */
83
+ export function migrateConventionPolicies(): string[] {
84
+ const from = policiesDir();
85
+ if (!existsSync(from)) return [];
86
+ const moved: string[] = [];
87
+ try {
88
+ const entries = readdirSync(from, { withFileTypes: true }).filter(
89
+ (e) => e.isFile() && USER_SOURCE_RE.test(e.name) && !e.name.endsWith(".d.ts"),
90
+ );
91
+ if (entries.length === 0) return [];
92
+
93
+ const to = customPoliciesDir();
94
+ mkdirSync(to, { recursive: true });
95
+ for (const entry of entries) {
96
+ const target = resolve(to, entry.name);
97
+ if (existsSync(target)) continue;
98
+ try {
99
+ renameSync(resolve(from, entry.name), target);
100
+ moved.push(entry.name);
101
+ } catch {
102
+ // One unmovable file must not strand the rest. It stays where it is,
103
+ // and the reset no longer deletes that directory.
104
+ }
105
+ }
106
+ } catch {
107
+ // A policies directory we cannot read is not worth aborting a reset over.
108
+ }
109
+ return moved.sort((a, b) => a.localeCompare(b));
110
+ }
111
+
112
+ /**
113
+ * Delete every path layout 1 or layout 2 could have written, then stamp
114
+ * VERSION so the next run reads as current.
115
+ *
116
+ * Enumerated rather than "remove the home directory": a reset must never take
117
+ * out something a future layout adds that this list has not been taught about,
118
+ * and `bin/` and `run/` are excluded on purpose — a downloaded daemon binary is
119
+ * large, version-pinned and re-verified on use, and `run/` holds sockets
120
+ * belonging to a process that may be alive right now.
121
+ */
122
+ export function resetHome(from: number): ResetOutcome {
123
+ // BEFORE the deletions, so a file that is mid-move is never one the reset
124
+ // then walks over.
125
+ const migrated = migrateConventionPolicies();
126
+ const removed: string[] = [];
127
+ for (const path of resettablePaths()) {
128
+ if (!existsSync(path)) continue;
129
+ try {
130
+ rmSync(path, { recursive: true, force: true });
131
+ removed.push(path);
132
+ } catch {
133
+ // A path we cannot remove is not worth aborting the reset over; the
134
+ // VERSION stamp below is what stops this repeating, and a leftover
135
+ // directory from an old layout is inert once nothing reads it.
136
+ }
137
+ }
138
+ writeVersionFile();
139
+ return { removed, migrated, from };
140
+ }
141
+
142
+ export interface LayoutCheck {
143
+ state: LayoutState;
144
+ /** Lines to print. Empty when there is nothing to say. */
145
+ lines: string[];
146
+ /** True when the caller should stop rather than continue. */
147
+ fatal: boolean;
148
+ /**
149
+ * True when this call actually reset the home.
150
+ *
151
+ * The caller must force setup when it is set. A reset removes the global
152
+ * policy config, but `isConfigured()` is a union that also counts the agent
153
+ * CLIs' settings files — which the reset deliberately leaves alone — so the
154
+ * machine still reads as configured, the wizard is skipped, and
155
+ * `markLauncherSeen()` back-fills the marker so every later run skips it too.
156
+ * The user is left with hooks firing on every tool call against no policies
157
+ * at all, and nothing ever says so again.
158
+ */
159
+ didReset: boolean;
160
+ }
161
+
162
+ /**
163
+ * The interactive path: reset a stale home, refuse a future one.
164
+ *
165
+ * A future layout is refused rather than reset because the two failures are
166
+ * not the same. An older home can be rebuilt by re-running setup; a home
167
+ * written by a NEWER CLI holds data this build cannot read but a simple
168
+ * upgrade could, and deleting it would destroy something recoverable.
169
+ */
170
+ export async function checkLayoutForCli(): Promise<LayoutCheck> {
171
+ const state = detectLayout();
172
+
173
+ if (state.kind === "future") {
174
+ return {
175
+ state,
176
+ fatal: true,
177
+ didReset: false,
178
+ lines: [
179
+ `This machine's failproofai directory was written by a newer version`,
180
+ `(layout ${state.found}; this build speaks ${LAYOUT_VERSION}).`,
181
+ ``,
182
+ `Upgrade rather than reset — the data is fine, this build just cannot read it:`,
183
+ ` npm install -g failproofai@latest`,
184
+ ],
185
+ };
186
+ }
187
+
188
+ if (state.kind === "stale") {
189
+ const { removed, migrated } = resetHome(state.found);
190
+ return {
191
+ state,
192
+ fatal: false,
193
+ didReset: true,
194
+ lines: [
195
+ `failproofai reorganised ${failproofaiHome()} in this version.`,
196
+ `Removed ${removed.length} item(s) from the old layout — policy config, activity`,
197
+ `history and audit cache. Your downloaded daemon binary was kept.`,
198
+ // Named individually rather than counted. These are files a person
199
+ // wrote; "moved 3 items" is not something you can check at a glance,
200
+ // and the whole point of saying it is that they can.
201
+ ...(migrated.length > 0
202
+ ? [
203
+ ``,
204
+ `Kept your own policy file(s) and moved them to where this version`,
205
+ `loads them (${customPoliciesDir()}):`,
206
+ ...migrated.map((name) => ` ${name}`),
207
+ ]
208
+ : []),
209
+ ``,
210
+ `Run \`failproofai config\` to set up again.`,
211
+ ],
212
+ };
213
+ }
214
+
215
+ if (state.kind === "absent") writeVersionFile();
216
+ return {
217
+ state,
218
+ fatal: false,
219
+ didReset: false,
220
+ lines: [...(await healDaemonFlag()), ...staleDaemonHint()],
221
+ };
222
+ }
223
+
224
+ /**
225
+ * Clear `daemonConfigured` when the service it points at is provably gone.
226
+ *
227
+ * This exists because the combination it repairs bricked a real machine during
228
+ * development. `daemonConfigured` makes every hook route through failproofaid
229
+ * and FAIL CLOSED when it cannot be reached — so removing the service without
230
+ * first clearing the flag denies every tool call on the box, including
231
+ * `UserPromptSubmit`, which locks the user out of their agent entirely. There
232
+ * was no command to undo it: the only recovery was hand-editing JSON.
233
+ *
234
+ * Deliberately keyed on "not-installed", never on "stopped". A stopped service
235
+ * is usually a restart in progress, and clearing the flag there would silently
236
+ * downgrade a healthy machine to the in-process path — trading a loud, correct
237
+ * failure for a quiet, wrong one.
238
+ */
239
+ async function healDaemonFlag(): Promise<string[]> {
240
+ try {
241
+ const cfg = readConfig();
242
+ if (!cfg.daemon.configured) return [];
243
+ if (!isDaemonSupportedPlatform()) return [];
244
+
245
+ const status = daemonServiceStatus();
246
+ if (status === "not-installed") {
247
+ updateConfig({ daemon: { configured: false } });
248
+ return [
249
+ `failproofaid is no longer installed, but this machine was still configured`,
250
+ `to require it — which denies every tool call. Cleared that flag; policies`,
251
+ `now evaluate in-process. Run \`failproofai config\` to reinstall the daemon.`,
252
+ ``,
253
+ ];
254
+ }
255
+
256
+ // Installed and RUNNING is not the same as working, and the difference is
257
+ // a total lockout. `ExecStart` bakes in `process.execPath`, so an
258
+ // `nvm uninstall 20` months later leaves a unit systemd still calls active
259
+ // whose worker dies on every spawn. Nothing else catches it: the install
260
+ // probe cannot run retroactively, and the not-installed branch above never
261
+ // fires because the unit is very much installed.
262
+ //
263
+ // Clearing the flag is the whole repair, and it is deliberately NOT
264
+ // accompanied by an uninstall: this runs unprompted at the top of whatever
265
+ // command the user typed, and tearing down a root-owned service from there
266
+ // is not a decision to make on their behalf. Removing and reinstalling the
267
+ // unit is the wizard's job, where a person is present — see the
268
+ // `daemonAlreadyHealthy` probe in `configure-wizard.ts`.
269
+ if (status === "running" && !(await probeDaemonEndToEnd())) {
270
+ updateConfig({ daemon: { configured: false } });
271
+ return [
272
+ `failproofaid is running but cannot evaluate policies — its worker process`,
273
+ `will not start (most often because the Node install its service was built`,
274
+ `against is gone). This machine was configured to require it, which denies`,
275
+ `every tool call, so that flag is cleared; policies now evaluate in-process.`,
276
+ `Run \`failproofai config\` to rebuild the service.`,
277
+ ``,
278
+ ];
279
+ }
280
+ return [];
281
+ } catch {
282
+ // Never let a self-heal attempt break the command the user actually typed.
283
+ return [];
284
+ }
285
+ }
286
+
287
+ /**
288
+ * One line when the daemon is older than the CLI.
289
+ *
290
+ * Deliberately NOT on the hook path. A stale daemon still enforces every policy
291
+ * correctly — it is slower to notice an upgrade, not broken — so a warning once
292
+ * per tool call would be noise about something that is working. CLI commands
293
+ * are where a person is present to act on it.
294
+ */
295
+ function staleDaemonHint(): string[] {
296
+ try {
297
+ const skew = daemonVersionSkew();
298
+ if (!skew) return [];
299
+ return [
300
+ `[failproofai] daemon is ${skew.installed}, CLI is ${skew.expected} — ` +
301
+ `run \`failproofai config\` to update it.`,
302
+ ``,
303
+ ];
304
+ } catch {
305
+ return [];
306
+ }
307
+ }
308
+
309
+ /**
310
+ * The hook path: never delete, never deny, but never stay quiet either.
311
+ *
312
+ * Returns a single stderr line when the layout is not current. Hooks run once
313
+ * per tool call, so this repeats — deliberately. A warning that appears once
314
+ * and then stops is a warning nobody sees, and the state it describes (a
315
+ * machine whose global policies have silently stopped firing) persists until
316
+ * somebody acts on it.
317
+ */
318
+ export function layoutWarningForHook(): string | null {
319
+ const state = detectLayout();
320
+ if (state.kind === "current" || state.kind === "absent") return null;
321
+ if (state.kind === "future") {
322
+ return (
323
+ `[failproofai] this directory was written by a newer version ` +
324
+ `(layout ${state.found} vs ${LAYOUT_VERSION}) — policies are NOT being enforced. ` +
325
+ `Upgrade failproofai.`
326
+ );
327
+ }
328
+ return (
329
+ `[failproofai] setup predates this version — global policies are NOT being enforced. ` +
330
+ `Run \`failproofai config\` to re-create it.`
331
+ );
332
+ }