failproofai 1.0.0-beta.5 → 1.0.0-beta.7

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 (368) 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]__0c_qcgp._.js +3 -0
  116. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0kbc9bs._.js +3 -0
  117. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0spkm68._.js +10 -10
  118. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1a2hcb_._.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/_0r-dsre._.js +3 -0
  128. package/.next/standalone/.next/server/chunks/ssr/_0rjgfln._.js +3 -0
  129. package/.next/standalone/.next/server/chunks/ssr/_0se484m._.js +3 -0
  130. package/.next/standalone/.next/server/chunks/ssr/_0uz7o9y._.js +3 -0
  131. package/.next/standalone/.next/server/chunks/ssr/_11_p9y8._.js +1 -1
  132. package/.next/standalone/.next/server/chunks/ssr/_194yh9u._.js +3 -0
  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/0945ybz3fsvba.js +1 -0
  150. package/.next/standalone/.next/static/chunks/{0cr85wuc9gc9k.js → 0gr76ps8_zm26.js} +1 -1
  151. package/.next/standalone/.next/static/chunks/{2cqk4a9s893oy.js → 0m-m7wgtxdoav.js} +1 -1
  152. package/.next/standalone/.next/static/chunks/{1tp9dex23zs8y.js → 11l6oh9cyb35a.js} +1 -1
  153. package/.next/standalone/.next/static/chunks/166f8qnh03jqc.js +6 -0
  154. package/.next/standalone/.next/static/chunks/1bm0q12hgs22l.css +2 -0
  155. package/.next/standalone/.next/static/chunks/1v1gqvpjk62jm.js +1 -0
  156. package/.next/standalone/.next/static/chunks/{2s9g1dsde_ts1.js → 2aej0vi1fm87m.js} +1 -1
  157. package/.next/standalone/.next/static/chunks/{1bkynffp3q1f7.js → 2bxld6-rym3ah.js} +22 -22
  158. package/.next/standalone/.next/static/chunks/{2v1rpzrh2i1wv.js → 2p2kz4aj1tooj.js} +1 -1
  159. package/.next/standalone/.next/static/chunks/2uvhw57mf9lg_.css +2 -0
  160. package/.next/standalone/.next/static/chunks/36pc3_8fpb6ic.js +1 -0
  161. package/.next/standalone/.next/static/chunks/{2k285z07qce47.js → 3t1wr_kx6brwc.js} +1 -1
  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 +202 -86
  197. package/dist/cli.mjs +17803 -15346
  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 +160 -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 +25 -43
  229. package/src/hooks/configure-wizard.ts +750 -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 +605 -29
  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 +355 -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-attempt.ts +179 -0
  246. package/src/hooks/onboarding-lock.ts +119 -0
  247. package/src/hooks/policy-types.ts +0 -7
  248. package/src/hooks/session-pause-cli.ts +15 -13
  249. package/src/hooks/session-pause.ts +36 -4
  250. package/src/hooks/setup-state.ts +256 -0
  251. package/src/hooks/tui.ts +4 -4
  252. package/src/hooks/worker-server.ts +53 -1
  253. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0f8nu8d._.js +0 -3
  254. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0szqzl8._.js +0 -3
  255. package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +0 -3
  256. package/.next/standalone/.next/server/chunks/[root-of-the-server]__19120tr._.js +0 -3
  257. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1fwl2mz._.js +0 -3
  258. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1myjm-d._.js +0 -3
  259. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1rhmvod._.js +0 -3
  260. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02r5bgf._.js +0 -4
  261. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__094nop3._.js +0 -3
  262. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e8sjqm._.js +0 -4
  263. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0lkzqax._.js +0 -4
  264. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ls0gsr._.js +0 -4
  265. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n_uvv0._.js +0 -3
  266. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qucxyj._.js +0 -4
  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]__1gak4pd._.js +0 -3
  270. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1j4u3yd._.js +0 -4
  271. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1zqz4v8._.js +0 -4
  272. package/.next/standalone/.next/server/chunks/ssr/_1m_p7pi._.js +0 -3
  273. package/.next/standalone/.next/server/chunks/ssr/node_modules_html-to-image_es_index_12c_2cz.js +0 -3
  274. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1ezd2jf._.js +0 -5
  275. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1tnuifj._.js +0 -5
  276. package/.next/standalone/.next/static/chunks/0h7auy7hzjyhw.js +0 -1
  277. package/.next/standalone/.next/static/chunks/1bw4dfzflelcv.js +0 -1
  278. package/.next/standalone/.next/static/chunks/34sjdw8lv46e3.js +0 -6
  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/Cargo.lock +0 -2222
  282. package/.next/standalone/Cargo.toml +0 -9
  283. package/.next/standalone/crates/CLOUD_POLICIES.md +0 -136
  284. package/.next/standalone/crates/PROTOCOL.md +0 -122
  285. package/.next/standalone/crates/failproofaid/Cargo.toml +0 -25
  286. package/.next/standalone/crates/failproofaid/src/cloud_client.rs +0 -484
  287. package/.next/standalone/crates/failproofaid/src/cloud_policies.rs +0 -921
  288. package/.next/standalone/crates/failproofaid/src/lock.rs +0 -81
  289. package/.next/standalone/crates/failproofaid/src/main.rs +0 -639
  290. package/.next/standalone/crates/failproofaid/src/paths.rs +0 -201
  291. package/.next/standalone/crates/failproofaid/src/server.rs +0 -502
  292. package/.next/standalone/crates/failproofaid/src/worker.rs +0 -400
  293. package/.next/standalone/crates/failproofaid/tests/daemon_e2e.rs +0 -241
  294. package/.next/standalone/crates/fpai-collect/Cargo.toml +0 -43
  295. package/.next/standalone/crates/fpai-collect/src/config.rs +0 -420
  296. package/.next/standalone/crates/fpai-collect/src/cursor.rs +0 -520
  297. package/.next/standalone/crates/fpai-collect/src/delivery.rs +0 -472
  298. package/.next/standalone/crates/fpai-collect/src/filetail.rs +0 -487
  299. package/.next/standalone/crates/fpai-collect/src/health.rs +0 -369
  300. package/.next/standalone/crates/fpai-collect/src/lib.rs +0 -34
  301. package/.next/standalone/crates/fpai-collect/src/redact.rs +0 -516
  302. package/.next/standalone/crates/fpai-collect/src/sources/claude/mod.rs +0 -279
  303. package/.next/standalone/crates/fpai-collect/src/sources/claude/transform.rs +0 -619
  304. package/.next/standalone/crates/fpai-collect/src/sources/codex/mod.rs +0 -156
  305. package/.next/standalone/crates/fpai-collect/src/sources/codex/transform.rs +0 -715
  306. package/.next/standalone/crates/fpai-collect/src/sources/copilot/mod.rs +0 -158
  307. package/.next/standalone/crates/fpai-collect/src/sources/copilot/transform.rs +0 -512
  308. package/.next/standalone/crates/fpai-collect/src/sources/goose/mod.rs +0 -511
  309. package/.next/standalone/crates/fpai-collect/src/sources/goose/transform.rs +0 -586
  310. package/.next/standalone/crates/fpai-collect/src/sources/hermes/mod.rs +0 -318
  311. package/.next/standalone/crates/fpai-collect/src/sources/hermes/transform.rs +0 -579
  312. package/.next/standalone/crates/fpai-collect/src/sources/hooks/mod.rs +0 -314
  313. package/.next/standalone/crates/fpai-collect/src/sources/hooks/transform.rs +0 -448
  314. package/.next/standalone/crates/fpai-collect/src/sources/mod.rs +0 -23
  315. package/.next/standalone/crates/fpai-collect/src/sources/openclaw/mod.rs +0 -176
  316. package/.next/standalone/crates/fpai-collect/src/sources/openclaw/transform.rs +0 -500
  317. package/.next/standalone/crates/fpai-collect/src/sources/opencode/mod.rs +0 -315
  318. package/.next/standalone/crates/fpai-collect/src/sources/opencode/transform.rs +0 -493
  319. package/.next/standalone/crates/fpai-collect/src/sources/pi/mod.rs +0 -201
  320. package/.next/standalone/crates/fpai-collect/src/sources/pi/transform.rs +0 -533
  321. package/.next/standalone/crates/fpai-collect/src/spool.rs +0 -535
  322. package/.next/standalone/crates/fpai-collect/src/sqlitepoll.rs +0 -390
  323. package/.next/standalone/crates/fpai-collect/src/supervisor.rs +0 -423
  324. package/.next/standalone/crates/fpai-collect/src/uploader.rs +0 -600
  325. package/.next/standalone/crates/fpai-collect/tests/claude_source.rs +0 -739
  326. package/.next/standalone/crates/fpai-collect/tests/claude_subagents.rs +0 -394
  327. package/.next/standalone/crates/fpai-collect/tests/codex_source.rs +0 -976
  328. package/.next/standalone/crates/fpai-collect/tests/config.rs +0 -286
  329. package/.next/standalone/crates/fpai-collect/tests/copilot_source.rs +0 -1020
  330. package/.next/standalone/crates/fpai-collect/tests/delivery.rs +0 -281
  331. package/.next/standalone/crates/fpai-collect/tests/goose_source.rs +0 -1009
  332. package/.next/standalone/crates/fpai-collect/tests/hermes_source.rs +0 -1130
  333. package/.next/standalone/crates/fpai-collect/tests/hooks_source.rs +0 -622
  334. package/.next/standalone/crates/fpai-collect/tests/openclaw_source.rs +0 -855
  335. package/.next/standalone/crates/fpai-collect/tests/opencode_source.rs +0 -1478
  336. package/.next/standalone/crates/fpai-collect/tests/pi_source.rs +0 -1192
  337. package/.next/standalone/crates/fpai-collect/tests/supervisor.rs +0 -290
  338. package/.next/standalone/crates/fpai-collect/tests/uploader.rs +0 -506
  339. package/.next/standalone/crates/fpai-ipc/Cargo.toml +0 -16
  340. package/.next/standalone/crates/fpai-ipc/src/envelope.rs +0 -175
  341. package/.next/standalone/crates/fpai-ipc/src/framing.rs +0 -177
  342. package/.next/standalone/crates/fpai-ipc/src/lib.rs +0 -10
  343. package/.next/standalone/crates/fpai-ipc/src/peer.rs +0 -80
  344. package/.next/standalone/docker-hook-sync/Dockerfile +0 -79
  345. package/.next/standalone/docker-hook-sync/entrypoint.sh +0 -109
  346. package/.next/standalone/integration-suite/Dockerfile +0 -47
  347. package/.next/standalone/integration-suite/README.md +0 -129
  348. package/.next/standalone/integration-suite/canary-policies.mjs +0 -45
  349. package/.next/standalone/integration-suite/capture-tokens.sh +0 -48
  350. package/.next/standalone/integration-suite/ci-entrypoint.sh +0 -179
  351. package/.next/standalone/integration-suite/inject-tokens.sh +0 -44
  352. package/.next/standalone/integration-suite/install-clis.sh +0 -136
  353. package/.next/standalone/integration-suite/probe-cli.sh +0 -248
  354. package/.next/standalone/integration-suite/report.js +0 -120
  355. package/.next/standalone/integration-suite/run.sh +0 -159
  356. package/.next/standalone/openclaw-plugin/index.js +0 -223
  357. package/.next/standalone/openclaw-plugin/openclaw.plugin.json +0 -6
  358. package/.next/standalone/openclaw-plugin/package.json +0 -12
  359. package/.next/standalone/osv-scanner.toml +0 -17
  360. package/.next/standalone/pi-extension/index.ts +0 -524
  361. package/.next/standalone/pi-extension/package.json +0 -12
  362. package/.next/standalone/postcss.config.mjs +0 -8
  363. package/.next/standalone/readme-arch-hq.gif +0 -0
  364. package/.next/standalone/rust-toolchain.toml +0 -4
  365. package/src/auth/cli.ts +0 -371
  366. /package/.next/standalone/.next/static/{LOuwMmfomO6hQYfMQYs4K → LUaLkKg40nSkHrIajexIk}/_buildManifest.js +0 -0
  367. /package/.next/standalone/.next/static/{LOuwMmfomO6hQYfMQYs4K → LUaLkKg40nSkHrIajexIk}/_clientMiddlewareManifest.js +0 -0
  368. /package/.next/standalone/.next/static/{LOuwMmfomO6hQYfMQYs4K → LUaLkKg40nSkHrIajexIk}/_ssgManifest.js +0 -0
@@ -16,11 +16,14 @@
16
16
  * Environment variables still win over this file, so CI, containers and the
17
17
  * existing tests are unaffected.
18
18
  */
19
+ import { randomUUID } from "node:crypto";
19
20
  import { existsSync, readFileSync, rmSync } from "node:fs";
20
- import { homedir } from "node:os";
21
+ import { homedir, hostname } from "node:os";
21
22
  import { join } from "node:path";
22
23
  import { writeJsonAtomically } from "../../lib/atomic-write";
23
24
  import { fetchWithTimeout, isAbortError } from "../../lib/fetch-with-timeout";
25
+ import { credentialsFile } from "./fp-home";
26
+ import { readCredentials, writeCredentials } from "./fp-config";
24
27
 
25
28
  const SCHEMA_VERSION = 1;
26
29
  const VERIFY_TIMEOUT_MS = 10_000;
@@ -29,17 +32,34 @@ export interface CloudCredentials {
29
32
  url: string;
30
33
  machineId: string;
31
34
  token: string;
35
+ /**
36
+ * A human-facing name for this machine (e.g. the hostname, or "Chetan's
37
+ * laptop"). Display only — the identity is `machineId`. Optional: absent on
38
+ * credentials written before labels existed, and never required to connect.
39
+ */
40
+ machineLabel?: string;
32
41
  }
33
42
 
34
43
  interface StoredCredentials extends CloudCredentials {
35
44
  schemaVersion: number;
36
45
  }
37
46
 
38
- /** `~/.failproofai/cloud.json`. The override is honoured by the daemon too. */
47
+ /**
48
+ * Where the cloud credential lives.
49
+ *
50
+ * Layout 2 moved it out of `cloud.json` and into the `[cloud]` table of
51
+ * `credentials.toml`, alongside every other token, so there is exactly one
52
+ * owner-only file to protect rather than three. The env override still names a
53
+ * standalone JSON file, because the daemon and CI both use it that way and it
54
+ * predates the consolidation.
55
+ */
39
56
  export function cloudCredentialPath(): string {
40
- const override = process.env.FAILPROOFAI_CLOUD_CREDENTIALS;
41
- if (override) return override;
42
- return join(homedir(), ".failproofai", "cloud.json");
57
+ return process.env.FAILPROOFAI_CLOUD_CREDENTIALS ?? credentialsFile();
58
+ }
59
+
60
+ /** True when the credential is coming from the JSON override, not the TOML. */
61
+ function usingJsonOverride(): boolean {
62
+ return Boolean(process.env.FAILPROOFAI_CLOUD_CREDENTIALS);
43
63
  }
44
64
 
45
65
  /**
@@ -81,6 +101,7 @@ export function maskToken(token: string): string {
81
101
  }
82
102
 
83
103
  export function readCloudCredentials(): CloudCredentials | null {
104
+ if (!usingJsonOverride()) return readCredentials().cloud ?? null;
84
105
  const path = cloudCredentialPath();
85
106
  if (!existsSync(path)) return null;
86
107
  try {
@@ -90,7 +111,8 @@ export function readCloudCredentials(): CloudCredentials | null {
90
111
  return null;
91
112
  }
92
113
  if (!raw.url || !raw.machineId || !raw.token) return null;
93
- return { url: raw.url, machineId: raw.machineId, token: raw.token };
114
+ const label = typeof raw.machineLabel === "string" && raw.machineLabel ? raw.machineLabel : undefined;
115
+ return { url: raw.url, machineId: raw.machineId, token: raw.token, machineLabel: label };
94
116
  } catch {
95
117
  // Unreadable or malformed reads as "not connected" rather than throwing:
96
118
  // this is consulted by `--status`, and a corrupt file should be reported
@@ -100,21 +122,63 @@ export function readCloudCredentials(): CloudCredentials | null {
100
122
  }
101
123
 
102
124
  export function writeCloudCredentials(creds: CloudCredentials): void {
103
- // 0600 inside a 0700 dir — the default for writeJsonAtomically, and the
104
- // whole reason this is a file of ours rather than a line in the unit.
105
- writeJsonAtomically(cloudCredentialPath(), { schemaVersion: SCHEMA_VERSION, ...creds });
125
+ if (usingJsonOverride()) {
126
+ // 0600 inside a 0700 dir — the default for writeJsonAtomically.
127
+ writeJsonAtomically(cloudCredentialPath(), { schemaVersion: SCHEMA_VERSION, ...creds });
128
+ return;
129
+ }
130
+ // Merge, never replace: credentials.toml also carries the ingest key and the
131
+ // auth session, and rewriting the file from one caller must not drop the
132
+ // others.
133
+ writeCredentials({ ...readCredentials(), cloud: creds });
134
+ }
135
+
136
+ /**
137
+ * The stable key that identifies this machine to the cloud.
138
+ *
139
+ * An explicit `--machine-id` always wins. Otherwise the id already enrolled on
140
+ * this machine is reused, so re-running `--connect` is idempotent and never
141
+ * "moves" the machine. Only a machine that has none mints a fresh one — and it
142
+ * mints a random id, NOT the hostname, because two hosts sharing a hostname
143
+ * (fresh cloud VMs, cloned images) would otherwise silently merge into one
144
+ * machine on the server. The hostname becomes the human label instead.
145
+ */
146
+ export function resolveMachineId(explicit?: string): string {
147
+ const trimmed = explicit?.trim();
148
+ if (trimmed) return trimmed;
149
+ const existing = readCloudCredentials();
150
+ if (existing?.machineId) return existing.machineId;
151
+ return randomUUID();
152
+ }
153
+
154
+ /**
155
+ * The human-facing name for this machine. Defaults to the hostname as a
156
+ * *suggestion* — mutable, not the identity, and free to collide with another
157
+ * machine's label because `machineId` keeps them apart.
158
+ */
159
+ export function resolveMachineLabel(explicit?: string): string {
160
+ return explicit?.trim() || hostname();
106
161
  }
107
162
 
108
163
  /** True if there was something to remove. */
109
164
  export function clearCloudCredentials(): boolean {
110
- const path = cloudCredentialPath();
111
- if (!existsSync(path)) return false;
112
- try {
113
- rmSync(path);
114
- return true;
115
- } catch {
116
- return false;
165
+ if (usingJsonOverride()) {
166
+ const path = cloudCredentialPath();
167
+ if (!existsSync(path)) return false;
168
+ try {
169
+ rmSync(path);
170
+ return true;
171
+ } catch {
172
+ return false;
173
+ }
117
174
  }
175
+ const current = readCredentials();
176
+ if (!current.cloud) return false;
177
+ // Drop only the cloud table — disconnecting policy must not also revoke the
178
+ // ingest key or the dashboard session.
179
+ const { cloud: _dropped, ...rest } = current;
180
+ writeCredentials(rest);
181
+ return true;
118
182
  }
119
183
 
120
184
  export type VerifyResult =
@@ -131,7 +195,13 @@ export type VerifyResult =
131
195
  * came back.
132
196
  */
133
197
  export async function verifyCloudCredentials(creds: CloudCredentials): Promise<VerifyResult> {
134
- const url = `${creds.url}/enforcement/v1/desired-state?machineId=${encodeURIComponent(creds.machineId)}`;
198
+ // The label rides the enrolment request so the server can record a
199
+ // human-facing name alongside the id. An older server simply ignores the
200
+ // extra query param, so sending it is always safe.
201
+ const labelParam = creds.machineLabel
202
+ ? `&label=${encodeURIComponent(creds.machineLabel)}`
203
+ : "";
204
+ const url = `${creds.url}/enforcement/v1/desired-state?machineId=${encodeURIComponent(creds.machineId)}${labelParam}`;
135
205
  let response: Response;
136
206
  try {
137
207
  response = await fetchWithTimeout(
@@ -0,0 +1,147 @@
1
+ /**
2
+ * `GET /v1/auth/introspect` — asking the server what a key actually is.
3
+ *
4
+ * Before this endpoint existed a machine could not describe its own
5
+ * credential: every other `/keys*` route needs a `keys:*` permission that a
6
+ * machine credential must never hold. So a revoked key, a valid key missing
7
+ * one permission, and a valid key pointed at the WRONG ORG all failed
8
+ * identically — at the point of use, later, as an empty dashboard.
9
+ *
10
+ * Introspect answers all three at connect time, in one request:
11
+ *
12
+ * is the key accepted at all? 401 vs 200
13
+ * which org will this machine report into? org_slug / org_name
14
+ * can it do the job it was provisioned for? permissions
15
+ *
16
+ * ## Effective, not granted — the subtle part
17
+ *
18
+ * Permissions imply other permissions, and the server widens a grant at
19
+ * authentication time (`expand_implied`): `alerts:read` also carries
20
+ * `issues:read`, and so on. Authorization is checked against the WIDENED set.
21
+ *
22
+ * The dashboard's key page and the CLI both display the *stored* grant, so both
23
+ * understate what a key can do. Introspect returns what the server actually
24
+ * enforces — which is precisely why a local permission check is only correct
25
+ * when it is built against this response and not against the displayed list.
26
+ *
27
+ * ## Do not poll this
28
+ *
29
+ * `/v1` has no rate limiting and failed auth is not negatively cached: one bad
30
+ * token is one database lookup per request. This runs ONCE, when a machine is
31
+ * provisioned. Revocation and expiry are cached server-side for up to a minute,
32
+ * so treat a positive answer as current to within a minute — never to the
33
+ * second.
34
+ */
35
+
36
+ /** The path introspect is served on, appended to the cloud origin. */
37
+ export const INTROSPECT_PATH = "/v1/auth/introspect";
38
+
39
+ export interface KeyIdentity {
40
+ keyId?: string;
41
+ orgId?: string;
42
+ orgSlug?: string;
43
+ orgName?: string;
44
+ /** The EFFECTIVE permission set — what the server enforces. */
45
+ permissions: string[];
46
+ expiresAt?: string | null;
47
+ }
48
+
49
+ export type IntrospectResult =
50
+ | { kind: "ok"; identity: KeyIdentity }
51
+ /** The key was refused. Nothing more is knowable — the body carries no detail. */
52
+ | { kind: "rejected" }
53
+ /**
54
+ * This server has no introspect endpoint, i.e. it predates the endpoint.
55
+ * The caller must fall back to probing rather than treating it as a bad key:
56
+ * the CLI ships independently of whatever AgentEye a customer runs, so a
57
+ * perfectly good key on an older server must still connect.
58
+ */
59
+ | { kind: "unsupported" }
60
+ /** Network/DNS/TLS — indistinguishable from a typo'd host, so reported as-is. */
61
+ | { kind: "unreachable"; reason: string };
62
+
63
+ export function introspectUrlFor(origin: string): string {
64
+ return `${origin.replace(/\/$/, "")}${INTROSPECT_PATH}`;
65
+ }
66
+
67
+ export async function introspectKey(
68
+ origin: string,
69
+ token: string,
70
+ fetchImpl: typeof fetch = fetch,
71
+ timeoutMs = 10_000,
72
+ ): Promise<IntrospectResult> {
73
+ // AbortController rather than the shared fetchWithTimeout helper: this needs
74
+ // an injectable `fetch` so tests never reach the network, and that helper
75
+ // closes over the global one.
76
+ const controller = new AbortController();
77
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
78
+ let res: Response;
79
+ try {
80
+ res = await fetchImpl(introspectUrlFor(origin), {
81
+ headers: { Authorization: `Bearer ${token}` },
82
+ // Never follow a redirect. The dashboard app answers unrouted paths and
83
+ // will happily 307 to a login page that then returns 200 — which would
84
+ // read as a valid key against an endpoint that authenticated nothing.
85
+ redirect: "manual",
86
+ signal: controller.signal,
87
+ });
88
+ } catch (err) {
89
+ const message = err instanceof Error ? err.message : String(err);
90
+ // Deliberately does not echo the URL: setup is routinely run while
91
+ // screen-sharing, and the host may be one the user would rather not show.
92
+ return { kind: "unreachable", reason: message };
93
+ } finally {
94
+ clearTimeout(timer);
95
+ }
96
+
97
+ if (res.status === 401 || res.status === 403) return { kind: "rejected" };
98
+ // 404 is "this server has no such route"; a redirect means we reached the web
99
+ // app rather than the API, which on an older deployment means the same thing.
100
+ if (res.status === 404 || (res.status >= 300 && res.status < 400)) {
101
+ return { kind: "unsupported" };
102
+ }
103
+ if (!res.ok) return { kind: "unreachable", reason: `the server answered ${res.status}` };
104
+
105
+ let body: unknown;
106
+ try {
107
+ body = await res.json();
108
+ } catch {
109
+ // A 200 that is not JSON is a proxy or a static host, not introspect.
110
+ return { kind: "unsupported" };
111
+ }
112
+
113
+ const b = body as Record<string, unknown>;
114
+ // `valid: false` is not documented as a 200 shape, but treating a negative
115
+ // assertion as success would be the worst possible reading of it.
116
+ if (b.valid === false) return { kind: "rejected" };
117
+ if (!Array.isArray(b.permissions)) {
118
+ // Shaped like something else entirely — an unrelated 200 from a proxy.
119
+ return { kind: "unsupported" };
120
+ }
121
+
122
+ return {
123
+ kind: "ok",
124
+ identity: {
125
+ keyId: typeof b.key_id === "string" ? b.key_id : undefined,
126
+ orgId: typeof b.org_id === "string" ? b.org_id : undefined,
127
+ orgSlug: typeof b.org_slug === "string" ? b.org_slug : undefined,
128
+ orgName: typeof b.org_name === "string" ? b.org_name : undefined,
129
+ permissions: b.permissions.filter((p): p is string => typeof p === "string"),
130
+ expiresAt: typeof b.expires_at === "string" ? b.expires_at : null,
131
+ },
132
+ };
133
+ }
134
+
135
+ /** The permission each capability needs. Named so the messages can quote them. */
136
+ export const PERMISSION_EVENTS = "events:add";
137
+ export const PERMISSION_POLICIES = "policies:pull";
138
+
139
+ export function hasPermission(identity: KeyIdentity, permission: string): boolean {
140
+ return identity.permissions.includes(permission);
141
+ }
142
+
143
+ /** "Acme Inc (acme)", or the slug/id alone when the server sent less. */
144
+ export function describeOrg(identity: KeyIdentity): string {
145
+ if (identity.orgName && identity.orgSlug) return `${identity.orgName} (${identity.orgSlug})`;
146
+ return identity.orgName ?? identity.orgSlug ?? identity.orgId ?? "an unknown organisation";
147
+ }
@@ -5,9 +5,10 @@
5
5
  * before import so the worker never knowingly executes modified bytes.
6
6
  */
7
7
  import { createHash } from "node:crypto";
8
- import { existsSync, readFileSync, realpathSync } from "node:fs";
8
+ import { existsSync, readFileSync, realpathSync, rmSync } from "node:fs";
9
9
  import { homedir } from "node:os";
10
10
  import { isAbsolute, relative, resolve } from "node:path";
11
+ import { cloudPoliciesDir } from "./fp-home";
11
12
 
12
13
  const ACTIVE_SCHEMA_VERSION = 1;
13
14
  const SHA256_RE = /^[a-f0-9]{64}$/;
@@ -47,7 +48,7 @@ interface ActiveManifest {
47
48
  export function cloudManagedPolicyRoot(): string {
48
49
  return (
49
50
  process.env.FAILPROOFAI_CLOUD_POLICY_DIR ??
50
- resolve(homedir(), ".failproofai", "policies", "cloud-managed")
51
+ cloudPoliciesDir()
51
52
  );
52
53
  }
53
54
 
@@ -85,6 +86,36 @@ function resolveManagedPath(root: string, candidate: string): string {
85
86
  return realFile;
86
87
  }
87
88
 
89
+ /**
90
+ * Stop enforcing cloud-managed policies on this machine.
91
+ *
92
+ * Removes `active.json` only — the manifest that says which generation is
93
+ * live. The generation directories and content-addressed artifacts are left
94
+ * alone: they are large, hash-verified on use, and inert once nothing points
95
+ * at them, so keeping them makes a reconnect cheap and offline-safe.
96
+ *
97
+ * Called by `--disconnect`, which without it did not disconnect. Clearing the
98
+ * credential stops the daemon REFRESHING policy; every artifact already on disk
99
+ * kept being loaded and enforced on every tool call, so a user who had
100
+ * deliberately left their organisation's cloud went on being governed by
101
+ * whatever generation happened to be current when they left — indefinitely,
102
+ * with `--status` reporting the machine as unconnected.
103
+ *
104
+ * Returns true when a manifest was actually removed.
105
+ */
106
+ export function clearActiveCloudManagedPolicies(): boolean {
107
+ const activePath = resolve(cloudManagedPolicyRoot(), "active.json");
108
+ if (!existsSync(activePath)) return false;
109
+ try {
110
+ rmSync(activePath, { force: true });
111
+ return true;
112
+ } catch {
113
+ // Best-effort: `--disconnect` still clears the credentials, and reporting
114
+ // a failure to remove one file would obscure that the rest succeeded.
115
+ return false;
116
+ }
117
+ }
118
+
88
119
  export function readActiveCloudManagedPolicies(): CloudManagedPolicyArtifact[] {
89
120
  const root = cloudManagedPolicyRoot();
90
121
  const activePath = resolve(root, "active.json");
@@ -28,9 +28,11 @@ import { join } from "node:path";
28
28
  import { homedir } from "node:os";
29
29
 
30
30
  import { readHooksConfig, writeHooksConfig } from "./hooks-config";
31
+ import { credentialsFile, failproofaiHome as layoutHome } from "./fp-home";
32
+ import { readCredentials, writeCredentials, updateConfig } from "./fp-config";
31
33
 
32
34
  /** The hosted ingest endpoint — a COMPLETE endpoint, not a base to join onto. */
33
- export const DEFAULT_INGEST_URL = "https://server.befailproof.ai/events";
35
+ export const DEFAULT_INGEST_URL = "https://server.befailproof.ai/v1/events";
34
36
 
35
37
  export interface IngestCredential {
36
38
  url: string;
@@ -55,16 +57,16 @@ export interface CollectorSettings {
55
57
  }
56
58
 
57
59
  export function failproofaiHome(): string {
58
- return process.env.FAILPROOFAI_HOME || join(homedir(), ".failproofai");
60
+ return layoutHome();
59
61
  }
60
62
 
61
63
  export function ingestPath(): string {
62
- return join(failproofaiHome(), "ingest.json");
64
+ return credentialsFile();
63
65
  }
64
66
 
65
67
  /** Whether an ingest credential is already configured on this machine. */
66
68
  export function hasIngestCredential(): boolean {
67
- return existsSync(ingestPath());
69
+ return Boolean(readCredentials().ingest);
68
70
  }
69
71
 
70
72
  /**
@@ -76,24 +78,19 @@ export function hasIngestCredential(): boolean {
76
78
  * cannot read it either, is the truth.
77
79
  */
78
80
  export function readIngestCredential(): IngestCredential | null {
79
- try {
80
- const raw = JSON.parse(readFileSync(ingestPath(), "utf8")) as Partial<IngestCredential>;
81
- if (typeof raw.url !== "string" || typeof raw.key !== "string") return null;
82
- if (!raw.url || !raw.key) return null;
83
- return { url: raw.url, key: raw.key };
84
- } catch {
85
- return null;
86
- }
81
+ const ingest = readCredentials().ingest;
82
+ return ingest ? { url: ingest.url, key: ingest.key } : null;
87
83
  }
88
84
 
89
85
  /** Remove the ingest credential. Returns whether a file was actually removed. */
90
86
  export function clearIngestCredential(): boolean {
91
- try {
92
- rmSync(ingestPath());
93
- return true;
94
- } catch {
95
- return false;
96
- }
87
+ const current = readCredentials();
88
+ if (!current.ingest) return false;
89
+ // Drop only the ingest table: stopping event reporting must not also revoke
90
+ // the policy-pull credential or the dashboard session.
91
+ const { ingest: _dropped, ...rest } = current;
92
+ writeCredentials(rest);
93
+ return true;
97
94
  }
98
95
 
99
96
  /**
@@ -105,41 +102,26 @@ export function clearIngestCredential(): boolean {
105
102
  * without POSIX modes; the write itself is not.
106
103
  */
107
104
  export function writeIngestCredential(cred: IngestCredential): string {
108
- const home = failproofaiHome();
109
- mkdirSync(home, { recursive: true });
110
- try {
111
- const mode = statSync(home).mode & 0o777;
112
- if (mode & 0o077) chmodSync(home, 0o700);
113
- } catch {
114
- // Not fatal: the file's own 0600 is the primary protection.
115
- }
116
-
117
- const path = ingestPath();
118
- // `mode` on writeFileSync applies only when the file is CREATED, so an
119
- // existing over-permissive file would keep its mode without the chmod.
120
- writeFileSync(path, JSON.stringify(cred, null, 2) + "\n", { mode: 0o600 });
121
- try {
122
- chmodSync(path, 0o600);
123
- } catch {
124
- /* best effort */
125
- }
126
- return path;
105
+ // Merge, never replace — credentials.toml also holds the cloud token and the
106
+ // auth session, and one caller rewriting the file must not drop the others.
107
+ // writeCredentials owns the 0600 mode and tightens the home around it.
108
+ writeCredentials({ ...readCredentials(), ingest: cred });
109
+ return credentialsFile();
127
110
  }
128
111
 
129
112
  /** Merge the collector block into the shared (non-secret) config. */
130
113
  export function writeCollectorSettings(settings: CollectorSettings): void {
131
- const config = readHooksConfig();
132
- writeHooksConfig({
133
- ...config,
114
+ // Collector preferences are NOT secret, so they live in config.toml. The key
115
+ // that makes them meaningful lives in credentials.toml; that split is the
116
+ // whole point of layout 2.
117
+ updateConfig({
134
118
  collector: {
135
119
  sessions: settings.sessions,
136
120
  hooks: settings.hooks,
137
121
  hooksVerbosity: settings.hooksVerbosity ?? "decisions",
138
122
  redact: settings.redact ?? "minimal",
139
123
  environment: settings.environment ?? "local",
140
- // Omit when unknown rather than writing null: the Rust side treats an
141
- // absent field as "no machine", which is the correct fallback.
142
- ...(settings.machineId ? { machineId: settings.machineId } : {}),
124
+ machineId: settings.machineId,
143
125
  },
144
126
  });
145
127
  }